Creating release candidate final from release_370 branch

git-svn-id: https://llvm.org/svn/llvm-project/polly/tags/RELEASE_370@246253 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/final/.arcconfig b/final/.arcconfig
new file mode 100644
index 0000000..d64a648
--- /dev/null
+++ b/final/.arcconfig
@@ -0,0 +1,11 @@
+{
+  "project_id" : "polly",
+  "conduit_uri" : "http://reviews.llvm.org/",
+  "history.immutable" : true,
+  "linter.scriptandregex.script": "sh -c './utils/check_format.sh \"$0\" 2> /dev/null || true'",
+  "linter.scriptandregex.regex": "/^(OK:(?P<ignore>.+)|Error:) (?P<message>.+)$/m",
+  "load" : [
+    "utils/arcanist/LitTestEngine"
+  ],
+  "unit.engine" : "LitTestEngine"
+}
diff --git a/final/.arclint b/final/.arclint
new file mode 100644
index 0000000..84546f5
--- /dev/null
+++ b/final/.arclint
@@ -0,0 +1,23 @@
+{
+  "linters": {
+    "format": {
+      "include": "(include/polly/.+\\.h$|lib/.+\\.cpp$)",
+      "exclude": "(lib/JSON/.*)",
+      "type": "script-and-regex"
+    },
+    "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..97b102a
--- /dev/null
+++ b/final/.gitignore
@@ -0,0 +1,2 @@
+test/lit.site.cfg
+00*
diff --git a/final/CMakeLists.txt b/final/CMakeLists.txt
new file mode 100644
index 0000000..5c0270e
--- /dev/null
+++ b/final/CMakeLists.txt
@@ -0,0 +1,169 @@
+# Check if this is a in tree build.
+if (NOT DEFINED LLVM_MAIN_SRC_DIR)
+  project(Polly)
+  cmake_minimum_required(VERSION 2.8)
+
+  # Where is LLVM installed?
+  set(LLVM_INSTALL_ROOT "" CACHE PATH "Root of LLVM install.")
+  # Check if the LLVM_INSTALL_ROOT valid.
+  if( NOT EXISTS ${LLVM_INSTALL_ROOT}/include/llvm )
+    message(FATAL_ERROR "LLVM_INSTALL_ROOT (${LLVM_INSTALL_ROOT}) is not a valid LLVM installation.")
+  endif(NOT EXISTS ${LLVM_INSTALL_ROOT}/include/llvm)
+  #FileCheck is not install by default, warn the user to Copy FileCheck
+  if( NOT EXISTS ${LLVM_INSTALL_ROOT}/bin/FileCheck
+      OR NOT EXISTS ${LLVM_INSTALL_ROOT}/bin/not)
+    message(WARNING "FileCheck or not are required by running regress tests, "
+                    "but they are not installed! Please copy it to "
+                    "${LLVM_INSTALL_ROOT}/bin.")
+  endif(NOT EXISTS ${LLVM_INSTALL_ROOT}/bin/FileCheck
+        OR NOT EXISTS ${LLVM_INSTALL_ROOT}/bin/not)
+  # Add the llvm header path.
+  include_directories(${LLVM_INSTALL_ROOT}/include/)
+
+  # Get the system librarys that will link into LLVM.
+  function(get_system_libs return_var)
+    # Returns in `return_var' a list of system libraries used by LLVM.
+    if( NOT MSVC )
+      if( MINGW )
+        set(system_libs ${system_libs} imagehlp psapi)
+      elseif( CMAKE_HOST_UNIX )
+        if( HAVE_LIBDL )
+          set(system_libs ${system_libs} ${CMAKE_DL_LIBS})
+        endif()
+        if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD )
+          set(system_libs ${system_libs} pthread)
+        endif()
+      endif( MINGW )
+    endif( NOT MSVC )
+    set(${return_var} ${system_libs} PARENT_SCOPE)
+  endfunction(get_system_libs)
+
+  # Now set the header paths.
+  execute_process(COMMAND "${LLVM_INSTALL_ROOT}/bin/llvm-config" --includedir
+                  OUTPUT_VARIABLE LLVM_INCLUDE_DIR
+                  OUTPUT_STRIP_TRAILING_WHITESPACE)
+  include_directories( ${LLVM_INCLUDE_DIR} )
+
+  # Get the TARGET_TRIPLE
+  execute_process(COMMAND "${LLVM_INSTALL_ROOT}/bin/llvm-config" --host-target
+                  OUTPUT_VARIABLE TARGET_TRIPLE
+                  OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  # And then set the cxx flags.
+  execute_process(COMMAND "${LLVM_INSTALL_ROOT}/bin/llvm-config" --cxxflags
+                  OUTPUT_VARIABLE LLVM_CXX_FLAGS
+                  OUTPUT_STRIP_TRAILING_WHITESPACE)
+  set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS})
+
+  # Make sure the isl c files are built as fPIC
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+endif(NOT DEFINED LLVM_MAIN_SRC_DIR)
+
+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")
+endif ()
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
+
+# Define the FLAGS for the compilation of isl and imath
+#
+# Those are the only C files we have in the repository. Hence, we can just use
+# the CFLAGS to identify them.
+#
+# We first set the visibility of all isl functions to hidden to ensure we do
+# not clash with other isl versions that got linked into a program that uses
+# Polly. (This happens e.g when linking Polly with dragonegg)
+#
+# We also disable all warnings, as these should be fixed upstream. There is
+# no value in reporting them here.
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -w")
+
+# 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, as GPU code generation test cases can be run without
+  # a cuda library.
+  FIND_PACKAGE(CUDA)
+  set(GPU_CODEGEN TRUE)
+endif(POLLY_ENABLE_GPGPU_CODEGEN)
+
+# Support GPGPU code generation if the library is available.
+if (CUDALIB_FOUND)
+  INCLUDE_DIRECTORIES( ${CUDALIB_INCLUDE_DIR} )
+endif(CUDALIB_FOUND)
+
+include_directories(
+  BEFORE
+  ${CMAKE_CURRENT_SOURCE_DIR}/include
+  ${CMAKE_CURRENT_SOURCE_DIR}/lib/JSON/include
+  ${CMAKE_CURRENT_BINARY_DIR}/lib/External/isl/include
+  ${CMAKE_CURRENT_BINARY_DIR}/lib/External/isl
+  ${CMAKE_CURRENT_SOURCE_DIR}/lib/External/isl/include
+  ${CMAKE_CURRENT_SOURCE_DIR}/lib/External/isl/imath
+  ${CMAKE_CURRENT_SOURCE_DIR}/lib/External/isl
+  ${CMAKE_CURRENT_BINARY_DIR}/include
+  )
+
+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
+  )
+
+add_definitions( -D_GNU_SOURCE )
+
+add_subdirectory(include)
+add_subdirectory(lib)
+add_subdirectory(test)
+add_subdirectory(tools)
+# 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 *.cpp)
+file( GLOB_RECURSE jsonfiles lib/JSON/*.h lib/JSON/*.cpp)
+file( GLOB_RECURSE islfiles lib/External/isl/*.h lib/External/isl/*.c
+                   lib/External/isl/include/isl/*.h lib/External/isl/imath/*.h
+                   lib/External/isl/imath/*.c)
+list( REMOVE_ITEM files ${jsonfiles} ${islfiles})
+add_custom_command( OUTPUT formatting COMMAND
+  CLANG_FORMAT=${LLVM_BINARY_DIR}/bin/clang-format
+  ${CMAKE_CURRENT_SOURCE_DIR}/utils/check_format.sh ${files})
+add_custom_target(polly-check-format DEPENDS formatting)
+add_custom_command( OUTPUT formatting-update COMMAND
+  CLANG_FORMAT=${LLVM_BINARY_DIR}/bin/clang-format
+  ${CMAKE_CURRENT_SOURCE_DIR}/utils/update_format.sh ${files})
+add_custom_target(polly-update-format DEPENDS formatting-update)
+
+# Set the variable POLLY_LINK_LIBS in the llvm/tools/ dir.
+set(POLLY_LINK_LIBS ${POLLY_LINK_LIBS} PARENT_SCOPE)
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..86d29f5
--- /dev/null
+++ b/final/LICENSE.txt
@@ -0,0 +1,61 @@
+==============================================================================
+Polly Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2014 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/JSON
+
+
+
diff --git a/final/Makefile b/final/Makefile
new file mode 100644
index 0000000..2ad5b36
--- /dev/null
+++ b/final/Makefile
@@ -0,0 +1,17 @@
+##===- projects/polly/Makefile -----------------------------*- Makefile -*-===##
+#
+# This is a polly Makefile for a project that uses LLVM.
+#
+##===----------------------------------------------------------------------===##
+
+#
+# Indicates our relative path to the top of the project's root directory.
+#
+LEVEL = .
+DIRS = lib test tools
+EXTRA_DIST = include
+
+#
+# Include the Master Makefile that knows how to build all.
+#
+include $(LEVEL)/Makefile.common
diff --git a/final/Makefile.common.in b/final/Makefile.common.in
new file mode 100644
index 0000000..8a5b945
--- /dev/null
+++ b/final/Makefile.common.in
@@ -0,0 +1,34 @@
+#===-- Makefile.common - Common make rules for Polly -------*- Makefile -*--===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+#
+# Configuration file to set paths specific to local installation of LLVM
+#
+PROJECT_NAME := polly
+PROJ_VERSION := 0.9
+# Set this variable to the top of the LLVM source tree.
+LLVM_SRC_ROOT = @LLVM_SRC@
+
+# Set the name of the project here
+
+# (this is *not* the same as OBJ_ROOT as defined in LLVM's Makefile.config).
+LLVM_OBJ_ROOT = @LLVM_OBJ@
+
+PROJ_SRC_ROOT := $(subst //,/,@abs_top_srcdir@)
+
+# Set the root directory of this project's object files
+PROJ_OBJ_ROOT := $(subst //,/,@abs_top_builddir@)
+
+ifndef LLVM_OBJ_ROOT
+include $(LEVEL)/Makefile.config
+else
+include $(PROJ_OBJ_ROOT)/Makefile.config
+endif
+
+# Include LLVM's Master Makefile.
+include $(LLVM_SRC_ROOT)/Makefile.common
diff --git a/final/Makefile.config.in b/final/Makefile.config.in
new file mode 100644
index 0000000..457567e
--- /dev/null
+++ b/final/Makefile.config.in
@@ -0,0 +1,63 @@
+#===-- Makefile.config - Local configuration for LLVM ------*- Makefile -*--===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+#
+# This file is included by Makefile.common.  It defines paths and other
+# values specific to a particular installation of LLVM.
+#
+#===------------------------------------------------------------------------===#
+
+# Set the root directory of this polly's object files
+POLLY_SRC_ROOT := $(subst //,/,@abs_top_srcdir@)
+
+# Set this variable to the top level directory where LLVM was built
+POLLY_OBJ_ROOT := $(subst //,/,@abs_top_builddir@)
+
+# Set the root directory of this project's install prefix
+PROJ_INSTALL_ROOT := @prefix@
+
+# Set the C++ flags
+ifeq (@GXX@,yes)
+POLLY_CXXFLAGS := "-fno-common -Woverloaded-virtual -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings"
+endif
+
+POLLY_CXXFLAGS += "-fno-rtti -fno-exceptions"
+
+# Define the FLAGS for the compilation of isl and imath
+#
+# Those are the only C files we have in the repository. Hence, we can just use
+# the CFLAGS to identify them.
+#
+# We first set the visibility of all isl functions to hidden to ensure we do
+# not clash with other isl versions that got linked into a program that uses
+# Polly. (This happens e.g when linking Polly with dragonegg)
+#
+# We also disable all warnings, as these should be fixed upstream. There is
+# no value in reporting them here.
+#
+# ISL with activated small integer optimization use C99 extern inline
+# semantics. In order to work, we need to enable C99 mode (instead the default
+# -std=gnu89 in case of gcc)
+POLLY_CFLAGS := -fvisibility=hidden
+POLLY_CFLAGS += -w
+POLLY_CFLAGS += -std=gnu99
+
+CUDALIB_FOUND := @cuda_found@
+
+# Set include directories
+POLLY_INC :=  @cuda_inc@ \
+              -I$(POLLY_OBJ_ROOT)/lib/External/isl/include \
+              -I$(POLLY_OBJ_ROOT)/lib/External/isl \
+              -I$(POLLY_SRC_ROOT)/lib/JSON/include \
+              -I$(POLLY_SRC_ROOT)/lib/External/isl/include \
+              -I$(POLLY_SRC_ROOT)/lib/External/isl/imath \
+              -I$(POLLY_SRC_ROOT)/lib/External/isl
+
+POLLY_LD := @cuda_ld@
+
+POLLY_LIB := @cuda_lib@
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/autoconf/AutoRegen.sh b/final/autoconf/AutoRegen.sh
new file mode 100755
index 0000000..bafef34
--- /dev/null
+++ b/final/autoconf/AutoRegen.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+die () {
+	echo "$@" 1>&2
+	exit 1
+}
+
+test -d autoconf && test -f autoconf/configure.ac && cd autoconf
+test -f configure.ac || die "Can't find 'autoconf' dir; please cd into it first"
+autoconf --version | egrep '2\.[5-6][0-9]' > /dev/null
+if test $? -ne 0 ; then
+	die "Your autoconf was not detected as being 2.5x"
+fi
+cwd=`pwd`
+if test -d ../../../autoconf/m4 ; then
+  cd ../../../autoconf/m4
+  llvm_m4=`pwd`
+  cd $cwd
+elif test -d ../../llvm/autoconf/m4 ; then
+  cd ../../llvm/autoconf/m4
+  llvm_m4=`pwd`
+  cd $cwd
+else
+  die "Can't find the LLVM autoconf/m4 directory. polly should be checked out to projects directory"
+fi
+echo "Regenerating aclocal.m4 with aclocal"
+rm -f aclocal.m4
+aclocal -I $llvm_m4 -I "$llvm_m4/.." -I $(pwd)/m4 || die "aclocal failed"
+echo "Regenerating configure with autoconf 2.5x"
+autoconf --force --warnings=all -o ../configure configure.ac || die "autoconf failed"
+cd ..
+echo "Regenerating config.h.in with autoheader"
+autoheader --warnings=all -I autoconf -I autoconf/m4 -I $llvm_m4 -I "$llvm_m4/.." autoconf/configure.ac || die "autoheader failed"
+exit 0
diff --git a/final/autoconf/LICENSE.TXT b/final/autoconf/LICENSE.TXT
new file mode 100644
index 0000000..72fdd39
--- /dev/null
+++ b/final/autoconf/LICENSE.TXT
@@ -0,0 +1,24 @@
+------------------------------------------------------------------------------
+Autoconf Files
+------------------------------------------------------------------------------
+All autoconf files are licensed under the LLVM license with the following
+additions:
+
+llvm/autoconf/install-sh:
+	This script is licensed under the LLVM license, with the following
+	additional copyrights and restrictions:
+
+	Copyright 1991 by the Massachusetts Institute of Technology
+
+	Permission to use, copy, modify, distribute, and sell this software and its
+	documentation for any purpose is hereby granted without fee, provided that
+	the above copyright notice appear in all copies and that both that
+	copyright notice and this permission notice appear in supporting 
+	documentation, and that the name of M.I.T. not be used in advertising or
+	publicity pertaining to distribution of the software without specific,
+	written prior permission.  M.I.T. makes no representations about the
+	suitability of this software for any purpose.  It is provided "as is"
+	without express or implied warranty.
+
+Please see the source files for additional copyrights.
+
diff --git a/final/autoconf/aclocal.m4 b/final/autoconf/aclocal.m4
new file mode 100644
index 0000000..07893d5
--- /dev/null
+++ b/final/autoconf/aclocal.m4
@@ -0,0 +1,77 @@
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 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($@)])])
+dnl find_lib_and_headers(name, verify-header, library-name, requirded?)
+dnl Export
+dnl         name_inc in -I"include-path" form
+dnl         name_lib in -l"library-name" form
+dnl         name_ld  in -L"library-path" form
+dnl         name_found set to "yes" if found
+
+AC_DEFUN([find_lib_and_headers],
+[
+  AC_LANG_PUSH(C++)
+  OLD_CXXFLAGS=$CXXFLAGS;
+  OLD_LDFLAGS=$LDFLAGS;
+  OLD_LIBS=$LIBS;
+
+  LIBS="$LIBS -l$3";
+
+  # Get include path and lib path
+  AC_ARG_WITH([$1],
+    [AS_HELP_STRING([--with-$1], [prefix of $1 ])],
+      [given_inc_path="$withval/include"; CXXFLAGS="-I$given_inc_path $CXXFLAGS";
+       given_lib_path="$withval/lib"; LDFLAGS="-L$given_lib_path $LDFLAGS"],
+      [given_inc_path=inc_not_give_$1;
+       given_lib_path=lib_not_give_$1]
+    )
+  # Check for library and headers works
+  AC_MSG_CHECKING([for $1: $2 in $given_inc_path, and lib$3 in $given_lib_path])
+
+  # try to compile a file that includes a header of the library
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <$2>]], [[;]])],
+    [AC_MSG_RESULT([ok])
+    AC_SUBST([$1_found],["yes"])
+    AS_IF([test "x$given_inc_path" != "xinc_not_give_$1"],
+      [AC_SUBST([$1_inc],["-I$given_inc_path"])])
+    AC_SUBST([$1_lib],["-l$3"])
+    AS_IF([test "x$given_lib_path" != "xlib_not_give_$1"],
+      [AC_SUBST([$1_ld],["-L$given_lib_path"])])],
+    [AS_IF([test "x$4" = "xrequired"],
+      [AC_MSG_ERROR([$1 required but not found])],
+      [AC_MSG_RESULT([not found])])]
+  )
+
+  # reset original CXXFLAGS
+  CXXFLAGS=$OLD_CXXFLAGS
+  LDFLAGS=$OLD_LDFLAGS;
+  LIBS=$OLD_LIBS
+  AC_LANG_POP(C++)
+])
+
+#
+# Provide the arguments and other processing needed for an LLVM project
+#
+AC_DEFUN([LLVM_CONFIG_PROJECT],
+  [AC_ARG_WITH([llvmsrc],
+    AS_HELP_STRING([--with-llvmsrc],[Location of LLVM Source Code]),
+    [llvm_src="$withval"],[llvm_src="]$1["])
+  AC_SUBST(LLVM_SRC,$llvm_src)
+  AC_ARG_WITH([llvmobj],
+    AS_HELP_STRING([--with-llvmobj],[Location of LLVM Object Code]),
+    [llvm_obj="$withval"],[llvm_obj="]$2["])
+  AC_SUBST(LLVM_OBJ,$llvm_obj)
+  AC_CONFIG_COMMANDS([setup],,[llvm_src="${LLVM_SRC}"])
+])
+
diff --git a/final/autoconf/config.guess b/final/autoconf/config.guess
new file mode 100644
index 0000000..cc726cd
--- /dev/null
+++ b/final/autoconf/config.guess
@@ -0,0 +1,1388 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-02-22'
+
+# 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, 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.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted 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.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+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
+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 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # 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 -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { 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 ;'
+
+# 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 tupples: *-*-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 ;;
+	    *) 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 __ELF__ >/dev/null
+		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 0 ;;
+    amiga:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    arc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    hp300:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mac68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    macppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+	echo m88k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    pmax:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sgi:OpenBSD:*:*)
+	echo mipseb-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sun3:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    *:OpenBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	if test $UNAME_RELEASE = "V4.0"; then
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+	fi
+	# 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 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/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit 0 ;;
+    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 0 ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit 0;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit 0 ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit 0 ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit 0;;
+    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 0 ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7 && exit 0 ;;
+	esac ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    i86pc:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    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 0 ;;
+    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 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    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 0 ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    # 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 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit 0 ;;
+    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 \
+	  && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+	  && exit 0
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit 0 ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    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 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit 0 ;;
+    ????????: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 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    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 0 ;;
+    *: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
+		$CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+		echo rs6000-ibm-aix3.2.5
+	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 0 ;;
+    *:AIX:*:[45])
+	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 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    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
+	    # avoid double evaluation of $set_cc_for_build
+	    test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    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 && $dummy && exit 0
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit 0 ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    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 0 ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    *:UNICOS/mp:*:*)
+	echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' 
+	exit 0 ;;
+    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 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*)
+	# Determine whether the default compiler uses glibc.
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#if __GLIBC__ >= 2
+	LIBC=gnu
+	#else
+	LIBC=
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+	exit 0 ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit 0 ;;
+    i*:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit 0 ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit 0 ;;
+    x86:Interix*:3*)
+	echo i586-pc-interix3
+	exit 0 ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit 0 ;;
+    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 0 ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit 0 ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit 0 ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit 0 ;;
+    arm*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#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 0
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#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 0
+	;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit 0 ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit 0 ;;
+    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 ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit 0 ;;
+    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 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit 0 ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit 0 ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit 0 ;;
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit 0 ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit 0 ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#ifdef __INTEL_COMPILER
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+	test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+	;;
+    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 0 ;;
+    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 0 ;;
+    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 0 ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit 0 ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit 0 ;;
+    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 0 ;;
+    i*86:*:5:[78]*)
+	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 0 ;;
+    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 0 ;;
+    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 i386.
+	echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit 0 ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit 0 ;;
+    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 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit 0 ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit 0 ;;
+    M68*:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*: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)
+	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 0
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *: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 0 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit 0 ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit 0 ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit 0 ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit 0 ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit 0 ;;
+    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 0 ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit 0 ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit 0 ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Darwin:*:*)
+	case `uname -p` in
+	    *86) UNAME_PROCESSOR=i686 ;;
+	    powerpc) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit 0 ;;
+    *: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 0 ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit 0 ;;
+    NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit 0 ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit 0 ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit 0 ;;
+    *: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 0 ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit 0 ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit 0 ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit 0 ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit 0 ;;
+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"); 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 && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# 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 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    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
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+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/autoconf/config.sub b/final/autoconf/config.sub
new file mode 100644
index 0000000..9772e87
--- /dev/null
+++ b/final/autoconf/config.sub
@@ -0,0 +1,1489 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-02-22'
+
+# 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, 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.
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted 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.
+
+# 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
+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 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # 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 0;;
+
+    * )
+       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* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    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)
+		os=
+		basic_machine=$1
+		;;
+	-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
+		;;
+	-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/'`
+		;;
+	-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*)
+		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 \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+	| clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k \
+	| m32r | m68000 | m68k | m88k | mcore \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| msp430 \
+	| ns16k | ns32k \
+	| openrisc | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+	| strongarm \
+	| tahoe | thumb | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xscale | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+
+	# 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-* \
+	| 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-* \
+	| bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* \
+	| m32r-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| msp430-* \
+	| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+	| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+	| xtensa-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# 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
+		;;
+	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
+		;;
+	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
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	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
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	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
+		;;
+	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'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	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
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	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
+		;;
+	mmix*)
+		basic_machine=mmix-knuth
+		os=-mmixware
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	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
+		;;
+	nv1)
+		basic_machine=nv1-cray
+		os=-unicosmp
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	or32 | or32-*)
+		basic_machine=or32-unknown
+		os=-coff
+		;;
+	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
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2)
+		basic_machine=i686-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-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	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
+		;;
+	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
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	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
+		;;
+	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
+		;;
+        tic4x | c4x*)
+		basic_machine=tic4x-unknown
+		os=-coff
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	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
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-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
+		;;
+	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
+		;;
+	sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparc | sparcv9 | sparcv9b)
+		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.
+	-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* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -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*)
+	# 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* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-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
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-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
+		;;
+	-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
+		;;
+	-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
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	# 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
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	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
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-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
+				;;
+			-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
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-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 0
+
+# 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/autoconf/configure.ac b/final/autoconf/configure.ac
new file mode 100644
index 0000000..3a7d06c
--- /dev/null
+++ b/final/autoconf/configure.ac
@@ -0,0 +1,108 @@
+dnl **************************************************************************
+dnl * Initialize
+dnl **************************************************************************
+AC_INIT([Polly],[0.01],[polly-dev@googlegroups.com])
+
+dnl Identify where LLVM source tree is
+LLVM_SRC_ROOT="`(cd $srcdir/../..; pwd)`"
+LLVM_OBJ_ROOT="`(cd ../..; pwd)`"
+
+dnl Tell autoconf that this is an LLVM project being configured
+dnl This provides the --with-llvmsrc and --with-llvmobj options
+LLVM_CONFIG_PROJECT($LLVM_SRC_ROOT,$LLVM_OBJ_ROOT)
+
+dnl Tell autoconf that the auxiliary files are actually located in
+dnl the LLVM autoconf directory, not here.
+AC_CONFIG_AUX_DIR($LLVM_SRC/autoconf)
+
+dnl Indicate that we require autoconf 2.59 or later. Ths is needed because we
+dnl use some autoconf macros only available in 2.59.
+AC_PREREQ(2.59)
+
+dnl Verify that the source directory is valid
+AC_CONFIG_SRCDIR(["lib/Analysis/ScopInfo.cpp"])
+
+dnl Configure a common Makefile
+AC_CONFIG_FILES(Makefile.config)
+AC_CONFIG_FILES(Makefile.common)
+
+dnl Configure project makefiles
+dnl List every Makefile that exists within your source tree
+
+dnl Quit if the source directory has already been configured.
+dnl NOTE: This relies upon undocumented autoconf behavior.
+if test ${srcdir} != "." ; then
+  if test -f ${srcdir}/include/polly/Config/config.h ; then
+    AC_MSG_ERROR([Already configured in ${srcdir}])
+  fi
+fi
+
+dnl **************************************************************************
+dnl * Determine which system we are building on
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Check for programs.
+dnl **************************************************************************
+
+dnl AC_PROG_CPP
+dnl AC_PROG_CC(gcc)
+dnl AC_PROG_CXX(g++)
+
+dnl **************************************************************************
+dnl * Check for libraries.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Checks for header files.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Checks for typedefs, structures, and compiler characteristics.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Checks for library functions.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Enable various compile-time options
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Set the location of various third-party software packages
+dnl **************************************************************************
+
+dnl Check if CUDA lib there
+dnl Disable the build of polly, even if it is checked out into tools/polly.
+AC_ARG_ENABLE(polly_gpu_codegen,
+              AS_HELP_STRING([--enable-polly-gpu-codegen],
+                             [Enable GPU code generation in Polly(default is NO)]),,
+                             enableval=default)
+case "$enableval" in
+  yes) AC_DEFINE([GPU_CODEGEN],[1], [Define if gpu codegen is enabled]) ;;
+  no) ;;
+  default) ;;
+  *) AC_MSG_ERROR([Invalid setting for --enable-polly-gpu-codegen. Use "yes" or "no"]) ;;
+esac
+
+find_lib_and_headers([cuda], [cuda.h], [cuda])
+
+AS_IF([test "x$cuda_found" = "xyes"],
+  [AC_DEFINE([CUDALIB_FOUND],[1],[Define if cudalib found])])
+
+dnl **************************************************************************
+dnl * Create the output files
+dnl **************************************************************************
+
+dnl Let ISL's configure generate isl_config.h and gitversion.h
+AC_CONFIG_SUBDIRS(lib/External/isl)
+AC_CONFIG_COMMANDS_POST([
+  dnl Configure ISL with small integer optimization, but do not add the
+  dnl option to config.status as it is mandatory for Polly.
+  ac_configure_args="$ac_configure_args --with-int=imath-32"
+])
+
+dnl This must be last
+AC_CONFIG_HEADERS(include/polly/Config/config.h)
+AC_OUTPUT
diff --git a/final/autoconf/configure.bak b/final/autoconf/configure.bak
new file mode 100644
index 0000000..f1cac90
--- /dev/null
+++ b/final/autoconf/configure.bak
@@ -0,0 +1,65 @@
+dnl **************************************************************************
+dnl * Initialize
+dnl **************************************************************************
+AC_INIT([Polly],[0.01],[etherzhhb@gmail.com grosser@fim.uni-passau.de ojomojo@gmail.com])
+
+dnl Identify where LLVM source tree is
+LLVM_SRC_ROOT="../.."
+LLVM_OBJ_ROOT="../.."
+dnl Tell autoconf that the auxiliary files are actually located in
+dnl the LLVM autoconf directory, not here.
+AC_CONFIG_AUX_DIR($LLVM_SRC_ROOT/autoconf)
+
+dnl Tell autoconf that this is an LLVM project being configured
+dnl This provides the --with-llvmsrc and --with-llvmobj options
+LLVM_CONFIG_PROJECT($LLVM_SRC_ROOT,$LLVM_OBJ_ROOT)
+
+dnl Verify that the source directory is valid
+AC_CONFIG_SRCDIR(["Makefile.common.in"])
+
+dnl Configure a common Makefile
+AC_CONFIG_FILES(Makefile.common)
+
+dnl Configure project makefiles
+dnl List every Makefile that exists within your source tree
+AC_CONFIG_MAKEFILE(Makefile)
+AC_CONFIG_MAKEFILE(lib/Makefile)
+
+dnl **************************************************************************
+dnl * Determine which system we are building on
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Check for programs.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Check for libraries.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Checks for header files.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Checks for typedefs, structures, and compiler characteristics.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Checks for library functions.
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Enable various compile-time options
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Set the location of various third-party software packages
+dnl **************************************************************************
+
+dnl **************************************************************************
+dnl * Create the output files
+dnl **************************************************************************
+
+dnl This must be last
+AC_OUTPUT
diff --git a/final/autoconf/m4/find_lib_and_headers.m4 b/final/autoconf/m4/find_lib_and_headers.m4
new file mode 100644
index 0000000..e872819
--- /dev/null
+++ b/final/autoconf/m4/find_lib_and_headers.m4
@@ -0,0 +1,47 @@
+dnl find_lib_and_headers(name, verify-header, library-name, requirded?)
+dnl Export
+dnl         name_inc in -I"include-path" form
+dnl         name_lib in -l"library-name" form
+dnl         name_ld  in -L"library-path" form
+dnl         name_found set to "yes" if found
+
+AC_DEFUN([find_lib_and_headers],
+[
+  AC_LANG_PUSH(C++)
+  OLD_CXXFLAGS=$CXXFLAGS;
+  OLD_LDFLAGS=$LDFLAGS;
+  OLD_LIBS=$LIBS;
+
+  LIBS="$LIBS -l$3";
+
+  # Get include path and lib path
+  AC_ARG_WITH([$1],
+    [AS_HELP_STRING([--with-$1], [prefix of $1 ])],
+      [given_inc_path="$withval/include"; CXXFLAGS="-I$given_inc_path $CXXFLAGS";
+       given_lib_path="$withval/lib"; LDFLAGS="-L$given_lib_path $LDFLAGS"],
+      [given_inc_path=inc_not_give_$1;
+       given_lib_path=lib_not_give_$1]
+    )
+  # Check for library and headers works
+  AC_MSG_CHECKING([for $1: $2 in $given_inc_path, and lib$3 in $given_lib_path])
+
+  # try to compile a file that includes a header of the library
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <$2>]], [[;]])],
+    [AC_MSG_RESULT([ok])
+    AC_SUBST([$1_found],["yes"])
+    AS_IF([test "x$given_inc_path" != "xinc_not_give_$1"],
+      [AC_SUBST([$1_inc],["-I$given_inc_path"])])
+    AC_SUBST([$1_lib],["-l$3"])
+    AS_IF([test "x$given_lib_path" != "xlib_not_give_$1"],
+      [AC_SUBST([$1_ld],["-L$given_lib_path"])])],
+    [AS_IF([test "x$4" = "xrequired"],
+      [AC_MSG_ERROR([$1 required but not found])],
+      [AC_MSG_RESULT([not found])])]
+  )
+
+  # reset original CXXFLAGS
+  CXXFLAGS=$OLD_CXXFLAGS
+  LDFLAGS=$OLD_LDFLAGS;
+  LIBS=$OLD_LIBS
+  AC_LANG_POP(C++)
+])
diff --git a/final/cmake/FindCUDA.cmake b/final/cmake/FindCUDA.cmake
new file mode 100644
index 0000000..37592f9
--- /dev/null
+++ b/final/cmake/FindCUDA.cmake
@@ -0,0 +1,23 @@
+IF (NOT CUDA_HEADER_PREFIX)
+  SET(CUDA_HEADER_PREFIX "/usr/local/cuda/include")
+ENDIF (NOT CUDA_HEADER_PREFIX)
+
+FIND_PATH(CUDALIB_INCLUDE_DIR
+  NAMES cuda.h
+  PATHS ${CUDA_HEADER_PREFIX})
+
+FIND_LIBRARY(CUDALIB_LIBRARY NAMES cuda)
+
+IF (CUDALIB_INCLUDE_DIR)
+  SET(CUDALIB_FOUND TRUE)
+ENDIF (CUDALIB_INCLUDE_DIR)
+
+IF (CUDALIB_FOUND)
+  IF (NOT CUDA_FIND_QUIETLY)
+    MESSAGE(STATUS "Found CUDA: ${CUDALIB_INCLUDE_DIR}")
+  ENDIF (NOT CUDA_FIND_QUIETLY)
+ELSE (CUDALIB_FOUND)
+  IF (CUDA_FIND_REQUIRED)
+    MESSAGE(FATAL_ERROR "Could not find CUDA")
+  ENDIF (CUDA_FIND_REQUIRED)
+ENDIF (CUDALIB_FOUND)
diff --git a/final/cmake/polly_macros.cmake b/final/cmake/polly_macros.cmake
new file mode 100644
index 0000000..ab06661
--- /dev/null
+++ b/final/cmake/polly_macros.cmake
@@ -0,0 +1,88 @@
+
+macro(add_polly_library name)
+  set(srcs ${ARGN})
+  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} )
+  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(MSVC)
+    get_target_property(cflag ${name} COMPILE_FLAGS)
+    if(NOT cflag)
+      set(cflag "")
+    endif(NOT cflag)
+    set(cflag "${cflag} /Za")
+    set_target_properties(${name} PROPERTIES COMPILE_FLAGS ${cflag})
+  endif(MSVC)
+  install(TARGETS ${name}
+    EXPORT LLVMExports
+    LIBRARY DESTINATION lib
+    ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
+  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})
+  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/configure b/final/configure
new file mode 100755
index 0000000..28aabea
--- /dev/null
+++ b/final/configure
@@ -0,0 +1,3938 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for Polly 0.01.
+#
+# Report bugs to <polly-dev@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"
+  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: polly-dev@googlegroups.com about your system, including
+$0: any error possibly output before this message. Then
+$0: install a modern shell, or manually run the script
+$0: 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'"
+
+
+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='Polly'
+PACKAGE_TARNAME='polly'
+PACKAGE_VERSION='0.01'
+PACKAGE_STRING='Polly 0.01'
+PACKAGE_BUGREPORT='polly-dev@googlegroups.com'
+PACKAGE_URL=''
+
+ac_unique_file=""lib/Analysis/ScopInfo.cpp""
+enable_option_checking=no
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+subdirs
+cuda_ld
+cuda_lib
+cuda_inc
+cuda_found
+OBJEXT
+EXEEXT
+ac_ct_CXX
+CPPFLAGS
+LDFLAGS
+CXXFLAGS
+CXX
+LLVM_OBJ
+LLVM_SRC
+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
+with_llvmsrc
+with_llvmobj
+enable_polly_gpu_codegen
+with_cuda
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CXX
+CXXFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CCC'
+ac_subdirs_all='lib/External/isl'
+
+# 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 Polly 0.01 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/polly]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of Polly 0.01:";;
+   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-polly-gpu-codegen
+                          Enable GPU code generation in Polly(default is NO)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-llvmsrc          Location of LLVM Source Code
+  --with-llvmobj          Location of LLVM Object Code
+  --with-cuda             prefix of cuda
+
+Some influential environment variables:
+  CXX         C++ compiler command
+  CXXFLAGS    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>
+
+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 <polly-dev@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
+Polly configure 0.01
+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_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_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
+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 Polly $as_me 0.01, 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
+
+
+
+LLVM_SRC_ROOT="`(cd $srcdir/../..; pwd)`"
+LLVM_OBJ_ROOT="`(cd ../..; pwd)`"
+
+
+# Check whether --with-llvmsrc was given.
+if test "${with_llvmsrc+set}" = set; then :
+  withval=$with_llvmsrc; llvm_src="$withval"
+else
+  llvm_src="$LLVM_SRC_ROOT"
+fi
+
+  LLVM_SRC=$llvm_src
+
+
+# Check whether --with-llvmobj was given.
+if test "${with_llvmobj+set}" = set; then :
+  withval=$with_llvmobj; llvm_obj="$withval"
+else
+  llvm_obj="$LLVM_OBJ_ROOT"
+fi
+
+  LLVM_OBJ=$llvm_obj
+
+  ac_config_commands="$ac_config_commands setup"
+
+
+
+ac_aux_dir=
+for ac_dir in $LLVM_SRC/autoconf "$srcdir"/$LLVM_SRC/autoconf; 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 $LLVM_SRC/autoconf \"$srcdir\"/$LLVM_SRC/autoconf" "$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.
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files Makefile.config"
+
+ac_config_files="$ac_config_files Makefile.common"
+
+
+
+if test ${srcdir} != "." ; then
+  if test -f ${srcdir}/include/polly/Config/config.h ; then
+    as_fn_error $? "Already configured in ${srcdir}" "$LINENO" 5
+  fi
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-polly_gpu_codegen was given.
+if test "${enable_polly_gpu_codegen+set}" = set; then :
+  enableval=$enable_polly_gpu_codegen;
+else
+  enableval=default
+fi
+
+case "$enableval" in
+  yes)
+$as_echo "#define GPU_CODEGEN 1" >>confdefs.h
+ ;;
+  no) ;;
+  default) ;;
+  *) as_fn_error $? "Invalid setting for --enable-polly-gpu-codegen. Use \"yes\" or \"no\"" "$LINENO" 5 ;;
+esac
+
+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
+
+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_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=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_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
+
+  OLD_CXXFLAGS=$CXXFLAGS;
+  OLD_LDFLAGS=$LDFLAGS;
+  OLD_LIBS=$LIBS;
+
+  LIBS="$LIBS -lcuda";
+
+  # Get include path and lib path
+
+# Check whether --with-cuda was given.
+if test "${with_cuda+set}" = set; then :
+  withval=$with_cuda; given_inc_path="$withval/include"; CXXFLAGS="-I$given_inc_path $CXXFLAGS";
+       given_lib_path="$withval/lib"; LDFLAGS="-L$given_lib_path $LDFLAGS"
+else
+  given_inc_path=inc_not_give_cuda;
+       given_lib_path=lib_not_give_cuda
+
+fi
+
+  # Check for library and headers works
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cuda: cuda.h in $given_inc_path, and libcuda in $given_lib_path" >&5
+$as_echo_n "checking for cuda: cuda.h in $given_inc_path, and libcuda in $given_lib_path... " >&6; }
+
+  # try to compile a file that includes a header of the library
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <cuda.h>
+int
+main ()
+{
+;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+    cuda_found="yes"
+
+    if test "x$given_inc_path" != "xinc_not_give_cuda"; then :
+  cuda_inc="-I$given_inc_path"
+
+fi
+    cuda_lib="-lcuda"
+
+    if test "x$given_lib_path" != "xlib_not_give_cuda"; then :
+  cuda_ld="-L$given_lib_path"
+
+fi
+else
+  if test "x" = "xrequired"; then :
+  as_fn_error $? "cuda required but not found" "$LINENO" 5
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+fi
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+  # reset original CXXFLAGS
+  CXXFLAGS=$OLD_CXXFLAGS
+  LDFLAGS=$OLD_LDFLAGS;
+  LIBS=$OLD_LIBS
+  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$cuda_found" = "xyes"; then :
+
+$as_echo "#define CUDALIB_FOUND 1" >>confdefs.h
+
+fi
+
+
+
+
+subdirs="$subdirs lib/External/isl"
+
+
+
+ac_config_headers="$ac_config_headers include/polly/Config/config.h"
+
+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
+
+
+
+: "${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 Polly $as_me 0.01, 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 <polly-dev@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="\\
+Polly config.status 0.01
+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'
+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
+#
+llvm_src="${LLVM_SRC}"
+
+_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
+    "setup") CONFIG_COMMANDS="$CONFIG_COMMANDS setup" ;;
+    "Makefile.config") CONFIG_FILES="$CONFIG_FILES Makefile.config" ;;
+    "Makefile.common") CONFIG_FILES="$CONFIG_FILES Makefile.common" ;;
+    "include/polly/Config/config.h") CONFIG_HEADERS="$CONFIG_HEADERS include/polly/Config/config.h" ;;
+
+  *) 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
+  #
+
+_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
+$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
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  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 --with-int=imath-32"
+
+
+# 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/include/CMakeLists.txt b/final/include/CMakeLists.txt
new file mode 100644
index 0000000..abe73d1
--- /dev/null
+++ b/final/include/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(polly)
diff --git a/final/include/polly/CMakeLists.txt b/final/include/polly/CMakeLists.txt
new file mode 100644
index 0000000..ef92163
--- /dev/null
+++ b/final/include/polly/CMakeLists.txt
@@ -0,0 +1,9 @@
+if( MSVC_IDE OR XCODE )
+  # Creates a dummy target containing all headers for the benefit of
+  # Visual Studio users.
+  file(GLOB_RECURSE headers *.h)
+  add_library(polly_headers_do_not_build EXCLUDE_FROM_ALL
+    # We need at least one source file:
+    ${POLLY_SOURCE_DIR}/lib/Support/GICHelper.cpp
+    ${headers})
+endif()
diff --git a/final/include/polly/Canonicalization.h b/final/include/polly/Canonicalization.h
new file mode 100644
index 0000000..723b490
--- /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 {
+
+/// @brief 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);
+}
+
+#endif
diff --git a/final/include/polly/CodeGen/BlockGenerators.h b/final/include/polly/CodeGen/BlockGenerators.h
new file mode 100644
index 0000000..64a1540
--- /dev/null
+++ b/final/include/polly/CodeGen/BlockGenerators.h
@@ -0,0 +1,611 @@
+//===-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 "llvm/ADT/DenseMap.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "isl/map.h"
+#include <vector>
+
+struct isl_ast_build;
+
+namespace llvm {
+class Pass;
+class Region;
+class ScalarEvolution;
+}
+
+namespace polly {
+using namespace llvm;
+class ScopStmt;
+class MemoryAccess;
+class IslExprBuilder;
+
+typedef DenseMap<const Value *, Value *> ValueMapT;
+typedef std::vector<ValueMapT> VectorValueMapT;
+
+/// @brief Check whether an instruction can be synthesized by the code
+///        generator.
+///
+/// Some instructions 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 I The instruction to check.
+/// @param LI The LoopInfo analysis.
+/// @param SE The scalar evolution database.
+/// @param R The region out of which SSA names are parameters.
+/// @return If the instruction I can be regenerated from its
+///         scalar evolution representation, return true,
+///         otherwise return false.
+bool canSynthesize(const llvm::Instruction *I, const llvm::LoopInfo *LI,
+                   llvm::ScalarEvolution *SE, const llvm::Region *R);
+
+/// @brief Return true iff @p V is an intrinsic that we ignore during code
+///        generation.
+bool isIgnoredIntrinsic(const llvm::Value *V);
+
+/// @brief Generate a new basic block for a polyhedral statement.
+class BlockGenerator {
+public:
+  /// @brief Map types to resolve scalar dependences.
+  ///
+  ///@{
+
+  /// @see The ScalarMap and PHIOpMap member.
+  using ScalarAllocaMapTy = DenseMap<Instruction *, AllocaInst *>;
+
+  /// @brief Simple vector of instructions to store escape users.
+  using EscapeUserVectorTy = SmallVector<Instruction *, 4>;
+
+  /// @brief Map type to resolve escaping users for scalar instructions.
+  ///
+  /// @see The EscapeMap member.
+  using EscapeUsersAllocaMapTy =
+      DenseMap<Instruction *, std::pair<AllocaInst *, EscapeUserVectorTy>>;
+
+  ///@}
+
+  /// @brief 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 PHIOpMap    Map from PHIs to their demoted operand location.
+  /// @param EscapeMap   Map from scalars to their escape users and locations.
+  /// @param ExprBuilder An expression builder to generate new access functions.
+  BlockGenerator(PollyIRBuilder &Builder, LoopInfo &LI, ScalarEvolution &SE,
+                 DominatorTree &DT, ScalarAllocaMapTy &ScalarMap,
+                 ScalarAllocaMapTy &PHIOpMap, EscapeUsersAllocaMapTy &EscapeMap,
+                 IslExprBuilder *ExprBuilder = nullptr);
+
+  /// @brief 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 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 map from old loops to new induction variables as SCEVs.
+  void copyStmt(ScopStmt &Stmt, ValueMapT &GlobalMap, LoopToScevMapT &LTS);
+
+  /// @brief 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(Region &, ValueMapT &)
+  /// @see createScalarFinalization(Region &)
+  void finalizeSCoP(Scop &S, ValueMapT &VMap);
+
+  /// @brief An empty destructor
+  virtual ~BlockGenerator(){};
+
+protected:
+  PollyIRBuilder &Builder;
+  LoopInfo &LI;
+  ScalarEvolution &SE;
+  IslExprBuilder *ExprBuilder;
+
+  /// @brief The dominator tree of this function.
+  DominatorTree &DT;
+
+  /// @brief The entry block of the current function.
+  BasicBlock *EntryBB;
+
+  /// @brief Maps to resolve scalar dependences for PHI operands and scalars.
+  ///
+  /// Usage example:
+  ///
+  ///  x1 = ...   // x1 will be inserted in the ScalarMap and PhiOpMap.
+  ///  for (i=0...N) {
+  ///      x2 = phi(x1, add) // x2 will be inserted in the ScalarMap, x1 and
+  ///                        // add are mapped in the PHIOpMap.
+  ///      add = x2 + A[i];  // add will be inserted in the ScalarMap and
+  ///                        // the PhiOpMap.
+  ///  }
+  ///  print(x1)  // x1 is mapped in the ScalarMap.
+  ///  print(x2)  // x2 is mapped in the ScalarMap.
+  ///  print(add) // add is mapped in the ScalarMap.
+  ///
+  ///{
+
+  /// The PHIOpMap is used to get the alloca to communicate a value to a PHI
+  /// node, hence when the operand of a PHI is demoted the corresponding write
+  /// access will use the PHIOpMap to look for the correct alloca. PHI nodes
+  /// will then read that location in order to get the correct/current operand
+  /// value.
+  ScalarAllocaMapTy &PHIOpMap;
+
+  /// The ScalarMap is used in __all__ other cases, thus always when a scalar
+  /// variable is read/written and the write is not because the scalar is a PHI
+  /// operand.
+  ScalarAllocaMapTy &ScalarMap;
+  ///}
+
+  /// @brief Map from instructions to their escape users as well as the alloca.
+  EscapeUsersAllocaMapTy &EscapeMap;
+
+  /// @brief Split @p BB to create a new one we can use to clone @p BB in.
+  BasicBlock *splitBB(BasicBlock *BB);
+
+  /// @brief 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 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 map from old loops to new induction variables as SCEVs.
+  ///
+  /// @returns The copy of the basic block.
+  BasicBlock *copyBB(ScopStmt &Stmt, BasicBlock *BB, ValueMapT &BBMap,
+                     ValueMapT &GlobalMap, LoopToScevMapT &LTS);
+
+  /// @brief 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 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 map from old loops to new induction variables as SCEVs.
+  void copyBB(ScopStmt &Stmt, BasicBlock *BB, BasicBlock *BBCopy,
+              ValueMapT &BBMap, ValueMapT &GlobalMap, LoopToScevMapT &LTS);
+
+  /// @brief Return the alloca for @p ScalarBase in @p Map.
+  ///
+  /// If no alloca was mapped to @p ScalarBase in @p Map a new one is created
+  /// and named after @p ScalarBase with the suffix @p NameExt.
+  ///
+  /// @param ScalarBase The demoted scalar instruction.
+  /// @param Map        The map we should look for a mapped alloca instruction.
+  /// @param NameExt    The suffix we add to the name of a new created alloca.
+  /// @param IsNew      If set it will hold true iff the alloca was created.
+  ///
+  /// @returns The alloca for @p ScalarBase in @p Map.
+  AllocaInst *getOrCreateAlloca(Instruction *ScalarBase, ScalarAllocaMapTy &Map,
+                                const char *NameExt = ".s2a",
+                                bool *IsNew = nullptr);
+
+  /// @brief Generate reload of scalars demoted to memory and needed by @p Inst.
+  ///
+  /// @param Stmt  The statement we generate code for.
+  /// @param Inst  The instruction that might need reloaded values.
+  /// @param BBMap A mapping from old values to their new values in this block.
+  virtual void generateScalarLoads(ScopStmt &Stmt, const Instruction *Inst,
+                                   ValueMapT &BBMap);
+
+  /// @brief 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 BB    The basic block we generate code for.
+  /// @param BBMap A mapping from old values to their new values in this block.
+  /// @param GlobalMap A mapping for globally replaced values.
+  virtual void generateScalarStores(ScopStmt &Stmt, BasicBlock *BB,
+                                    ValueMapT &BBMAp, ValueMapT &GlobalMap);
+
+  /// @brief Handle users of @p Inst outside the SCoP.
+  ///
+  /// @param R        The current SCoP region.
+  /// @param Inst     The current instruction we check.
+  /// @param InstCopy The copy of the instruction @p Inst in the optimized SCoP.
+  void handleOutsideUsers(const Region &R, Instruction *Inst, Value *InstCopy);
+
+  /// @brief Initialize the memory of demoted scalars.
+  ///
+  /// If a PHI node was demoted and one of its predecessor blocks was outside
+  /// the SCoP we need to initialize the memory cell we demoted the PHI into
+  /// with the value corresponding to that predecessor. As a SCoP is a
+  /// __single__ entry region there is at most one such predecessor.
+  void createScalarInitialization(Region &R, ValueMapT &VMap);
+
+  /// @brief 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(Region &R);
+
+  /// @brief 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 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 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, const Value *Old, ValueMapT &BBMap,
+                     ValueMapT &GlobalMap, LoopToScevMapT &LTS, Loop *L) const;
+
+  void copyInstScalar(ScopStmt &Stmt, const Instruction *Inst, ValueMapT &BBMap,
+                      ValueMapT &GlobalMap, LoopToScevMapT &LTS);
+
+  /// @brief Get the innermost loop that surrounds an instruction.
+  ///
+  /// @param Inst The instruction for which we get the loop.
+  /// @return The innermost loop that surrounds the instruction.
+  Loop *getLoopForInst(const Instruction *Inst);
+
+  /// @brief Get the new operand address according to access relation of @p MA.
+  Value *getNewAccessOperand(ScopStmt &Stmt, const MemoryAccess &MA);
+
+  /// @brief Generate the operand address
+  Value *generateLocationAccessed(ScopStmt &Stmt, const Instruction *Inst,
+                                  const Value *Pointer, ValueMapT &BBMap,
+                                  ValueMapT &GlobalMap, LoopToScevMapT &LTS);
+
+  Value *generateScalarLoad(ScopStmt &Stmt, const LoadInst *load,
+                            ValueMapT &BBMap, ValueMapT &GlobalMap,
+                            LoopToScevMapT &LTS);
+
+  Value *generateScalarStore(ScopStmt &Stmt, const StoreInst *store,
+                             ValueMapT &BBMap, ValueMapT &GlobalMap,
+                             LoopToScevMapT &LTS);
+
+  /// @brief Copy a single PHI instruction.
+  ///
+  /// The implementation in the BlockGenerator is trivial, however it allows
+  /// subclasses to handle PHIs different.
+  ///
+  /// @returns The nullptr as the BlockGenerator does not copy PHIs.
+  virtual Value *copyPHIInstruction(ScopStmt &, const PHINode *, ValueMapT &,
+                                    ValueMapT &, LoopToScevMapT &) {
+    return nullptr;
+  }
+
+  /// @brief 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).
+  void copyInstruction(ScopStmt &Stmt, const Instruction *Inst,
+                       ValueMapT &BBMap, ValueMapT &GlobalMap,
+                       LoopToScevMapT &LTS);
+
+  /// @brief Helper to get the newest version of @p ScalarValue.
+  ///
+  /// @param ScalarValue The original value needed.
+  /// @param R           The current SCoP region.
+  /// @param ReloadMap   The scalar map for demoted values.
+  /// @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).
+  ///
+  /// @returns The newest version (e.g., reloaded) of the scalar value.
+  Value *getNewScalarValue(Value *ScalarValue, const Region &R,
+                           ScalarAllocaMapTy &ReloadMap, ValueMapT &BBMap,
+                           ValueMapT &GlobalMap);
+};
+
+/// @brief Generate a new vector basic block for a polyhedral statement.
+///
+/// The only public function exposed is generate().
+class VectorBlockGenerator : BlockGenerator {
+public:
+  /// @brief 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 GlobalMaps A vector of maps that define for certain Values
+  ///                   referenced from the original code new Values they should
+  ///                   be replaced with. Each map in the vector of maps is
+  ///                   used for one vector lane. The number of elements in the
+  ///                   vector defines the width of the generated vector
+  ///                   instructions.
+  /// @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 statemenet.
+  static void generate(BlockGenerator &BlockGen, ScopStmt &Stmt,
+                       VectorValueMapT &GlobalMaps,
+                       std::vector<LoopToScevMapT> &VLTS,
+                       __isl_keep isl_map *Schedule) {
+    VectorBlockGenerator Generator(BlockGen, GlobalMaps, VLTS, Schedule);
+    Generator.copyStmt(Stmt);
+  }
+
+private:
+  // This is a vector of global value 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 referenes to the old instructions with their recalculated values.
+  VectorValueMapT &GlobalMaps;
+
+  // 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 referenes 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 statemenet.
+  isl_map *Schedule;
+
+  VectorBlockGenerator(BlockGenerator &BlockGen, VectorValueMapT &GlobalMaps,
+                       std::vector<LoopToScevMapT> &VLTS,
+                       __isl_keep isl_map *Schedule);
+
+  int getVectorWidth();
+
+  Value *getVectorValue(ScopStmt &Stmt, const Value *Old, ValueMapT &VectorMap,
+                        VectorValueMapT &ScalarMaps, Loop *L);
+
+  Type *getVectorPtrTy(const Value *V, int Width);
+
+  /// @brief 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.
+  ///
+  Value *generateStrideOneLoad(ScopStmt &Stmt, const LoadInst *Load,
+                               VectorValueMapT &ScalarMaps,
+                               bool NegativeStride);
+
+  /// @brief 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 shuffeled 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
+  ///
+  Value *generateStrideZeroLoad(ScopStmt &Stmt, const LoadInst *Load,
+                                ValueMapT &BBMap);
+
+  /// @brief 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
+  ///
+  Value *generateUnknownStrideLoad(ScopStmt &Stmt, const LoadInst *Load,
+                                   VectorValueMapT &ScalarMaps);
+
+  void generateLoad(ScopStmt &Stmt, const LoadInst *Load, ValueMapT &VectorMap,
+                    VectorValueMapT &ScalarMaps);
+
+  void copyUnaryInst(ScopStmt &Stmt, const UnaryInstruction *Inst,
+                     ValueMapT &VectorMap, VectorValueMapT &ScalarMaps);
+
+  void copyBinaryInst(ScopStmt &Stmt, const BinaryOperator *Inst,
+                      ValueMapT &VectorMap, VectorValueMapT &ScalarMaps);
+
+  void copyStore(ScopStmt &Stmt, const StoreInst *Store, ValueMapT &VectorMap,
+                 VectorValueMapT &ScalarMaps);
+
+  void copyInstScalarized(ScopStmt &Stmt, const Instruction *Inst,
+                          ValueMapT &VectorMap, VectorValueMapT &ScalarMaps);
+
+  bool extractScalarValues(const Instruction *Inst, ValueMapT &VectorMap,
+                           VectorValueMapT &ScalarMaps);
+
+  bool hasVectorOperands(const Instruction *Inst, ValueMapT &VectorMap);
+
+  void copyInstruction(ScopStmt &Stmt, const Instruction *Inst,
+                       ValueMapT &VectorMap, VectorValueMapT &ScalarMaps);
+
+  void copyStmt(ScopStmt &Stmt);
+};
+
+/// @brief Generator for new versions of polyhedral region statements.
+class RegionGenerator : public BlockGenerator {
+public:
+  /// @brief Create a generator for regions.
+  ///
+  /// @param BlockGen A generator for basic blocks.
+  RegionGenerator(BlockGenerator &BlockGen) : BlockGenerator(BlockGen) {}
+
+  /// @brief 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 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 map from old loops to new induction variables as SCEVs.
+  void copyStmt(ScopStmt &Stmt, ValueMapT &GlobalMap, LoopToScevMapT &LTS);
+
+  /// @brief An empty destructor
+  virtual ~RegionGenerator(){};
+
+private:
+  /// @brief A map from old to new blocks in the region.
+  DenseMap<BasicBlock *, BasicBlock *> BlockMap;
+
+  /// @brief The "BBMaps" for the whole region (one for each block).
+  DenseMap<BasicBlock *, ValueMapT> RegionMaps;
+
+  /// @brief Mapping to remember PHI nodes that still need incoming values.
+  using PHINodePairTy = std::pair<const PHINode *, PHINode *>;
+  DenseMap<BasicBlock *, SmallVector<PHINodePairTy, 4>> IncompletePHINodeMap;
+
+  /// @brief 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);
+
+  /// @brief Add the new operand from the copy of @p IncomingBB to @p PHICopy.
+  ///
+  /// @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 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 map from old loops to new induction variables as
+  /// SCEVs.
+  void addOperandToPHI(ScopStmt &Stmt, const PHINode *PHI, PHINode *PHICopy,
+                       BasicBlock *IncomingBB, ValueMapT &GlobalMap,
+                       LoopToScevMapT &LTS);
+
+  /// @brief Generate reload of scalars demoted to memory and needed by @p Inst.
+  ///
+  /// @param Stmt  The statement we generate code for.
+  /// @param Inst  The instruction that might need reloaded values.
+  /// @param BBMap A mapping from old values to their new values in this block.
+  virtual void generateScalarLoads(ScopStmt &Stmt, const Instruction *Inst,
+                                   ValueMapT &BBMap) override;
+
+  /// @brief 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 BB    The basic block we generate code for.
+  /// @param BBMap A mapping from old values to their new values in this 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).
+  virtual void generateScalarStores(ScopStmt &Stmt, BasicBlock *BB,
+                                    ValueMapT &BBMAp,
+                                    ValueMapT &GlobalMap) override;
+
+  /// @brief 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 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 map from old loops to new induction variables as SCEVs.
+  ///
+  /// @returns The copied instruction or nullptr if no copy was made.
+  virtual Value *copyPHIInstruction(ScopStmt &Stmt, const PHINode *Inst,
+                                    ValueMapT &BBMap, ValueMapT &GlobalMap,
+                                    LoopToScevMapT &LTS) override;
+};
+}
+#endif
diff --git a/final/include/polly/CodeGen/CodeGeneration.h b/final/include/polly/CodeGen/CodeGeneration.h
new file mode 100644
index 0000000..03dc869
--- /dev/null
+++ b/final/include/polly/CodeGen/CodeGeneration.h
@@ -0,0 +1,28 @@
+//===------ 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 "polly/Config/config.h"
+#include "isl/map.h"
+#include "isl/set.h"
+
+namespace polly {
+enum VectorizerChoice {
+  VECTORIZER_NONE,
+  VECTORIZER_STRIPMINE,
+  VECTORIZER_POLLY,
+};
+extern VectorizerChoice PollyVectorizerChoice;
+}
+
+#endif // POLLY_CODEGENERATION_H
diff --git a/final/include/polly/CodeGen/IRBuilder.h b/final/include/polly/CodeGen/IRBuilder.h
new file mode 100644
index 0000000..b4873e3
--- /dev/null
+++ b/final/include/polly/CodeGen/IRBuilder.h
@@ -0,0 +1,123 @@
+//===- 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/Analysis/LoopInfo.h"
+#include "llvm/IR/IRBuilder.h"
+
+namespace llvm {
+class ScalarEvolution;
+}
+
+namespace polly {
+class Scop;
+
+/// @brief 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();
+
+  /// @brief Build all alias scopes for the given SCoP.
+  void buildAliasScopes(Scop &S);
+
+  /// @brief Add a new loop @p L which is parallel if @p IsParallel is true.
+  void pushLoop(llvm::Loop *L, bool IsParallel);
+
+  /// @brief Remove the last added loop.
+  void popLoop(bool isParallel);
+
+  /// @brief Annotate the new instruction @p I for all parallel loops.
+  void annotate(llvm::Instruction *I);
+
+  /// @brief Annotate the loop latch @p B wrt. @p L.
+  void annotateLoopLatch(llvm::BranchInst *B, llvm::Loop *L,
+                         bool IsParallel) const;
+
+private:
+  /// @brief The ScalarEvolution analysis we use to find base pointers.
+  llvm::ScalarEvolution *SE;
+
+  /// @brief All loops currently under construction.
+  llvm::SmallVector<llvm::Loop *, 8> ActiveLoops;
+
+  /// @brief Metadata pointing to parallel loops currently under construction.
+  llvm::SmallVector<llvm::MDNode *, 8> ParallelLoops;
+
+  /// @brief The alias scope domain for the current SCoP.
+  llvm::MDNode *AliasScopeDomain;
+
+  /// @brief A map from base pointers to its alias scope.
+  llvm::DenseMap<llvm::Value *, llvm::MDNode *> AliasScopeMap;
+
+  /// @brief A map from base pointers to an alias scope list of other pointers.
+  llvm::DenseMap<llvm::Value *, llvm::MDNode *> OtherAliasScopeListMap;
+};
+
+/// @brief Add Polly specifics when running IRBuilder.
+///
+/// This is used to add additional items such as e.g. the llvm.loop.parallel
+/// metadata.
+template <bool PreserveNames>
+class PollyBuilderInserter
+    : protected llvm::IRBuilderDefaultInserter<PreserveNames> {
+public:
+  PollyBuilderInserter() : Annotator(0) {}
+  PollyBuilderInserter(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<PreserveNames>::InsertHelper(I, Name, BB,
+                                                                InsertPt);
+    if (Annotator)
+      Annotator->annotate(I);
+  }
+
+private:
+  class ScopAnnotator *Annotator;
+};
+
+// 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 PollyBuilderInserter<true> IRInserter;
+typedef llvm::IRBuilder<true, llvm::ConstantFolder, IRInserter> PollyIRBuilder;
+
+/// @brief 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;
+}
+}
+#endif
diff --git a/final/include/polly/CodeGen/IslAst.h b/final/include/polly/CodeGen/IslAst.h
new file mode 100644
index 0000000..4d68569
--- /dev/null
+++ b/final/include/polly/CodeGen/IslAst.h
@@ -0,0 +1,156 @@
+//===- 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_ISL_AST_H
+#define POLLY_ISL_AST_H
+
+#include "polly/Config/config.h"
+#include "polly/ScopPass.h"
+#include "isl/ast.h"
+
+namespace llvm {
+class raw_ostream;
+}
+
+struct isl_pw_aff;
+struct isl_ast_node;
+struct isl_ast_expr;
+struct isl_ast_build;
+struct isl_union_map;
+struct isl_pw_multi_aff;
+
+namespace polly {
+class Scop;
+class IslAst;
+class MemoryAccess;
+
+class IslAstInfo : public ScopPass {
+public:
+  using MemoryAccessSet = SmallPtrSet<MemoryAccess *, 4>;
+
+  /// @brief Payload information used to annotate an AST node.
+  struct IslAstUserPayload {
+    /// @brief Construct and initialize the payload.
+    IslAstUserPayload()
+        : IsInnermost(false), IsInnermostParallel(false),
+          IsOutermostParallel(false), IsReductionParallel(false),
+          MinimalDependenceDistance(nullptr), Build(nullptr) {}
+
+    /// @brief Cleanup all isl structs on destruction.
+    ~IslAstUserPayload();
+
+    /// @brief Flag to mark innermost loops.
+    bool IsInnermost;
+
+    /// @brief Flag to mark innermost parallel loops.
+    bool IsInnermostParallel;
+
+    /// @brief Flag to mark outermost parallel loops.
+    bool IsOutermostParallel;
+
+    /// @brief Flag to mark parallel loops which break reductions.
+    bool IsReductionParallel;
+
+    /// @brief The minimal dependence distance for non parallel loops.
+    isl_pw_aff *MinimalDependenceDistance;
+
+    /// @brief The build environment at the time this node was constructed.
+    isl_ast_build *Build;
+
+    /// @brief Set of accesses which break reduction dependences.
+    MemoryAccessSet BrokenReductions;
+  };
+
+private:
+  Scop *S;
+  IslAst *Ast;
+
+public:
+  static char ID;
+  IslAstInfo() : ScopPass(ID), S(nullptr), Ast(nullptr) {}
+
+  /// @brief Build the AST for the given SCoP @p S.
+  bool runOnScop(Scop &S);
+
+  /// @brief Print a source code representation of the program.
+  void printScop(llvm::raw_ostream &OS, Scop &S) const;
+
+  /// @brief Return a copy of the AST root node.
+  __isl_give isl_ast_node *getAst() const;
+
+  /// @brief 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() const;
+
+  /// @name Extract information attached to an isl ast (for) node.
+  ///
+  ///{
+
+  /// @brief Get the complete payload attached to @p Node.
+  static IslAstUserPayload *getNodePayload(__isl_keep isl_ast_node *Node);
+
+  /// @brief Is this loop an innermost loop?
+  static bool isInnermost(__isl_keep isl_ast_node *Node);
+
+  /// @brief Is this loop a parallel loop?
+  static bool isParallel(__isl_keep isl_ast_node *Node);
+
+  /// @brief Is this loop an outermost parallel loop?
+  static bool isOutermostParallel(__isl_keep isl_ast_node *Node);
+
+  /// @brief Is this loop an innermost parallel loop?
+  static bool isInnermostParallel(__isl_keep isl_ast_node *Node);
+
+  /// @brief Is this loop a reduction parallel loop?
+  static bool isReductionParallel(__isl_keep isl_ast_node *Node);
+
+  /// @brief Will the loop be run as thread parallel?
+  static bool isExecutedInParallel(__isl_keep isl_ast_node *Node);
+
+  /// @brief Get the nodes schedule or a nullptr if not available.
+  static __isl_give isl_union_map *getSchedule(__isl_keep isl_ast_node *Node);
+
+  /// @brief Get minimal dependence distance or nullptr if not available.
+  static __isl_give isl_pw_aff *
+  getMinimalDependenceDistance(__isl_keep isl_ast_node *Node);
+
+  /// @brief Get the nodes broken reductions or a nullptr if not available.
+  static MemoryAccessSet *getBrokenReductions(__isl_keep isl_ast_node *Node);
+
+  /// @brief Get the nodes build context or a nullptr if not available.
+  static __isl_give isl_ast_build *getBuild(__isl_keep isl_ast_node *Node);
+
+  ///}
+
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
+  virtual void releaseMemory();
+};
+}
+
+namespace llvm {
+class PassRegistry;
+void initializeIslAstInfoPass(llvm::PassRegistry &);
+}
+#endif /* POLLY_ISL_AST_H */
diff --git a/final/include/polly/CodeGen/IslExprBuilder.h b/final/include/polly/CodeGen/IslExprBuilder.h
new file mode 100644
index 0000000..24fa4e4
--- /dev/null
+++ b/final/include/polly/CodeGen/IslExprBuilder.h
@@ -0,0 +1,152 @@
+//===-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 "llvm/ADT/MapVector.h"
+#include "isl/ast.h"
+
+namespace llvm {
+class SCEVExpander;
+}
+
+namespace polly {
+
+/// @brief 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.
+///
+/// FIXME: Hardcoding sizes can cause issues:
+///
+///   a) Certain run-time checks that we may want to generate can involve the
+///      size of the data types the computation is performed on. When code
+///      generating these run-time checks to isl_ast_expr[essions], the
+///      resulting computation may require more than 64 bit.
+///
+///   b) 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.
+///
+/// 2) We always flag computations with 'nsw'
+///
+/// As isl_ast_expr[essions] assume arbitrary precision, no wrapping should
+/// ever occur in the generated LLVM-IR (assuming the data type chosen is large
+/// enough).
+class IslExprBuilder {
+public:
+  /// @brief A map from isl_ids to llvm::Values.
+  typedef llvm::MapVector<isl_id *, llvm::Value *> IDToValueTy;
+
+  /// @brief 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 Expander  A SCEVExpander to create the indices for multi
+  ///                  dimensional accesses.
+  IslExprBuilder(PollyIRBuilder &Builder, IDToValueTy &IDToValue,
+                 llvm::SCEVExpander &Expander, llvm::DominatorTree &DT,
+                 llvm::LoopInfo &LI)
+      : Builder(Builder), IDToValue(IDToValue), Expander(Expander), DT(DT),
+        LI(LI) {}
+
+  /// @brief 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);
+
+  /// @brief 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);
+
+  /// @brief 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);
+
+private:
+  PollyIRBuilder &Builder;
+  IDToValueTy &IDToValue;
+
+  /// @brief A SCEVExpander to translate dimension sizes to llvm values.
+  llvm::SCEVExpander &Expander;
+
+  llvm::DominatorTree &DT;
+  llvm::LoopInfo &LI;
+
+  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);
+  llvm::Value *createAccessAddress(__isl_take isl_ast_expr *Expr);
+};
+}
+
+#endif
diff --git a/final/include/polly/CodeGen/IslNodeBuilder.h b/final/include/polly/CodeGen/IslNodeBuilder.h
new file mode 100644
index 0000000..9987dd1
--- /dev/null
+++ b/final/include/polly/CodeGen/IslNodeBuilder.h
@@ -0,0 +1,236 @@
+//===------ 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.
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_ISL_NODE_BUILDER_H
+#define POLLY_ISL_NODE_BUILDER_H
+
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/CodeGen/IslExprBuilder.h"
+#include "polly/CodeGen/LoopGenerators.h"
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
+#include "isl/ctx.h"
+#include "isl/union_map.h"
+
+using namespace polly;
+using namespace llvm;
+
+struct isl_ast_node;
+
+class IslNodeBuilder {
+public:
+  IslNodeBuilder(PollyIRBuilder &Builder, ScopAnnotator &Annotator, Pass *P,
+                 const DataLayout &DL, LoopInfo &LI, ScalarEvolution &SE,
+                 DominatorTree &DT, Scop &S)
+      : S(S), Builder(Builder), Annotator(Annotator), Rewriter(SE, DL, "polly"),
+        ExprBuilder(Builder, IDToValue, Rewriter, DT, LI),
+        BlockGen(Builder, LI, SE, DT, ScalarMap, PHIOpMap, EscapeMap,
+                 &ExprBuilder),
+        RegionGen(BlockGen), P(P), DL(DL), LI(LI), SE(SE), DT(DT) {}
+
+  ~IslNodeBuilder() {}
+
+  void addParameters(__isl_take isl_set *Context);
+  void create(__isl_take isl_ast_node *Node);
+
+  /// @brief Finalize code generation for the SCoP @p S.
+  ///
+  /// @see BlockGenerator::finalizeSCoP(Scop &S)
+  void finalizeSCoP(Scop &S) { BlockGen.finalizeSCoP(S, ValueMap); }
+
+  IslExprBuilder &getExprBuilder() { return ExprBuilder; }
+
+private:
+  Scop &S;
+  PollyIRBuilder &Builder;
+  ScopAnnotator &Annotator;
+
+  /// @brief A SCEVExpander to create llvm values from SCEVs.
+  SCEVExpander Rewriter;
+
+  IslExprBuilder ExprBuilder;
+
+  /// @brief Maps used by the block and region generator to demote scalars.
+  ///
+  ///@{
+
+  /// @brief See BlockGenerator::ScalarMap.
+  BlockGenerator::ScalarAllocaMapTy ScalarMap;
+
+  /// @brief See BlockGenerator::PhiOpMap.
+  BlockGenerator::ScalarAllocaMapTy PHIOpMap;
+
+  /// @brief See BlockGenerator::EscapeMap.
+  BlockGenerator::EscapeUsersAllocaMapTy EscapeMap;
+
+  ///@}
+
+  /// @brief The generator used to copy a basic block.
+  BlockGenerator BlockGen;
+
+  /// @brief The generator used to copy a non-affine region.
+  RegionGenerator RegionGen;
+
+  Pass *const P;
+  const DataLayout &DL;
+  LoopInfo &LI;
+  ScalarEvolution &SE;
+  DominatorTree &DT;
+
+  /// @brief 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;
+
+  /// Generate code for a given SCEV*
+  ///
+  /// This function generates code for a given SCEV expression. It generated
+  /// code is emmitted 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.
+  llvm::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.
+  polly::ValueMapT ValueMap;
+
+  // 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 invarient 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);
+
+  unsigned 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(ParallelLoopGenerator::ValueToValueMapTy &NewValues);
+
+  void createFor(__isl_take isl_ast_node *For);
+  void createForVector(__isl_take isl_ast_node *For, int VectorWidth);
+  void createForSequential(__isl_take isl_ast_node *For);
+
+  /// 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);
+
+  /// 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 VMap The value map into which the mapping from the old induction
+  ///             variable to the new one is inserted. This mapping is used
+  ///             for the classical code generation (not scev-based) and
+  ///             gives an explicit mapping from an original, materialized
+  ///             induction variable. It consequently can only be expressed
+  ///             if there was an explicit induction variable.
+  /// @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,
+                           ValueMapT &VMap, LoopToScevMapT &LTS);
+  void createSubstitutionsVector(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt,
+                                 VectorValueMapT &VMap,
+                                 std::vector<LoopToScevMapT> &VLTS,
+                                 std::vector<Value *> &IVS,
+                                 __isl_take isl_id *IteratorID);
+  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);
+  void createUser(__isl_take isl_ast_node *User);
+  void createBlock(__isl_take isl_ast_node *Block);
+};
+
+#endif
diff --git a/final/include/polly/CodeGen/LoopGenerators.h b/final/include/polly/CodeGen/LoopGenerators.h
new file mode 100644
index 0000000..f9e57b2
--- /dev/null
+++ b/final/include/polly/CodeGen/LoopGenerators.h
@@ -0,0 +1,213 @@
+//===- 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 "llvm/ADT/SetVector.h"
+#include "llvm/IR/ValueMap.h"
+
+namespace llvm {
+class Value;
+class Pass;
+class BasicBlock;
+}
+
+namespace polly {
+using namespace llvm;
+
+/// @brief 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.
+///
+/// @return Value*    The newly created induction variable for this loop.
+Value *createLoop(Value *LowerBound, Value *UpperBound, Value *Stride,
+                  PollyIRBuilder &Builder, Pass *P, LoopInfo &LI,
+                  DominatorTree &DT, BasicBlock *&ExitBlock,
+                  ICmpInst::Predicate Predicate,
+                  ScopAnnotator *Annotator = NULL, bool Parallel = false,
+                  bool UseGuard = true);
+
+/// @brief 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:
+  using ValueToValueMapTy = llvm::ValueMap<Value *, Value *>;
+
+  /// @brief Create a parallel loop generator for the current function.
+  ParallelLoopGenerator(PollyIRBuilder &Builder, Pass *P, LoopInfo &LI,
+                        DominatorTree &DT, const DataLayout &DL)
+      : Builder(Builder), P(P), LI(LI), DT(DT), DL(DL),
+        LongType(
+            Type::getIntNTy(Builder.getContext(), DL.getPointerSizeInBits())),
+        M(Builder.GetInsertBlock()->getParent()->getParent()) {}
+
+  /// @brief Create a parallel loop
+  ///
+  ///
+  /// @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, ValueToValueMapTy &VMap,
+                            BasicBlock::iterator *LoopBody);
+
+private:
+  /// @brief The IR builder we use to create instructions.
+  PollyIRBuilder &Builder;
+
+  /// @brief A pass pointer to update analysis information.
+  Pass *P;
+
+  /// @brief The loop info of the current function we need to update.
+  LoopInfo &LI;
+
+  /// @brief The dominance tree of the current function we need to update.
+  DominatorTree &DT;
+
+  /// @brief The target layout to get the right size for types.
+  const DataLayout &DL;
+
+  /// @brief The type of a "long" on this hardware used for backend calls.
+  Type *LongType;
+
+  /// @brief The current module
+  Module *M;
+
+  /// @brief 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);
+
+  /// @brief Create a runtime library call to join the worker threads.
+  void createCallJoinThreads();
+
+  /// @brief 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);
+
+  /// @brief 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 depends on it.
+  void createCallCleanupThread();
+
+  /// @brief 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);
+
+  /// @brief 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, ValueToValueMapTy &VMap);
+
+  /// @brief Create the definition of the parallel subfunction.
+  Function *createSubFnDefinition();
+
+  /// @brief 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, ValueToValueMapTy &VMap,
+                     Function **SubFn);
+};
+} // end 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..a22416f
--- /dev/null
+++ b/final/include/polly/CodeGen/RuntimeDebugBuilder.h
@@ -0,0 +1,136 @@
+//===--- 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 polly {
+
+/// @brief 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 {
+
+  /// @brief Print a string to stdout.
+  ///
+  /// @param String The string to print.
+  static void createStrPrinter(PollyIRBuilder &Builder,
+                               const std::string &String);
+
+  /// @brief Print a value to stdout.
+  ///
+  /// @param V The value to print.
+  ///
+  /// @note Only integer, floating point and pointer values up to 64bit are
+  ///       supported.
+  static void createValuePrinter(PollyIRBuilder &Builder, llvm::Value *V);
+
+  /// @brief Add a call to the fflush function with no file pointer given.
+  ///
+  /// This call will flush all opened file pointers including stdout and stderr.
+  static void createFlush(PollyIRBuilder &Builder);
+
+  /// @brief 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);
+
+  /// @brief 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;
+    createGPUVAPrinter(Builder, Vector, args...);
+  }
+
+private:
+  /// @brief GPU printing - Print a list of LLVM Values.
+  ///
+  static void createGPUVAPrinter(PollyIRBuilder &Builder,
+                                 llvm::ArrayRef<llvm::Value *> Values);
+
+  /// @brief GPU printing - Handle Values.
+  template <typename... Args>
+  static void createGPUVAPrinter(PollyIRBuilder &Builder,
+                                 std::vector<llvm::Value *> &Values,
+                                 llvm::Value *Value, Args... args) {
+    Values.push_back(Value);
+    createGPUVAPrinter(Builder, Values, args...);
+  }
+
+  /// @brief GPU printing - Handle StringRefs.
+  template <typename... Args>
+  static void createGPUVAPrinter(PollyIRBuilder &Builder,
+                                 std::vector<llvm::Value *> &Values,
+                                 llvm::StringRef String, Args... args) {
+    Values.push_back(Builder.CreateGlobalStringPtr(String, "", 4));
+    createGPUVAPrinter(Builder, Values, args...);
+  }
+
+  /// @brief GPU printing - Handle ArrayRefs.
+  template <typename... Args>
+  static void createGPUVAPrinter(PollyIRBuilder &Builder,
+                                 std::vector<llvm::Value *> &Values,
+                                 llvm::ArrayRef<llvm::Value *> Array,
+                                 Args... args) {
+    if (Array.size() >= 2)
+      createGPUVAPrinter(
+          Builder, Values, Array[0], " ",
+          llvm::ArrayRef<llvm::Value *>(&Array[1], Array.size() - 1), args...);
+    else if (Array.size() == 1)
+      createGPUVAPrinter(Builder, Values, Array[0], args...);
+    else
+      createGPUVAPrinter(Builder, Values, args...);
+  }
+
+  /// @brief Get (and possibly insert) a vprintf declaration into the module.
+  static llvm::Function *getVPrintF(PollyIRBuilder &Builder);
+
+  /// @brief 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);
+
+  /// @brief 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);
+};
+}
+
+#endif
diff --git a/final/include/polly/CodeGen/Utils.h b/final/include/polly/CodeGen/Utils.h
new file mode 100644
index 0000000..0752aa3
--- /dev/null
+++ b/final/include/polly/CodeGen/Utils.h
@@ -0,0 +1,61 @@
+//===- 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
+
+namespace llvm {
+class Pass;
+class Value;
+class BasicBlock;
+}
+
+namespace polly {
+
+class Scop;
+
+/// @brief 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 The 'StartBlock' to which new code can be added.
+llvm::BasicBlock *executeScopConditionally(Scop &S, llvm::Pass *P,
+                                           llvm::Value *RTC);
+}
+#endif
diff --git a/final/include/polly/Config/config.h.cmake b/final/include/polly/Config/config.h.cmake
new file mode 100644
index 0000000..4abf8b9
--- /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 CUDALIB_FOUND
+#cmakedefine GPU_CODEGEN
+
+#endif
diff --git a/final/include/polly/Config/config.h.in b/final/include/polly/Config/config.h.in
new file mode 100644
index 0000000..c7fc18f
--- /dev/null
+++ b/final/include/polly/Config/config.h.in
@@ -0,0 +1,25 @@
+/* include/polly/Config/config.h.in.  Generated from autoconf/configure.ac by autoheader.  */
+
+/* Define if cudalib found */
+#undef CUDALIB_FOUND
+
+/* Define if gpu codegen is enabled */
+#undef GPU_CODEGEN
+
+/* 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
diff --git a/final/include/polly/DependenceInfo.h b/final/include/polly/DependenceInfo.h
new file mode 100644
index 0000000..25bb7d4
--- /dev/null
+++ b/final/include/polly/DependenceInfo.h
@@ -0,0 +1,210 @@
+//===--- 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 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.
+//
+//===----------------------------------------------------------------------===//
+
+#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;
+
+/// @brief 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 {
+
+  /// @brief Map type for reduction dependences.
+  using ReductionDependencesMapTy = DenseMap<MemoryAccess *, isl_map *>;
+
+  /// @brief Map type to associate statements with schedules.
+  using StatementToIslMapTy = DenseMap<ScopStmt *, isl_map *>;
+
+  /// @brief The type of the dependences.
+  ///
+  /// Reduction dependences are separated from RAW/WAW/WAR dependences because
+  /// we can ignore them during the scheduling. This is the case since 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 therefor
+  /// 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,
+  };
+
+  /// @brief 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;
+
+  /// @brief Report if valid dependences are available.
+  bool hasValidDependences() const;
+
+  /// @brief 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;
+
+  /// @brief Return all reduction dependences.
+  const ReductionDependencesMapTy &getReductionDependences() const {
+    return ReductionDependences;
+  }
+
+  /// @brief 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;
+
+  /// @brief Check if a new schedule is valid.
+  ///
+  /// @param S             The current SCoP.
+  /// @param NewSchedules  The new schedules
+  ///
+  /// @return bool True if the new schedule is valid, false it it reverses
+  ///              dependences.
+  bool isValidSchedule(Scop &S, StatementToIslMapTy *NewSchedules) const;
+
+  /// @brief Print the dependence information stored.
+  void print(llvm::raw_ostream &OS) const;
+
+  /// @brief Dump the dependence information stored to the dbgs stream.
+  void dump() const;
+
+  /// @brief Allow the DependenceInfo access to private members and methods.
+  ///
+  /// To restict access to the internal state only the DependenceInfo class
+  /// is able to call or modify a dependences struct.
+  friend class DependenceInfo;
+
+private:
+  /// @brief Create an empty dependences struct.
+  Dependences()
+      : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr),
+        TC_RED(nullptr) {}
+
+  /// @brief Destructor that will free internal objects.
+  ~Dependences() { releaseMemory(); }
+
+  /// @brief Calculate and add at the privatization dependences.
+  void addPrivatizationDependences();
+
+  /// @brief Calculate the dependences for a certain SCoP @p S.
+  void calculateDependences(Scop &S);
+
+  /// @brief Set the reduction dependences for @p MA to @p Deps.
+  void setReductionDependences(MemoryAccess *MA, __isl_take isl_map *Deps);
+
+  /// @brief Free the objects associated with this dependences struct.
+  ///
+  /// The dependences struct will again be "empty" afterwards.
+  void releaseMemory();
+
+  /// @brief The different basic kinds of dependences we calculate.
+  isl_union_map *RAW;
+  isl_union_map *WAR;
+  isl_union_map *WAW;
+
+  /// @brief The special reduction dependences.
+  isl_union_map *RED;
+
+  /// @brief The (reverse) transitive closure of reduction dependences.
+  isl_union_map *TC_RED;
+
+  /// @brief Mapping from memory accesses to their reduction dependences.
+  ReductionDependencesMapTy ReductionDependences;
+};
+
+class DependenceInfo : public ScopPass {
+public:
+  static char ID;
+
+  /// @brief Construct a new DependenceInfo pass.
+  DependenceInfo() : ScopPass(ID) {}
+
+  /// @brief Return the dependence information for the current SCoP.
+  const Dependences &getDependences() { return D; }
+
+  /// @brief Recompute dependences from schedule and memory accesses.
+  void recomputeDependences();
+
+  bool runOnScop(Scop &S) override;
+  void printScop(raw_ostream &OS, Scop &) const override { D.print(OS); }
+  void releaseMemory() override { D.releaseMemory(); }
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  Scop *S;
+
+  /// @brief Dependences struct for the current SCoP.
+  Dependences D;
+};
+
+} // End polly namespace.
+
+namespace llvm {
+class PassRegistry;
+void initializeDependenceInfoPass(llvm::PassRegistry &);
+}
+
+#endif
diff --git a/final/include/polly/LinkAllPasses.h b/final/include/polly/LinkAllPasses.h
new file mode 100644
index 0000000..f60275e
--- /dev/null
+++ b/final/include/polly/LinkAllPasses.h
@@ -0,0 +1,95 @@
+//===- 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/Config/config.h"
+#include <cstdlib>
+
+namespace llvm {
+class Pass;
+class PassInfo;
+class PassRegistry;
+class RegionPass;
+}
+
+namespace polly {
+llvm::Pass *createCodePreparationPass();
+llvm::Pass *createDeadCodeElimPass();
+llvm::Pass *createDependenceInfoPass();
+llvm::Pass *createDOTOnlyPrinterPass();
+llvm::Pass *createDOTOnlyViewerPass();
+llvm::Pass *createDOTPrinterPass();
+llvm::Pass *createDOTViewerPass();
+llvm::Pass *createIndependentBlocksPass();
+llvm::Pass *createJSONExporterPass();
+llvm::Pass *createJSONImporterPass();
+llvm::Pass *createPollyCanonicalizePass();
+llvm::Pass *createScopDetectionPass();
+llvm::Pass *createScopInfoPass();
+llvm::Pass *createIslAstInfoPass();
+llvm::Pass *createCodeGenerationPass();
+llvm::Pass *createIslScheduleOptimizerPass();
+llvm::Pass *createTempScopInfoPass();
+
+extern char &IndependentBlocksID;
+extern char &CodePreparationID;
+}
+
+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::createIndependentBlocksPass();
+    polly::createJSONExporterPass();
+    polly::createJSONImporterPass();
+    polly::createScopDetectionPass();
+    polly::createScopInfoPass();
+    polly::createPollyCanonicalizePass();
+    polly::createIslAstInfoPass();
+    polly::createCodeGenerationPass();
+    polly::createIslScheduleOptimizerPass();
+    polly::createTempScopInfoPass();
+  }
+} PollyForcePassLinking; // Force link by creating a global definition.
+}
+
+namespace llvm {
+class PassRegistry;
+void initializeCodePreparationPass(llvm::PassRegistry &);
+void initializeDeadCodeElimPass(llvm::PassRegistry &);
+void initializeIndependentBlocksPass(llvm::PassRegistry &);
+void initializeJSONExporterPass(llvm::PassRegistry &);
+void initializeJSONImporterPass(llvm::PassRegistry &);
+void initializeIslAstInfoPass(llvm::PassRegistry &);
+void initializeCodeGenerationPass(llvm::PassRegistry &);
+void initializeIslScheduleOptimizerPass(llvm::PassRegistry &);
+void initializePollyCanonicalizePass(llvm::PassRegistry &);
+}
+
+#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/RegisterPasses.h b/final/include/polly/RegisterPasses.h
new file mode 100644
index 0000000..38aca82
--- /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 polly {
+void initializePollyPasses(llvm::PassRegistry &Registry);
+void registerPollyPasses(llvm::legacy::PassManagerBase &PM);
+}
+#endif
diff --git a/final/include/polly/ScheduleOptimizer.h b/final/include/polly/ScheduleOptimizer.h
new file mode 100644
index 0000000..80272d2
--- /dev/null
+++ b/final/include/polly/ScheduleOptimizer.h
@@ -0,0 +1,19 @@
+//===------ 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_SCHEDULE_OPTIMIZER_H
+#define POLLY_SCHEDULE_OPTIMIZER_H
+
+namespace polly {
+extern bool DisablePollyTiling;
+}
+
+#endif
diff --git a/final/include/polly/ScopDetection.h b/final/include/polly/ScopDetection.h
new file mode 100644
index 0000000..2b374cc
--- /dev/null
+++ b/final/include/polly/ScopDetection.h
@@ -0,0 +1,425 @@
+//===--- 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 fullfills 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_SCOP_DETECTION_H
+#define POLLY_SCOP_DETECTION_H
+
+#include "polly/ScopDetectionDiagnostic.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/Analysis/AliasSetTracker.h"
+#include "llvm/Pass.h"
+#include <map>
+#include <memory>
+#include <set>
+
+using namespace llvm;
+
+namespace llvm {
+class RegionInfo;
+class Region;
+class LoopInfo;
+class Loop;
+class ScalarEvolution;
+class SCEV;
+class SCEVAddRecExpr;
+class SCEVUnknown;
+class CallInst;
+class Instruction;
+class AliasAnalysis;
+class Value;
+}
+
+namespace polly {
+typedef std::set<const SCEV *> ParamSetType;
+
+// 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), DelinearizedSizes() {}
+};
+
+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), DelinearizedSubscripts() {}
+};
+
+typedef std::map<const Instruction *, MemAcc> MapInsnToMemAcc;
+typedef std::pair<const Instruction *, const SCEV *> PairInstSCEV;
+typedef std::vector<PairInstSCEV> AFs;
+typedef std::map<const SCEVUnknown *, AFs> BaseToAFs;
+typedef std::map<const SCEVUnknown *, const SCEV *> BaseToElSize;
+
+extern bool PollyTrackFailures;
+extern bool PollyDelinearize;
+extern bool PollyUseRuntimeAliasChecks;
+
+/// @brief A function attribute which will cause Polly to skip the function
+extern llvm::StringRef PollySkipFnAttr;
+
+//===----------------------------------------------------------------------===//
+/// @brief Pass to detect the maximal static control parts (Scops) of a
+/// function.
+class ScopDetection : public FunctionPass {
+public:
+  typedef SetVector<const Region *> RegionSet;
+
+  /// @brief Set of loops (used to remember loops in non-affine subregions).
+  using BoxedLoopsSetTy = SetVector<const Loop *>;
+
+private:
+  //===--------------------------------------------------------------------===//
+  ScopDetection(const ScopDetection &) = delete;
+  const ScopDetection &operator=(const ScopDetection &) = delete;
+
+  /// @brief Analysis passes used.
+  //@{
+  ScalarEvolution *SE;
+  LoopInfo *LI;
+  RegionInfo *RI;
+  AliasAnalysis *AA;
+  //@}
+
+  /// @brief Set to remember non-affine branches in regions.
+  using NonAffineSubRegionSetTy = RegionSet;
+  using NonAffineSubRegionMapTy =
+      DenseMap<const Region *, NonAffineSubRegionSetTy>;
+  NonAffineSubRegionMapTy NonAffineSubRegionMap;
+
+  /// @brief Map to remeber loops in non-affine regions.
+  using BoxedLoopsMapTy = DenseMap<const Region *, BoxedLoopsSetTy>;
+  BoxedLoopsMapTy BoxedLoopsMap;
+
+  /// @brief 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?
+    RejectLog Log;
+
+    /// @brief 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;
+
+    /// @brief The set of base pointers with non-affine accesses.
+    ///
+    /// This set contains all base pointers which are used in memory accesses
+    /// that can not be detected as affine accesses.
+    SetVector<const SCEVUnknown *> NonAffineAccesses;
+    BaseToElSize ElementSize;
+
+    /// @brief The region has at least one load instruction.
+    bool hasLoads;
+
+    /// @brief The region has at least one store instruction.
+    bool hasStores;
+
+    /// @brief The region has at least one loop that is not overapproximated.
+    bool hasAffineLoops;
+
+    /// @brief The set of non-affine subregions in the region we analyze.
+    NonAffineSubRegionSetTy &NonAffineSubRegionSet;
+
+    /// @brief The set of loops contained in non-affine regions.
+    BoxedLoopsSetTy &BoxedLoopsSet;
+
+    DetectionContext(Region &R, AliasAnalysis &AA,
+                     NonAffineSubRegionSetTy &NASRS, BoxedLoopsSetTy &BLS,
+                     bool Verify)
+        : CurRegion(R), AST(AA), Verifying(Verify), Log(&R), hasLoads(false),
+          hasStores(false), hasAffineLoops(false), NonAffineSubRegionSet(NASRS),
+          BoxedLoopsSet(BLS) {}
+  };
+
+  // Remember the valid regions
+  RegionSet ValidRegions;
+
+  // Remember a list of errors for every region.
+  mutable RejectLogsContainer RejectLogs;
+
+  /// @brief 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;
+
+  // 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);
+
+  /// @brief 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;
+
+  /// @brief Check the exit block of a region is valid.
+  ///
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if the exit of R is valid, false otherwise.
+  bool isValidExit(DetectionContext &Context) const;
+
+  /// @brief 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;
+
+  /// @brief Check if a call instruction can be part of a Scop.
+  ///
+  /// @param CI The call instruction to check.
+  /// @return True if the call instruction is valid, false otherwise.
+  static bool isValidCallInst(CallInst &CI);
+
+  /// @brief 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.
+  ///
+  /// @return True if the value represented by Val is invariant in the region
+  ///         identified by Reg.
+  bool isInvariant(const Value &Val, const Region &Reg) const;
+
+  /// @brief 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(Instruction &Inst, DetectionContext &Context) const;
+
+  /// @brief 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;
+
+  /// @brief 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;
+
+  /// @brief Check if the control flow in a basic block is valid.
+  ///
+  /// @param BB The BB to check the control flow.
+  /// @param Context The context of scop detection.
+  ///
+  /// @return True if the BB contains only valid control flow.
+  bool isValidCFG(BasicBlock &BB, DetectionContext &Context) const;
+
+  /// @brief 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;
+
+  /// @brief Check if the function @p F is marked as invalid.
+  ///
+  /// @note An OpenMP subfunction will be marked as invalid.
+  bool isValidFunction(llvm::Function &F);
+
+  /// @brief Print the locations of all detected scops.
+  void printLocations(llvm::Function &F);
+
+  /// @brief 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:
+  static char ID;
+  explicit ScopDetection();
+
+  /// @brief 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; }
+
+  /// @brief 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;
+
+  /// @brief Return the set of loops in non-affine subregions for @p R.
+  const BoxedLoopsSetTy *getBoxedLoops(const Region *R) const;
+
+  /// @brief Return true if @p SubR is a non-affine subregion in @p ScopR.
+  bool isNonAffineSubRegion(const Region *SubR, const Region *ScopR) const;
+
+  /// @brief 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.
+  //@{
+  typedef RegionSet::iterator iterator;
+  typedef RegionSet::const_iterator 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(); }
+  //@}
+
+  /// @name Reject log iterators
+  ///
+  /// These iterators iterate over the logs of all rejected regions of this
+  //  function.
+  //@{
+  typedef std::map<const Region *, RejectLog>::iterator reject_iterator;
+  typedef std::map<const Region *, RejectLog>::const_iterator
+      const_reject_iterator;
+
+  reject_iterator reject_begin() { return RejectLogs.begin(); }
+  reject_iterator reject_end() { return RejectLogs.end(); }
+
+  const_reject_iterator reject_begin() const { return RejectLogs.begin(); }
+  const_reject_iterator reject_end() const { return RejectLogs.end(); }
+  //@}
+
+  /// @brief Emit rejection remarks for all smallest invalid regions.
+  ///
+  /// @param F The function to emit remarks for.
+  /// @param R The region to start the region tree traversal for.
+  void emitMissedRemarksForLeaves(const Function &F, const Region *R);
+
+  /// @brief Emit rejection remarks for the parent regions of all valid regions.
+  ///
+  /// Emitting rejection remarks for the parent regions of all valid regions
+  /// may give the end-user clues about how to increase the size of the
+  /// detected Scops.
+  ///
+  /// @param F The function to emit remarks for.
+  /// @param ValidRegions The set of valid regions to emit remarks for.
+  void emitMissedRemarksForValidRegions(const Function &F,
+                                        const RegionSet &ValidRegions);
+
+  /// @brief Mark the function as invalid so we will not extract any scop from
+  ///        the function.
+  ///
+  /// @param F The function to mark as invalid.
+  void markFunctionAsInvalid(Function *F) const;
+
+  /// @brief Verify if all valid Regions in this Function are still valid
+  /// after some transformations.
+  void verifyAnalysis() const;
+
+  /// @brief 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;
+
+  /// @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;
+  //@}
+};
+
+} // end namespace polly
+
+namespace llvm {
+class PassRegistry;
+void initializeScopDetectionPass(llvm::PassRegistry &);
+}
+
+#endif
diff --git a/final/include/polly/ScopDetectionDiagnostic.h b/final/include/polly/ScopDetectionDiagnostic.h
new file mode 100644
index 0000000..2c5b975
--- /dev/null
+++ b/final/include/polly/ScopDetectionDiagnostic.h
@@ -0,0 +1,875 @@
+//=== 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_SCOP_DETECTION_DIAGNOSTIC_H
+#define POLLY_SCOP_DETECTION_DIAGNOSTIC_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Analysis/AliasSetTracker.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Value.h"
+#include "llvm/Support/Casting.h"
+#include <memory>
+#include <string>
+
+using namespace llvm;
+
+namespace llvm {
+class SCEV;
+class BasicBlock;
+class Value;
+class Region;
+}
+
+namespace polly {
+
+class RejectLog;
+/// @brief 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 F The function we emit remarks for.
+/// @param Log The error log containing all messages being emitted as remark.
+void emitRejectionRemarks(const llvm::Function &F, const RejectLog &Log);
+
+/// @brief Emit diagnostic remarks for a valid Scop
+///
+/// @param F The function we emit remarks for
+/// @param R The region that marks a valid Scop
+void emitValidRemarks(const llvm::Function &F, const Region *R);
+
+// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
+enum RejectReasonKind {
+  // CFG Category
+  rrkCFG,
+  rrkNonBranchTerminator,
+  rrkCondition,
+  rrkLastCFG,
+
+  // Non-Affinity
+  rrkAffFunc,
+  rrkUndefCond,
+  rrkInvalidCond,
+  rrkUnsignedCond,
+  rrkUndefOperand,
+  rrkNonAffBranch,
+  rrkNoBasePtr,
+  rrkUndefBasePtr,
+  rrkVariantBasePtr,
+  rrkNonAffineAccess,
+  rrkDifferentElementSize,
+  rrkLastAffFunc,
+
+  // IndVar
+  rrkIndVar,
+  rrkPhiNodeRefInRegion,
+  rrkLastIndVar,
+
+  rrkIndEdge,
+
+  rrkLoopBound,
+
+  rrkFuncCall,
+
+  rrkAlias,
+
+  rrkSimpleLoop,
+
+  // Other
+  rrkOther,
+  rrkIntToPtr,
+  rrkAlloca,
+  rrkUnknownInst,
+  rrkPHIinExit,
+  rrkEntry,
+  rrkUnprofitable,
+  rrkLastOther
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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:
+  RejectReasonKind getKind() const { return Kind; }
+
+  RejectReason(RejectReasonKind K) : Kind(K) {}
+
+  virtual ~RejectReason() {}
+
+  /// @brief Generate a reasonable diagnostic message describing this error.
+  ///
+  /// @return A debug message representing this error.
+  virtual std::string getMessage() const = 0;
+
+  /// @brief 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.";
+  };
+
+  /// @brief Get the source location of this error.
+  ///
+  /// @return The debug location for this error.
+  virtual const llvm::DebugLoc &getDebugLoc() const;
+};
+
+typedef std::shared_ptr<RejectReason> RejectReasonPtr;
+
+/// @brief Stores all errors that ocurred during the detection.
+class RejectLog {
+  Region *R;
+  llvm::SmallVector<RejectReasonPtr, 1> ErrorReports;
+
+public:
+  explicit RejectLog(Region *R) : R(R) {}
+
+  typedef llvm::SmallVector<RejectReasonPtr, 1>::const_iterator iterator;
+
+  iterator begin() const { return ErrorReports.begin(); }
+  iterator end() const { return ErrorReports.end(); }
+  size_t size() const { return ErrorReports.size(); }
+
+  /// @brief 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); }
+};
+
+/// @brief Store reject logs
+class RejectLogsContainer {
+  std::map<const Region *, RejectLog> Logs;
+
+public:
+  typedef std::map<const Region *, RejectLog>::iterator iterator;
+  typedef std::map<const Region *, RejectLog>::const_iterator const_iterator;
+
+  iterator begin() { return Logs.begin(); }
+  iterator end() { return Logs.end(); }
+
+  const_iterator begin() const { return Logs.begin(); }
+  const_iterator end() const { return Logs.end(); }
+
+  std::pair<iterator, bool>
+  insert(const std::pair<const Region *, RejectLog> &New) {
+    return Logs.insert(New);
+  }
+
+  std::map<const Region *, RejectLog>::mapped_type at(const Region *R) {
+    return Logs.at(R);
+  }
+
+  void clear() { Logs.clear(); }
+
+  size_t count(const Region *R) const { return Logs.count(R); }
+
+  size_t size(const Region *R) const {
+    if (!Logs.count(R))
+      return 0;
+    return Logs.at(R).size();
+  }
+
+  bool hasErrors(const Region *R) const {
+    if (!Logs.count(R))
+      return false;
+
+    RejectLog Log = Logs.at(R);
+    return Log.hasErrors();
+  }
+
+  bool hasErrors(Region *R) const { return hasErrors((const Region *)R); }
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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);
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a non-branch terminator within a Scop candidate.
+class ReportNonBranchTerminator : public ReportCFG {
+  BasicBlock *BB;
+
+public:
+  ReportNonBranchTerminator(BasicBlock *BB)
+      : ReportCFG(rrkNonBranchTerminator), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a not well-structured condition within the CFG.
+class ReportCondition : public ReportCFG {
+  //===--------------------------------------------------------------------===//
+
+  // The BasicBlock we found the broken condition in.
+  BasicBlock *BB;
+
+public:
+  ReportCondition(BasicBlock *BB) : ReportCFG(rrkCondition), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Base class for non-affine reject reasons.
+///
+/// Scop candidates that violate restrictions to affinity are reported under
+/// this class.
+class ReportAffFunc : public RejectReason {
+  //===--------------------------------------------------------------------===//
+
+  // 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
+  //@{
+  virtual const DebugLoc &getDebugLoc() const override {
+    return Inst->getDebugLoc();
+  };
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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(rrkUndefCond, Inst), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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(rrkInvalidCond, Inst), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures an condition on unsigned values
+///
+/// We do not yet allow conditions on unsigend values
+class ReportUnsignedCond : public ReportAffFunc {
+  //===--------------------------------------------------------------------===//
+
+  // The BasicBlock we found the broken condition in.
+  BasicBlock *BB;
+
+public:
+  ReportUnsignedCond(const Instruction *Inst, BasicBlock *BB)
+      : ReportAffFunc(rrkUnsignedCond, Inst), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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(rrkUndefOperand, Inst), BB(BB) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a non-affine branch.
+class ReportNonAffBranch : public ReportAffFunc {
+  //===--------------------------------------------------------------------===//
+
+  // The BasicBlock we found the non-affine branch in.
+  BasicBlock *BB;
+
+  /// @brief 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(rrkNonAffBranch, 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
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a missing base pointer.
+class ReportNoBasePtr : public ReportAffFunc {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportNoBasePtr(const Instruction *Inst)
+      : ReportAffFunc(rrkNoBasePtr, Inst) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures an undefined base pointer.
+class ReportUndefBasePtr : public ReportAffFunc {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportUndefBasePtr(const Instruction *Inst)
+      : ReportAffFunc(rrkUndefBasePtr, Inst) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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(rrkVariantBasePtr, Inst), BaseValue(BaseValue) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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(rrkNonAffineAccess, Inst), AccessFunction(AccessFunction),
+        BaseValue(V) {}
+
+  const SCEV *get() { return AccessFunction; }
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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(rrkDifferentElementSize, Inst), BaseValue(V) {}
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Base class for reject reasons related to induction variables.
+///
+//  ReportIndVar reject reasons are generated when the ScopDetection finds
+/// errors in the induction variable(s) of the Scop candidate.
+class ReportIndVar : public RejectReason {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportIndVar(const RejectReasonKind K);
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a phi node that refers to SSA names in the current region.
+class ReportPhiNodeRefInRegion : public ReportIndVar {
+  //===--------------------------------------------------------------------===//
+
+  // The offending instruction.
+  Instruction *Inst;
+
+public:
+  ReportPhiNodeRefInRegion(Instruction *Inst);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures a region with invalid entering edges.
+class ReportIndEdge : public RejectReason {
+  //===--------------------------------------------------------------------===//
+
+  BasicBlock *BB;
+
+public:
+  ReportIndEdge(BasicBlock *BB);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  virtual std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  virtual std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with aliasing.
+class ReportAlias : public RejectReason {
+  //===--------------------------------------------------------------------===//
+public:
+  typedef std::vector<const llvm::Value *> PointerSnapshotTy;
+
+private:
+  /// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  virtual std::string getEndUserMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with non simplified loops.
+class ReportSimpleLoop : public RejectReason {
+  //===--------------------------------------------------------------------===//
+public:
+  ReportSimpleLoop();
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief Captures errors with phi nodes in exit BBs.
+class ReportPHIinExit : public ReportOther {
+  //===--------------------------------------------------------------------===//
+  Instruction *Inst;
+
+public:
+  ReportPHIinExit(Instruction *Inst);
+
+  /// @name LLVM-RTTI interface
+  //@{
+  static bool classof(const RejectReason *RR);
+  //@}
+
+  /// @name RejectReason interface
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+//===----------------------------------------------------------------------===//
+/// @brief 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
+  //@{
+  virtual std::string getMessage() const override;
+  virtual std::string getEndUserMessage() const override;
+  virtual const DebugLoc &getDebugLoc() const override;
+  //@}
+};
+
+} // namespace polly
+
+#endif // POLLY_SCOP_DETECTION_DIAGNOSTIC_H
diff --git a/final/include/polly/ScopInfo.h b/final/include/polly/ScopInfo.h
new file mode 100644
index 0000000..d3aba3d
--- /dev/null
+++ b/final/include/polly/ScopInfo.h
@@ -0,0 +1,1151 @@
+//===------ polly/ScopInfo.h - Create Scops from LLVM IR --------*- 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.
+//
+// This representation is shared among several tools in the polyhedral
+// community, which are e.g. CLooG, Pluto, Loopo, Graphite.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_SCOP_INFO_H
+#define POLLY_SCOP_INFO_H
+
+#include "polly/ScopDetection.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Analysis/RegionPass.h"
+#include "isl/ctx.h"
+
+#include <forward_list>
+#include <deque>
+
+using namespace llvm;
+
+namespace llvm {
+class Loop;
+class LoopInfo;
+class PHINode;
+class ScalarEvolution;
+class SCEV;
+class SCEVAddRecExpr;
+class Type;
+}
+
+struct isl_ctx;
+struct isl_map;
+struct isl_basic_map;
+struct isl_id;
+struct isl_set;
+struct isl_union_set;
+struct isl_union_map;
+struct isl_space;
+struct isl_ast_build;
+struct isl_constraint;
+struct isl_pw_multi_aff;
+struct isl_schedule;
+
+namespace polly {
+
+class IRAccess;
+class Scop;
+class ScopStmt;
+class ScopInfo;
+class TempScop;
+class SCEVAffFunc;
+class Comparison;
+
+/// @brief 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:
+  /// @brief 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.
+  ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *IslCtx,
+                const SmallVector<const SCEV *, 4> &DimensionSizes);
+
+  /// @brief Destructor to free the isl id of the base pointer.
+  ~ScopArrayInfo();
+
+  /// @brief Return the base pointer.
+  Value *getBasePtr() const { return BasePtr; }
+
+  /// @brief Return the number of dimensions.
+  unsigned getNumberOfDimensions() const { return DimensionSizes.size(); }
+
+  /// @brief Return the size of dimension @p dim.
+  const SCEV *getDimensionSize(unsigned dim) const {
+    assert(dim < getNumberOfDimensions() && "Invalid dimension");
+    return DimensionSizes[dim];
+  }
+
+  /// @brief Get the type of the elements stored in this array.
+  Type *getElementType() const { return ElementType; }
+
+  /// @brief Get element size in bytes.
+  int getElemSizeInBytes() const;
+
+  /// @brief Get the name of this memory reference.
+  std::string getName() const;
+
+  /// @brief Return the isl id for the base pointer.
+  __isl_give isl_id *getBasePtrId() const;
+
+  /// @brief Dump a readable representation to stderr.
+  void dump() const;
+
+  /// @brief Print a readable representation to @p OS.
+  void print(raw_ostream &OS) const;
+
+  /// @brief Access the ScopArrayInfo associated with an access function.
+  static const ScopArrayInfo *
+  getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA);
+
+  /// @brief Access the ScopArrayInfo associated with an isl Id.
+  static const ScopArrayInfo *getFromId(__isl_take isl_id *Id);
+
+private:
+  /// @brief The base pointer.
+  Value *BasePtr;
+
+  /// @brief The type of the elements stored in this array.
+  Type *ElementType;
+
+  /// @brief The isl id for the base pointer.
+  isl_id *Id;
+
+  /// @brief The sizes of each dimension.
+  SmallVector<const SCEV *, 4> DimensionSizes;
+};
+
+/// @brief Represent memory accesses in statements.
+class MemoryAccess {
+public:
+  /// @brief 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, MUST_WRITE, MAY_WRITE };
+
+  /// @brief 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:
+  MemoryAccess(const MemoryAccess &) = delete;
+  const MemoryAccess &operator=(const MemoryAccess &) = delete;
+
+  isl_map *AccessRelation;
+  enum AccessType AccType;
+
+  /// @brief The base address (e.g., A for A[i+j]).
+  Value *BaseAddr;
+
+  std::string BaseName;
+  __isl_give isl_basic_map *createBasicAccessMap(ScopStmt *Statement);
+  ScopStmt *Statement;
+
+  /// @brief 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 lifing the equality check in ScopInfo,
+  /// 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;
+
+  /// @brief The access instruction of this memory access.
+  Instruction *Inst;
+
+  /// Updated access relation read from JSCOP file.
+  isl_map *newAccessRelation;
+
+  /// @brief A unique identifier for this memory access.
+  ///
+  /// The identifier is unique between all memory accesses belonging to the same
+  /// scop statement.
+  isl_id *Id;
+
+  void assumeNoOutOfBound(const IRAccess &Access);
+
+  /// @brief Compute bounds on an over approximated  access relation.
+  ///
+  /// @param ElementSize The size of one element accessed.
+  void computeBoundsOnAccessRelation(unsigned ElementSize);
+
+  /// @brief Get the original access function as read from IR.
+  __isl_give isl_map *getOriginalAccessRelation() const;
+
+  /// @brief Return the space in which the access relation lives in.
+  __isl_give isl_space *getOriginalAccessRelationSpace() const;
+
+  /// @brief Get the new access function imported or set by a pass
+  __isl_give isl_map *getNewAccessRelation() const;
+
+  /// @brief Fold the memory access to consider parameteric 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 preferrable. 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.
+  __isl_give isl_map *foldAccess(const IRAccess &Access,
+                                 __isl_take isl_map *AccessRelation,
+                                 ScopStmt *Statement);
+
+public:
+  /// @brief Create a memory access from an access in LLVM-IR.
+  ///
+  /// @param Access     The memory access.
+  /// @param AccInst    The access instruction.
+  /// @param Statement  The statement that contains the access.
+  /// @param SAI        The ScopArrayInfo object for this base pointer.
+  /// @param Identifier An identifier that is unique for all memory accesses
+  ///                   belonging to the same scop statement.
+  MemoryAccess(const IRAccess &Access, Instruction *AccInst,
+               ScopStmt *Statement, const ScopArrayInfo *SAI, int Identifier);
+
+  ~MemoryAccess();
+
+  /// @brief Get the type of a memory access.
+  enum AccessType getType() { return AccType; }
+
+  /// @brief Is this a reduction like access?
+  bool isReductionLike() const { return RedType != RT_NONE; }
+
+  /// @brief Is this a read memory access?
+  bool isRead() const { return AccType == MemoryAccess::READ; }
+
+  /// @brief Is this a must-write memory access?
+  bool isMustWrite() const { return AccType == MemoryAccess::MUST_WRITE; }
+
+  /// @brief Is this a may-write memory access?
+  bool isMayWrite() const { return AccType == MemoryAccess::MAY_WRITE; }
+
+  /// @brief Is this a write memory access?
+  bool isWrite() const { return isMustWrite() || isMayWrite(); }
+
+  /// @brief Check if a new access relation was imported or set by a pass.
+  bool hasNewAccessRelation() const { return newAccessRelation; }
+
+  /// @brief 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 *getAccessRelation() const {
+    return hasNewAccessRelation() ? getNewAccessRelation()
+                                  : getOriginalAccessRelation();
+  }
+
+  /// @brief Return the access relation after the schedule was applied.
+  __isl_give isl_pw_multi_aff *
+  applyScheduleToAccessRelation(__isl_take isl_union_map *Schedule) const;
+
+  /// @brief Get an isl string representing the access function read from IR.
+  std::string getOriginalAccessRelationStr() const;
+
+  /// @brief Get the base address of this access (e.g. A for A[i+j]).
+  Value *getBaseAddr() const { return BaseAddr; }
+
+  /// @brief Get the base array isl_id for this access.
+  __isl_give isl_id *getArrayId() const;
+
+  /// @brief Get the ScopArrayInfo object for the base address.
+  const ScopArrayInfo *getScopArrayInfo() const;
+
+  /// @brief Return a string representation of the accesse's reduction type.
+  const std::string getReductionOperatorStr() const;
+
+  /// @brief Return a string representation of the reduction type @p RT.
+  static const std::string getReductionOperatorStr(ReductionType RT);
+
+  const std::string &getBaseName() const { return BaseName; }
+
+  /// @brief Return the access instruction of this memory access.
+  Instruction *getAccessInstruction() const { return Inst; }
+
+  /// 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_give isl_set *getStride(__isl_take const isl_map *Schedule) const;
+
+  /// 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_take const 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_take const 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_take const isl_map *Schedule) const;
+
+  /// @brief Check if this is a scalar memory access.
+  bool isScalar() const;
+
+  /// @brief Get the statement that contains this memory access.
+  ScopStmt *getStatement() const { return Statement; }
+
+  /// @brief Get the reduction type of this access
+  ReductionType getReductionType() const { return RedType; }
+
+  /// @brief Set the updated access relation read from JSCOP file.
+  void setNewAccessRelation(__isl_take isl_map *newAccessRelation);
+
+  /// @brief Mark this a reduction like access
+  void markAsReductionLike(ReductionType RT) { RedType = RT; }
+
+  /// @brief Align the parameters in the access relation to the scop context
+  void realignParams();
+
+  /// @brief Get identifier for the memory access.
+  ///
+  /// This identifier is unique for all accesses that belong to the same scop
+  /// statement.
+  __isl_give isl_id *getId() const;
+
+  /// @brief Print the MemoryAccess.
+  ///
+  /// @param OS The output stream the MemoryAccess is printed to.
+  void print(raw_ostream &OS) const;
+
+  /// @brief Print the MemoryAccess to stderr.
+  void dump() const;
+};
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                              MemoryAccess::ReductionType RT);
+
+///===----------------------------------------------------------------------===//
+/// @brief 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 {
+public:
+  /// @brief List to hold all (scalar) memory accesses mapped to an instruction.
+  using MemoryAccessList = std::forward_list<MemoryAccess>;
+
+  ScopStmt(const ScopStmt &) = delete;
+  const ScopStmt &operator=(const ScopStmt &) = delete;
+
+  /// Create the ScopStmt from a BasicBlock.
+  ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
+           BasicBlock &bb, SmallVectorImpl<Loop *> &NestLoops);
+
+  /// Create an overapproximating ScopStmt for the region @p R.
+  ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion, Region &R,
+           SmallVectorImpl<Loop *> &NestLoops);
+
+private:
+  /// Polyhedral description
+  //@{
+
+  /// The Scop containing this ScopStmt
+  Scop &Parent;
+
+  /// 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.
+  typedef SmallVector<MemoryAccess *, 8> MemoryAccessVec;
+  MemoryAccessVec MemAccs;
+
+  /// @brief Mapping from instructions to (scalar) memory accesses.
+  DenseMap<const Instruction *, MemoryAccessList *> InstructionToAccess;
+
+  //@}
+
+  /// @brief 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.
+  ///
+  ///{
+
+  /// @brief The BasicBlock represented by this statement (in the affine case).
+  BasicBlock *BB;
+
+  /// @brief The region represented by this statement (in the non-affine case).
+  Region *R;
+
+  ///}
+
+  /// @brief The isl AST build for the new generated AST.
+  isl_ast_build *Build;
+
+  std::vector<Loop *> NestLoops;
+
+  std::string BaseName;
+
+  /// Build the statement.
+  //@{
+  __isl_give isl_set *buildConditionSet(const Comparison &Cmp);
+  __isl_give isl_set *addConditionsToDomain(__isl_take isl_set *Domain,
+                                            TempScop &tempScop,
+                                            const Region &CurRegion);
+  __isl_give isl_set *addLoopBoundsToDomain(__isl_take isl_set *Domain,
+                                            TempScop &tempScop);
+  __isl_give isl_set *buildDomain(TempScop &tempScop, const Region &CurRegion);
+
+  /// @brief Create the accesses for instructions in @p Block.
+  ///
+  /// @param tempScop       The template SCoP.
+  /// @param Block          The basic block for which accesses should be
+  ///                       created.
+  /// @param isApproximated Flag to indicate blocks that might not be executed,
+  ///                       hence for which write accesses need to be modeled as
+  ///                       may-write accesses.
+  void buildAccesses(TempScop &tempScop, BasicBlock *Block,
+                     bool isApproximated = false);
+
+  /// @brief Detect and mark reductions in the ScopStmt
+  void checkForReductions();
+
+  /// @brief Collect loads which might form a reduction chain with @p StoreMA
+  void
+  collectCandiateReductionLoads(MemoryAccess *StoreMA,
+                                llvm::SmallVectorImpl<MemoryAccess *> &Loads);
+  //@}
+
+  /// @brief Derive assumptions about parameter values from GetElementPtrInst
+  ///
+  /// In case a GEP instruction references into a fixed size array e.g., an
+  /// access A[i][j] into an array A[100x100], LLVM-IR does not guarantee that
+  /// the subscripts always compute values that are within array bounds. In this
+  /// function we derive the set of parameter values for which all accesses are
+  /// within bounds and add the assumption that the scop is only every executed
+  /// with this set of parameter values.
+  ///
+  /// Example:
+  ///
+  ///   void foo(float A[][20], long n, long m {
+  ///     for (long i = 0; i < n; i++)
+  ///       for (long j = 0; j < m; j++)
+  ///         A[i][j] = ...
+  ///
+  /// This loop yields out-of-bound accesses if m is at least 20 and at the same
+  /// time at least one iteration of the outer loop is executed. Hence, we
+  /// assume:
+  ///
+  ///   n <= 0 or m <= 20.
+  ///
+  /// TODO: The location where the GEP instruction is executed is not
+  /// necessarily the location where the memory is actually accessed. As a
+  /// result scanning for GEP[s] is imprecise. Even though this is not a
+  /// correctness problem, this imprecision may result in missed optimizations
+  /// or non-optimal run-time checks.
+  void deriveAssumptionsFromGEP(GetElementPtrInst *Inst);
+
+  /// @brief Scan @p Block and derive assumptions about parameter values.
+  void deriveAssumptions(BasicBlock *Block);
+
+public:
+  ~ScopStmt();
+
+  /// @brief Get an isl_ctx pointer.
+  isl_ctx *getIslCtx() const;
+
+  /// @brief Get the iteration domain of this ScopStmt.
+  ///
+  /// @return The iteration domain of this ScopStmt.
+  __isl_give isl_set *getDomain() const;
+
+  /// @brief Get the space of the iteration domain
+  ///
+  /// @return The space of the iteration domain
+  __isl_give isl_space *getDomainSpace() const;
+
+  /// @brief Get the id of the iteration domain space
+  ///
+  /// @return The id of the iteration domain space
+  __isl_give isl_id *getDomainId() const;
+
+  /// @brief Get an isl string representing this domain.
+  std::string getDomainStr() const;
+
+  /// @brief Get the schedule function of this ScopStmt.
+  ///
+  /// @return The schedule function of this ScopStmt.
+  __isl_give isl_map *getSchedule() const;
+
+  /// @brief Get an isl string representing this schedule.
+  std::string getScheduleStr() const;
+
+  /// @brief 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; }
+
+  /// @brief Return true if this statement represents a single basic block.
+  bool isBlockStmt() const { return BB != nullptr; }
+
+  /// @brief 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; }
+
+  /// @brief Return true if this statement represents a whole region.
+  bool isRegionStmt() const { return R != nullptr; }
+
+  /// @brief Return the (scalar) memory accesses for @p Inst.
+  const MemoryAccessList &getAccessesFor(const Instruction *Inst) const {
+    MemoryAccessList *MAL = lookupAccessesFor(Inst);
+    assert(MAL && "Cannot get memory accesses because they do not exist!");
+    return *MAL;
+  }
+
+  /// @brief Return the (scalar) memory accesses for @p Inst if any.
+  MemoryAccessList *lookupAccessesFor(const Instruction *Inst) const {
+    auto It = InstructionToAccess.find(Inst);
+    return It == InstructionToAccess.end() ? nullptr : It->getSecond();
+  }
+
+  /// @brief Return the __first__ (scalar) memory access for @p Inst.
+  const MemoryAccess &getAccessFor(const Instruction *Inst) const {
+    MemoryAccess *MA = lookupAccessFor(Inst);
+    assert(MA && "Cannot get memory access because it does not exist!");
+    return *MA;
+  }
+
+  /// @brief Return the __first__ (scalar) memory access for @p Inst if any.
+  MemoryAccess *lookupAccessFor(const Instruction *Inst) const {
+    auto It = InstructionToAccess.find(Inst);
+    return It == InstructionToAccess.end() ? nullptr
+                                           : &It->getSecond()->front();
+  }
+
+  void setBasicBlock(BasicBlock *Block) {
+    // TODO: Handle the case where the statement is a region statement, thus
+    //       the entry block was split and needs to be changed in the region R.
+    assert(BB && "Cannot set a block for a region statement");
+    BB = Block;
+  }
+
+  typedef MemoryAccessVec::iterator iterator;
+  typedef MemoryAccessVec::const_iterator 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(); }
+
+  unsigned getNumParams() const;
+  unsigned getNumIterators() const;
+
+  Scop *getParent() { return &Parent; }
+  const Scop *getParent() const { return &Parent; }
+
+  const char *getBaseName() const;
+
+  /// @brief Set the isl AST build.
+  void setAstBuild(__isl_keep isl_ast_build *B) { Build = B; }
+
+  /// @brief Get the isl AST build.
+  __isl_keep isl_ast_build *getAstBuild() const { return Build; }
+
+  /// @brief Restrict the domain of the statement.
+  ///
+  /// @param NewDomain The new statement domain.
+  void restrictDomain(__isl_take isl_set *NewDomain);
+
+  /// @brief Get the loop for a dimension.
+  ///
+  /// @param Dimension The dimension of the induction variable
+  /// @return The loop at a certain dimension.
+  const Loop *getLoopForDimension(unsigned Dimension) const;
+
+  /// @brief Align the parameters in the statement to the scop context
+  void realignParams();
+
+  /// @brief Print the ScopStmt.
+  ///
+  /// @param OS The output stream the ScopStmt is printed to.
+  void print(raw_ostream &OS) const;
+
+  /// @brief Print the ScopStmt to stderr.
+  void dump() const;
+};
+
+/// @brief Print ScopStmt S to raw_ostream O.
+static inline raw_ostream &operator<<(raw_ostream &O, const ScopStmt &S) {
+  S.print(O);
+  return O;
+}
+
+///===----------------------------------------------------------------------===//
+/// @brief 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:
+  /// @brief Type to represent a pair of minimal/maximal access to an array.
+  using MinMaxAccessTy = std::pair<isl_pw_multi_aff *, isl_pw_multi_aff *>;
+
+  /// @brief Vector of minimal/maximal accesses to different arrays.
+  using MinMaxVectorTy = SmallVector<MinMaxAccessTy, 4>;
+
+  /// @brief Vector of minimal/maximal access vectors one for each alias group.
+  using MinMaxVectorVectorTy = SmallVector<MinMaxVectorTy *, 4>;
+
+private:
+  Scop(const Scop &) = delete;
+  const Scop &operator=(const Scop &) = delete;
+
+  ScalarEvolution *SE;
+
+  /// The underlying Region.
+  Region &R;
+
+  /// Flag to indicate that the scheduler actually optimized the SCoP.
+  bool IsOptimized;
+
+  /// Max loop depth.
+  unsigned MaxLoopDepth;
+
+  typedef std::deque<ScopStmt> StmtSet;
+  /// The statements in this Scop.
+  StmtSet Stmts;
+
+  /// Parameters of this Scop
+  typedef SmallVector<const SCEV *, 8> ParamVecType;
+  ParamVecType Parameters;
+
+  /// The isl_ids that are used to represent the parameters
+  typedef std::map<const SCEV *, int> ParamIdType;
+  ParamIdType ParameterIds;
+
+  /// Isl context.
+  isl_ctx *IslCtx;
+
+  /// @brief A map from basic blocks to SCoP statements.
+  DenseMap<BasicBlock *, ScopStmt *> StmtMap;
+
+  /// Constraints on parameters.
+  isl_set *Context;
+
+  typedef MapVector<const Value *, std::unique_ptr<ScopArrayInfo>>
+      ArrayInfoMapTy;
+  /// @brief A map to remember ScopArrayInfo objects for all base pointers.
+  ArrayInfoMapTy ScopArrayInfoMap;
+
+  /// @brief 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;
+
+  /// @brief 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;
+
+  /// @brief 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.
+  MinMaxVectorVectorTy MinMaxAliasGroups;
+
+  /// Create the static control part with a region, max loop depth of this
+  /// region and parameters used in this region.
+  Scop(TempScop &TempScop, LoopInfo &LI, ScalarEvolution &SE, ScopDetection &SD,
+       isl_ctx *ctx);
+
+  /// @brief Check if a basic block is trivial.
+  ///
+  /// A trivial basic block does not contain any useful calculation. Therefore,
+  /// it does not need to be represented as a polyhedral statement.
+  ///
+  /// @param BB The basic block to check
+  /// @param tempScop TempScop returning further information regarding the Scop.
+  ///
+  /// @return True if the basic block is trivial, otherwise false.
+  static bool isTrivialBB(BasicBlock *BB, TempScop &tempScop);
+
+  /// @brief Build the Context of the Scop.
+  void buildContext();
+
+  /// @brief Add the bounds of the parameters to the context.
+  void addParameterBounds();
+
+  /// @brief Simplify the assumed context.
+  void simplifyAssumedContext();
+
+  /// @brief Create a new SCoP statement for either @p BB or @p R.
+  ///
+  /// Either @p BB or @p R should be non-null. A new statement for the non-null
+  /// argument will be created and added to the statement vector and map.
+  ///
+  /// @param BB         The basic block we build the statement for (or null)
+  /// @param R          The region we build the statement for (or null).
+  /// @param tempScop   The temp SCoP we use as model.
+  /// @param CurRegion  The SCoP region.
+  /// @param NestLoops  A vector of all surrounding loops.
+  ScopStmt *addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
+                        const Region &CurRegion,
+                        SmallVectorImpl<Loop *> &NestLoops);
+
+  /// @brief Build Scop and ScopStmts from a given TempScop.
+  ///
+  /// @param TempScop  The temporary scop that is translated into an actual
+  ///                  scop.
+  /// @param CurRegion The subregion of the current scop that we are currently
+  ///                  translating.
+  /// @param NestLoop  The set of loops that surround the current subregion.
+  /// @param LI        The LoopInfo object.
+  /// @param SD        The ScopDetection object.
+  __isl_give isl_schedule *buildScop(TempScop &TempScop,
+                                     const Region &CurRegion,
+                                     SmallVectorImpl<Loop *> &NestLoops,
+                                     LoopInfo &LI, ScopDetection &SD);
+
+  /// @name Helper function for printing the Scop.
+  ///
+  ///{
+  void printContext(raw_ostream &OS) const;
+  void printArrayInfo(raw_ostream &OS) const;
+  void printStatements(raw_ostream &OS) const;
+  void printAliasAssumptions(raw_ostream &OS) const;
+  ///}
+
+  friend class ScopInfo;
+
+public:
+  ~Scop();
+
+  ScalarEvolution *getSE() const;
+
+  /// @brief Get the count of parameters used in this Scop.
+  ///
+  /// @return The count of parameters used in this Scop.
+  inline ParamVecType::size_type getNumParams() const {
+    return Parameters.size();
+  }
+
+  /// @brief Get a set containing the parameters used in this Scop
+  ///
+  /// @return The set containing the parameters used in this Scop.
+  inline const ParamVecType &getParams() const { return Parameters; }
+
+  /// @brief Take a list of parameters and add the new ones to the scop.
+  void addParams(std::vector<const SCEV *> NewParameters);
+
+  int getNumArrays() { return ScopArrayInfoMap.size(); }
+
+  typedef iterator_range<ArrayInfoMapTy::iterator> array_range;
+  typedef iterator_range<ArrayInfoMapTy::const_iterator> const_array_range;
+
+  inline array_range arrays() {
+    return array_range(ScopArrayInfoMap.begin(), ScopArrayInfoMap.end());
+  }
+
+  inline const_array_range arrays() const {
+    return const_array_range(ScopArrayInfoMap.begin(), ScopArrayInfoMap.end());
+  }
+
+  /// @brief 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;
+
+  /// @name Parameter Iterators
+  ///
+  /// These iterators iterate over all parameters of this Scop.
+  //@{
+  typedef ParamVecType::iterator param_iterator;
+  typedef ParamVecType::const_iterator const_param_iterator;
+
+  param_iterator param_begin() { return Parameters.begin(); }
+  param_iterator param_end() { return Parameters.end(); }
+  const_param_iterator param_begin() const { return Parameters.begin(); }
+  const_param_iterator param_end() const { return Parameters.end(); }
+  //@}
+
+  /// @brief 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; }
+
+  /// @brief Get the maximum depth of the loop.
+  ///
+  /// @return The maximum depth of the loop.
+  inline unsigned getMaxLoopDepth() const { return MaxLoopDepth; }
+
+  /// @brief Mark the SCoP as optimized by the scheduler.
+  void markAsOptimized() { IsOptimized = true; }
+
+  /// @brief Check if the SCoP has been optimized by the scheduler.
+  bool isOptimized() const { return IsOptimized; }
+
+  /// @brief Get the name of this Scop.
+  std::string getNameStr() const;
+
+  /// @brief Get the constraint on parameter of this Scop.
+  ///
+  /// @return The constraint on parameter of this Scop.
+  __isl_give isl_set *getContext() const;
+  __isl_give isl_space *getParamSpace() const;
+
+  /// @brief Get the assumed context for this Scop.
+  ///
+  /// @return The assumed context of this Scop.
+  __isl_give isl_set *getAssumedContext() const;
+
+  /// @brief 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 Set A set describing relations between parameters that are assumed
+  ///            to hold.
+  void addAssumption(__isl_take isl_set *Set);
+
+  /// @brief Build all alias groups for this SCoP.
+  ///
+  /// @returns True if __no__ error occurred, false otherwise.
+  bool buildAliasGroups(AliasAnalysis &AA);
+
+  /// @brief Return all alias groups for this SCoP.
+  const MinMaxVectorVectorTy &getAliasGroups() const {
+    return MinMaxAliasGroups;
+  }
+
+  /// @brief Get an isl string representing the context.
+  std::string getContextStr() const;
+
+  /// @brief Get an isl string representing the assumed context.
+  std::string getAssumedContextStr() const;
+
+  /// @brief Return the stmt for the given @p BB or nullptr if none.
+  ScopStmt *getStmtForBasicBlock(BasicBlock *BB) const;
+
+  /// @brief 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.
+  //@{
+  typedef StmtSet::iterator iterator;
+  typedef StmtSet::const_iterator 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(); }
+
+  typedef StmtSet::reverse_iterator reverse_iterator;
+  typedef StmtSet::const_reverse_iterator 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(); }
+  //@}
+
+  /// @brief Return the (possibly new) ScopArrayInfo object for @p Access.
+  ///
+  /// @param ElementType The type of the elements stored in this array.
+  const ScopArrayInfo *
+  getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType,
+                           const SmallVector<const SCEV *, 4> &Sizes);
+
+  /// @brief Return the cached ScopArrayInfo object for @p BasePtr.
+  const ScopArrayInfo *getScopArrayInfo(Value *BasePtr);
+
+  void setContext(isl_set *NewContext);
+
+  /// @brief Align the parameters in the statement to the scop context
+  void realignParams();
+
+  /// @brief Print the static control part.
+  ///
+  /// @param OS The output stream the static control part is printed to.
+  void print(raw_ostream &OS) const;
+
+  /// @brief Print the ScopStmt to stderr.
+  void dump() const;
+
+  /// @brief Get the isl context of this static control part.
+  ///
+  /// @return The isl context of this static control part.
+  isl_ctx *getIslCtx() const;
+
+  /// @brief Get a union set containing the iteration domains of all statements.
+  __isl_give isl_union_set *getDomains() const;
+
+  /// @brief Get a union map of all may-writes performed in the SCoP.
+  __isl_give isl_union_map *getMayWrites();
+
+  /// @brief Get a union map of all must-writes performed in the SCoP.
+  __isl_give isl_union_map *getMustWrites();
+
+  /// @brief Get a union map of all writes performed in the SCoP.
+  __isl_give isl_union_map *getWrites();
+
+  /// @brief Get a union map of all reads performed in the SCoP.
+  __isl_give isl_union_map *getReads();
+
+  /// @brief Get the schedule of all the statements in the SCoP.
+  __isl_give isl_union_map *getSchedule() const;
+
+  /// @brief Get a schedule tree describing the schedule of all statements.
+  __isl_give isl_schedule *getScheduleTree() const;
+
+  /// @brief Update the current schedule
+  ///
+  /// @brief NewSchedule The new schedule (given as a flat union-map).
+  void setSchedule(__isl_take isl_union_map *NewSchedule);
+
+  /// @brief Update the current schedule
+  ///
+  /// @brief NewSchedule The new schedule (given as schedule tree).
+  void setScheduleTree(__isl_take isl_schedule *NewSchedule);
+
+  /// @brief Intersects the domains of all statements in the SCoP.
+  ///
+  /// @return true if a change was made
+  bool restrictDomains(__isl_take isl_union_set *Domain);
+};
+
+/// @brief Print Scop scop to raw_ostream O.
+static inline raw_ostream &operator<<(raw_ostream &O, const Scop &scop) {
+  scop.print(O);
+  return O;
+}
+
+///===---------------------------------------------------------------------===//
+/// @brief Build the Polly IR (Scop and ScopStmt) on a Region.
+///
+class ScopInfo : public RegionPass {
+  //===-------------------------------------------------------------------===//
+  ScopInfo(const ScopInfo &) = delete;
+  const ScopInfo &operator=(const ScopInfo &) = delete;
+
+  // The Scop
+  Scop *scop;
+  isl_ctx *ctx;
+
+  void clear() {
+    if (scop) {
+      delete scop;
+      scop = 0;
+    }
+  }
+
+public:
+  static char ID;
+  explicit ScopInfo();
+  ~ScopInfo();
+
+  /// @brief Try to build the Polly IR of static control part on 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 scop; }
+  const Scop *getScop() const { return scop; }
+
+  /// @name RegionPass interface
+  //@{
+  virtual bool runOnRegion(Region *R, RGPassManager &RGM);
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
+  virtual void releaseMemory() { clear(); }
+  virtual void print(raw_ostream &OS, const Module *) const {
+    if (scop)
+      scop->print(OS);
+    else
+      OS << "Invalid Scop!\n";
+  }
+  //@}
+};
+
+} // end namespace polly
+
+namespace llvm {
+class PassRegistry;
+void initializeScopInfoPass(llvm::PassRegistry &);
+}
+
+#endif
diff --git a/final/include/polly/ScopPass.h b/final/include/polly/ScopPass.h
new file mode 100644
index 0000000..173b580
--- /dev/null
+++ b/final/include/polly/ScopPass.h
@@ -0,0 +1,59 @@
+//===--------- 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 "llvm/Analysis/RegionPass.h"
+
+using namespace llvm;
+
+struct isl_ctx;
+
+namespace polly {
+class Scop;
+
+/// 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;
+
+  /// @brief Print method for SCoPs.
+  virtual void printScop(raw_ostream &OS, Scop &S) const = 0;
+
+  /// 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;
+};
+
+} // End llvm namespace
+
+#endif
diff --git a/final/include/polly/Support/GICHelper.h b/final/include/polly/Support/GICHelper.h
new file mode 100644
index 0000000..608dfd8
--- /dev/null
+++ b/final/include/polly/Support/GICHelper.h
@@ -0,0 +1,84 @@
+//===- 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/Support/raw_ostream.h"
+#include "isl/ctx.h"
+#include <string>
+
+struct isl_map;
+struct isl_union_map;
+struct isl_set;
+struct isl_union_set;
+struct isl_schedule;
+struct isl_multi_aff;
+struct isl_pw_multi_aff;
+struct isl_aff;
+struct isl_pw_aff;
+struct isl_val;
+
+namespace llvm {
+class Value;
+}
+
+namespace polly {
+__isl_give isl_val *isl_valFromAPInt(isl_ctx *Ctx, const llvm::APInt Int,
+                                     bool IsSigned);
+llvm::APInt APIntFromVal(__isl_take isl_val *Val);
+
+/// @brief 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_aff *aff);
+std::string stringFromIslObj(__isl_keep isl_pw_aff *pwaff);
+//@}
+
+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_pw_multi_aff *PMA) {
+  OS << polly::stringFromIslObj(PMA);
+  return OS;
+}
+
+/// @brief Return @p Prefix + @p Val->getName() + @p Suffix but Isl compatible.
+std::string getIslCompatibleName(const std::string &Prefix,
+                                 const llvm::Value *Val,
+                                 const std::string &Suffix);
+
+std::string getIslCompatibleName(const std::string &Prefix,
+                                 const std::string &Middle,
+                                 const std::string &Suffix);
+
+} // end 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..75e8ca8
--- /dev/null
+++ b/final/include/polly/Support/SCEVValidator.h
@@ -0,0 +1,65 @@
+//===--- 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 "llvm/ADT/SetVector.h"
+#include <vector>
+
+namespace llvm {
+class Region;
+class SCEV;
+class ScalarEvolution;
+class Value;
+class Loop;
+}
+
+namespace polly {
+/// @brief 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);
+
+/// @brief Find the values referenced by SCEVUnknowns in a given SCEV
+/// expression.
+///
+/// @param Expr The SCEV expression to scan for SCEVUnknowns.
+/// @param Expr A vector into which the found values are inserted.
+void findValues(const llvm::SCEV *Expr, llvm::SetVector<llvm::Value *> &Values);
+
+/// Returns true when the SCEV contains references to instructions within the
+/// region.
+///
+/// @param S The SCEV to analyze.
+/// @param R The region in which we look for dependences.
+bool hasScalarDepsInsideRegion(const llvm::SCEV *S, const llvm::Region *R);
+bool isAffineExpr(const llvm::Region *R, const llvm::SCEV *Expression,
+                  llvm::ScalarEvolution &SE,
+                  const llvm::Value *BaseAddress = 0);
+std::vector<const llvm::SCEV *>
+getParamsInAffineExpr(const llvm::Region *R, const llvm::SCEV *Expression,
+                      llvm::ScalarEvolution &SE,
+                      const llvm::Value *BaseAddress = 0);
+
+/// @brief 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::SCEV *, const llvm::SCEV *>
+extractConstantFactor(const llvm::SCEV *M, llvm::ScalarEvolution &SE);
+}
+
+#endif
diff --git a/final/include/polly/Support/ScopHelper.h b/final/include/polly/Support/ScopHelper.h
new file mode 100644
index 0000000..9277c22
--- /dev/null
+++ b/final/include/polly/Support/ScopHelper.h
@@ -0,0 +1,76 @@
+//===------ 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
+
+namespace llvm {
+class Type;
+class Instruction;
+class LoopInfo;
+class Loop;
+class ScalarEvolution;
+class SCEV;
+class Value;
+class PHINode;
+class Region;
+class Pass;
+class BasicBlock;
+}
+
+namespace polly {
+class Scop;
+/// Temporary Hack for extended regiontree.
+///
+/// @brief Cast the region to loop.
+///
+/// @param R  The Region to be casted.
+/// @param LI The LoopInfo to help the casting.
+///
+/// @return If there is a a loop that has the same entry and exit as the region,
+///         return the loop, otherwise, return null.
+llvm::Loop *castToLoop(const llvm::Region &R, llvm::LoopInfo &LI);
+
+/// @brief Check if the PHINode has any incoming Invoke edge.
+///
+/// @param PN The PHINode to check.
+///
+/// @return If the PHINode has an incoming BB that jumps to the parent BB
+///         of the PHINode with an invoke instruction, return true,
+///         otherwise, return false.
+bool hasInvokeEdge(const llvm::PHINode *PN);
+
+llvm::Value *getPointerOperand(llvm::Instruction &Inst);
+llvm::BasicBlock *createSingleExitEdge(llvm::Region *R, llvm::Pass *P);
+
+/// @brief Return the type of the access.
+llvm::Type *getAccessInstType(llvm::Instruction *AccInst);
+
+/// @brief Simplify the region in a SCoP to have a single unconditional entry
+///        edge and a single exit edge.
+///
+/// @param S  The SCoP that is simplified.
+/// @param P  The pass that is currently running.
+///
+/// @return The unique entering block for the region.
+llvm::BasicBlock *simplifyRegion(polly::Scop *S, llvm::Pass *P);
+
+/// @brief 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);
+}
+#endif
diff --git a/final/include/polly/Support/ScopLocation.h b/final/include/polly/Support/ScopLocation.h
new file mode 100644
index 0000000..83dc58e
--- /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 polly {
+
+/// @brief 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);
+}
+
+#endif // POLLY_SCOP_LOCATION_H
diff --git a/final/include/polly/TempScopInfo.h b/final/include/polly/TempScopInfo.h
new file mode 100644
index 0000000..829a5c8
--- /dev/null
+++ b/final/include/polly/TempScopInfo.h
@@ -0,0 +1,330 @@
+//===-------- polly/TempScopInfo.h - Extract TempScops ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Collect information about the control flow regions detected by the Scop
+// detection, such that this information can be translated info its polyhedral
+// representation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_TEMP_SCOP_EXTRACTION_H
+#define POLLY_TEMP_SCOP_EXTRACTION_H
+
+#include "polly/ScopDetection.h"
+#include "llvm/Analysis/RegionPass.h"
+#include "llvm/IR/Instructions.h"
+
+namespace llvm {
+class DataLayout;
+}
+
+using namespace llvm;
+
+namespace polly {
+
+//===---------------------------------------------------------------------===//
+/// @brief A memory access described by a SCEV expression and the access type.
+class IRAccess {
+public:
+  Value *BaseAddress;
+
+  const SCEV *Offset;
+
+  // The type of the scev affine function
+  enum TypeKind {
+    READ = 0x1,
+    MUST_WRITE = 0x2,
+    MAY_WRITE = 0x3,
+  };
+
+private:
+  unsigned ElemBytes;
+  TypeKind Type;
+  bool IsAffine;
+
+public:
+  SmallVector<const SCEV *, 4> Subscripts, Sizes;
+
+  explicit IRAccess(TypeKind Type, Value *BaseAddress, const SCEV *Offset,
+                    unsigned elemBytes, bool Affine)
+      : BaseAddress(BaseAddress), Offset(Offset), ElemBytes(elemBytes),
+        Type(Type), IsAffine(Affine) {}
+
+  explicit IRAccess(TypeKind Type, Value *BaseAddress, const SCEV *Offset,
+                    unsigned elemBytes, bool Affine,
+                    SmallVector<const SCEV *, 4> Subscripts,
+                    SmallVector<const SCEV *, 4> Sizes)
+      : BaseAddress(BaseAddress), Offset(Offset), ElemBytes(elemBytes),
+        Type(Type), IsAffine(Affine), Subscripts(Subscripts), Sizes(Sizes) {}
+
+  enum TypeKind getType() const { return Type; }
+
+  Value *getBase() const { return BaseAddress; }
+
+  const SCEV *getOffset() const { return Offset; }
+
+  unsigned getElemSizeInBytes() const { return ElemBytes; }
+
+  bool isAffine() const { return IsAffine; }
+
+  bool isRead() const { return Type == READ; }
+
+  bool isWrite() const { return Type == MUST_WRITE; }
+
+  void setMayWrite() { Type = MAY_WRITE; }
+
+  bool isMayWrite() const { return Type == MAY_WRITE; }
+
+  bool isScalar() const { return Subscripts.size() == 0; }
+
+  void print(raw_ostream &OS) const;
+};
+
+class Comparison {
+  const SCEV *LHS;
+  const SCEV *RHS;
+
+  ICmpInst::Predicate Pred;
+
+public:
+  Comparison(const SCEV *LHS, const SCEV *RHS, ICmpInst::Predicate Pred)
+      : LHS(LHS), RHS(RHS), Pred(Pred) {}
+
+  const SCEV *getLHS() const { return LHS; }
+  const SCEV *getRHS() const { return RHS; }
+
+  ICmpInst::Predicate getPred() const { return Pred; }
+  void print(raw_ostream &OS) const;
+};
+
+//===---------------------------------------------------------------------===//
+/// Types
+// The condition of a Basicblock, combine brcond with "And" operator.
+typedef SmallVector<Comparison, 4> BBCond;
+
+/// 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.
+typedef std::map<const Loop *, const SCEV *> LoopBoundMapType;
+
+/// Mapping BBs to its condition constrains
+typedef std::map<const BasicBlock *, BBCond> BBCondMapType;
+
+typedef std::vector<std::pair<IRAccess, Instruction *>> AccFuncSetType;
+typedef std::map<const BasicBlock *, AccFuncSetType> AccFuncMapType;
+
+//===---------------------------------------------------------------------===//
+/// @brief Scop represent with llvm objects.
+///
+/// A helper class for remembering the parameter number and the max depth in
+/// this Scop, and others context.
+class TempScop {
+  // The Region.
+  Region &R;
+
+  // Remember the bounds of loops, to help us build iteration domain of BBs.
+  const BBCondMapType &BBConds;
+
+  // Access function of bbs.
+  AccFuncMapType &AccFuncMap;
+
+  friend class TempScopInfo;
+
+  explicit TempScop(Region &r, BBCondMapType &BBCmps,
+                    AccFuncMapType &accFuncMap)
+      : R(r), BBConds(BBCmps), AccFuncMap(accFuncMap) {}
+
+public:
+  ~TempScop();
+
+  /// @brief Get the maximum Region contained by this Scop.
+  ///
+  /// @return The maximum Region contained by this Scop.
+  Region &getMaxRegion() const { return R; }
+
+  /// @brief Get the condition from entry block of the Scop to a BasicBlock
+  ///
+  /// @param BB The BasicBlock
+  ///
+  /// @return The condition from entry block of the Scop to a BB
+  ///
+  const BBCond *getBBCond(const BasicBlock *BB) const {
+    BBCondMapType::const_iterator at = BBConds.find(BB);
+    return at != BBConds.end() ? &(at->second) : 0;
+  }
+
+  /// @brief Get all access functions in a BasicBlock
+  ///
+  /// @param  BB The BasicBlock that containing the access functions.
+  ///
+  /// @return All access functions in BB
+  ///
+  AccFuncSetType *getAccessFunctions(const BasicBlock *BB) {
+    AccFuncMapType::iterator at = AccFuncMap.find(BB);
+    return at != AccFuncMap.end() ? &(at->second) : 0;
+  }
+  //@}
+
+  /// @brief Print the Temporary Scop information.
+  ///
+  /// @param OS The output stream the access functions is printed to.
+  /// @param SE The ScalarEvolution that help printing Temporary Scop
+  ///           information.
+  /// @param LI The LoopInfo that help printing the access functions.
+  void print(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI) const;
+
+  /// @brief Print the access functions and loop bounds in this Scop.
+  ///
+  /// @param OS The output stream the access functions is printed to.
+  /// @param SE The ScalarEvolution that help printing the access functions.
+  /// @param LI The LoopInfo that help printing the access functions.
+  void printDetail(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI,
+                   const Region *Reg, unsigned ind) const;
+};
+
+typedef std::map<const Region *, TempScop *> TempScopMapType;
+//===----------------------------------------------------------------------===//
+/// @brief The Function Pass to extract temporary information for Static control
+///        part in llvm function.
+///
+class TempScopInfo : public FunctionPass {
+  //===-------------------------------------------------------------------===//
+  TempScopInfo(const TempScopInfo &) = delete;
+  const TempScopInfo &operator=(const TempScopInfo &) = delete;
+
+  // The ScalarEvolution to help building Scop.
+  ScalarEvolution *SE;
+
+  // LoopInfo for information about loops
+  LoopInfo *LI;
+
+  // The AliasAnalysis to build AliasSetTracker.
+  AliasAnalysis *AA;
+
+  // Valid Regions for Scop
+  ScopDetection *SD;
+
+  // For condition extraction support.
+  DominatorTree *DT;
+  PostDominatorTree *PDT;
+
+  // Target data for element size computing.
+  const DataLayout *TD;
+
+  // And also Remember the constrains for BBs
+  BBCondMapType BBConds;
+
+  // Access function of statements (currently BasicBlocks) .
+  AccFuncMapType AccFuncMap;
+
+  // Pre-created zero for the scalar accesses, with it we do not need create a
+  // zero scev every time when we need it.
+  const SCEV *ZeroOffset;
+
+  // Mapping regions to the corresponding Scop in current function.
+  TempScopMapType TempScops;
+
+  // Clear the context.
+  void clear();
+
+  /// @brief Build condition constrains to BBs in a valid Scop.
+  ///
+  /// @param BB The BasicBlock to build condition constrains
+  /// @param R  The region for the current TempScop.
+  void buildCondition(BasicBlock *BB, Region &R);
+
+  // Build the affine function of the given condition
+  Comparison buildAffineCondition(Value &V, bool inverted);
+
+  // Return the temporary Scop information of Region R, where R must be a valid
+  // part of Scop
+  TempScop *getTempScop(Region &R);
+
+  // Build the temprory information of Region R, where R must be a valid part
+  // of Scop.
+  TempScop *buildTempScop(Region &R);
+
+  /// @brief Build an instance of IRAccess from the Load/Store instruction.
+  ///
+  /// @param Inst       The Load/Store instruction that access the memory
+  /// @param L          The parent loop of the instruction
+  /// @param R          The region on which we are going to build a TempScop
+  /// @param BoxedLoops The set of loops that are overapproximated in @p R.
+  ///
+  /// @return     The IRAccess to describe the access function of the
+  ///             instruction.
+  IRAccess buildIRAccess(Instruction *Inst, Loop *L, Region *R,
+                         const ScopDetection::BoxedLoopsSetTy *BoxedLoops);
+
+  /// @brief Analyze and extract the cross-BB scalar dependences (or,
+  ///        dataflow dependencies) of an instruction.
+  ///
+  /// @param Inst               The instruction to be analyzed
+  /// @param R                  The SCoP region
+  /// @param NonAffineSubRegion The non affine sub-region @p Inst is in.
+  ///
+  /// @return     True if the Instruction is used in other BB and a scalar write
+  ///             Access is required.
+  bool buildScalarDependences(Instruction *Inst, Region *R,
+                              Region *NonAffineSubRegio);
+
+  /// @brief Create IRAccesses for the given PHI node in the given region.
+  ///
+  /// @param PHI                The PHI node to be handled
+  /// @param R                  The SCoP region
+  /// @param Functions          The access functions of the current BB
+  /// @param NonAffineSubRegion The non affine sub-region @p PHI is in.
+  void buildPHIAccesses(PHINode *PHI, Region &R, AccFuncSetType &Functions,
+                        Region *NonAffineSubRegion);
+
+  /// @brief Build the access functions for the subregion @p SR.
+  ///
+  /// @param R  The SCoP region.
+  /// @param SR A subregion of @p R.
+  void buildAccessFunctions(Region &R, Region &SR);
+
+  /// @brief Build the access functions for the basic block @p BB
+  ///
+  /// @param R                  The SCoP region.
+  /// @param BB                 A basic block in @p R.
+  /// @param NonAffineSubRegion The non affine sub-region @p BB is in.
+  void buildAccessFunctions(Region &R, BasicBlock &BB,
+                            Region *NonAffineSubRegion = nullptr);
+
+public:
+  static char ID;
+  explicit TempScopInfo() : FunctionPass(ID) {}
+  ~TempScopInfo();
+
+  /// @brief Get the temporay Scop information in LLVM IR represent
+  ///        for Region R.
+  ///
+  /// @return The Scop information in LLVM IR represent.
+  TempScop *getTempScop(const Region *R) const;
+
+  /// @name FunctionPass interface
+  //@{
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
+  virtual void releaseMemory() { clear(); }
+  virtual bool runOnFunction(Function &F);
+  virtual void print(raw_ostream &OS, const Module *) const;
+  //@}
+};
+
+} // end namespace polly
+
+namespace llvm {
+class PassRegistry;
+void initializeTempScopInfoPass(llvm::PassRegistry &);
+}
+
+#endif
diff --git a/final/lib/Analysis/DependenceInfo.cpp b/final/lib/Analysis/DependenceInfo.cpp
new file mode 100644
index 0000000..9dd745c
--- /dev/null
+++ b/final/lib/Analysis/DependenceInfo.cpp
@@ -0,0 +1,681 @@
+//===- 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));
+
+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"),
+               clEnumValEnd),
+    cl::Hidden, cl::init(VALUE_BASED_ANALYSIS), cl::ZeroOrMore,
+    cl::cat(PollyCategory));
+
+//===----------------------------------------------------------------------===//
+
+/// @brief Collect information about the SCoP @p S.
+static void collectInfo(Scop &S, isl_union_map **Read, isl_union_map **Write,
+                        isl_union_map **MayWrite,
+                        isl_union_map **AccessSchedule,
+                        isl_union_map **StmtSchedule) {
+  isl_space *Space = S.getParamSpace();
+  *Read = isl_union_map_empty(isl_space_copy(Space));
+  *Write = isl_union_map_empty(isl_space_copy(Space));
+  *MayWrite = isl_union_map_empty(isl_space_copy(Space));
+  *AccessSchedule = isl_union_map_empty(isl_space_copy(Space));
+  *StmtSchedule = isl_union_map_empty(Space);
+
+  SmallPtrSet<const Value *, 8> ReductionBaseValues;
+  for (ScopStmt &Stmt : S)
+    for (MemoryAccess *MA : Stmt)
+      if (MA->isReductionLike())
+        ReductionBaseValues.insert(MA->getBaseAddr());
+
+  for (ScopStmt &Stmt : S) {
+    for (MemoryAccess *MA : Stmt) {
+      isl_set *domcp = Stmt.getDomain();
+      isl_map *accdom = MA->getAccessRelation();
+
+      accdom = isl_map_intersect_domain(accdom, domcp);
+
+      if (ReductionBaseValues.count(MA->getBaseAddr())) {
+        // 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]
+        //
+        // The original schedule looks like
+        //   Stmt[i0, i1] -> [0, i0, 2, i1, 0]
+        // but as we transformed the access domain we need the schedule
+        // to match the new access domains, thus we need
+        //   [Stmt[i0, i1] -> MemAcc_A[i0 + i1]] -> [0, i0, 2, i1, 0]
+        isl_map *Schedule = Stmt.getSchedule();
+        Schedule = isl_map_apply_domain(
+            Schedule,
+            isl_map_reverse(isl_map_domain_map(isl_map_copy(accdom))));
+        accdom = isl_map_range_map(accdom);
+        *AccessSchedule = isl_union_map_add_map(*AccessSchedule, Schedule);
+      }
+
+      if (MA->isRead())
+        *Read = isl_union_map_add_map(*Read, accdom);
+      else
+        *Write = isl_union_map_add_map(*Write, accdom);
+    }
+    *StmtSchedule = isl_union_map_add_map(*StmtSchedule, Stmt.getSchedule());
+  }
+
+  *StmtSchedule =
+      isl_union_map_intersect_params(*StmtSchedule, S.getAssumedContext());
+}
+
+/// @brief 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;
+}
+
+/// @brief 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), 0);
+
+  // 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);
+}
+
+void Dependences::calculateDependences(Scop &S) {
+  isl_union_map *Read, *Write, *MayWrite, *AccessSchedule, *StmtSchedule;
+  isl_schedule *Schedule;
+
+  DEBUG(dbgs() << "Scop: \n" << S << "\n");
+
+  collectInfo(S, &Read, &Write, &MayWrite, &AccessSchedule, &StmtSchedule);
+
+  // TODO: Compute dependences directly on the schedule tree
+  //
+  // We currently don't do this yet, as the compile-time performance
+  // implications are not 100% understood (we see some regressions).
+  if (false && isl_union_map_is_empty(AccessSchedule)) {
+    isl_union_map_free(AccessSchedule);
+    Schedule = S.getScheduleTree();
+  } else {
+    auto *ScheduleMap =
+        isl_union_map_union(AccessSchedule, isl_union_map_copy(StmtSchedule));
+    Schedule = isl_schedule_from_domain(
+        isl_union_map_domain(isl_union_map_copy(ScheduleMap)));
+    if (!isl_union_map_is_empty(ScheduleMap))
+      Schedule = isl_schedule_insert_partial_schedule(
+          Schedule, isl_multi_union_pw_aff_from_union_map(ScheduleMap));
+    else
+      isl_union_map_free(ScheduleMap);
+  }
+
+  Read = isl_union_map_coalesce(Read);
+  Write = isl_union_map_coalesce(Write);
+  MayWrite = isl_union_map_coalesce(MayWrite);
+
+  long MaxOpsOld = isl_ctx_get_max_operations(S.getIslCtx());
+  if (OptComputeOut)
+    isl_ctx_set_max_operations(S.getIslCtx(), OptComputeOut);
+  isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_CONTINUE);
+
+  DEBUG(dbgs() << "Read: " << Read << "\n";
+        dbgs() << "Write: " << Write << "\n";
+        dbgs() << "MayWrite: " << MayWrite << "\n");
+
+  RAW = WAW = WAR = RED = nullptr;
+
+  if (OptAnalysisType == VALUE_BASED_ANALYSIS) {
+    isl_union_access_info *AI;
+    isl_union_flow *Flow;
+
+    AI = isl_union_access_info_from_sink(isl_union_map_copy(Read));
+    AI = isl_union_access_info_set_must_source(AI, isl_union_map_copy(Write));
+    AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(MayWrite));
+    AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule));
+    Flow = isl_union_access_info_compute_flow(AI);
+
+    RAW = isl_union_flow_get_must_dependence(Flow);
+    isl_union_flow_free(Flow);
+
+    AI = isl_union_access_info_from_sink(isl_union_map_copy(Write));
+    AI = isl_union_access_info_set_must_source(AI, isl_union_map_copy(Write));
+    AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(Read));
+    AI = isl_union_access_info_set_schedule(AI, Schedule);
+    Flow = isl_union_access_info_compute_flow(AI);
+
+    WAW = isl_union_flow_get_must_dependence(Flow);
+    WAR = isl_union_flow_get_may_dependence(Flow);
+
+    // This subtraction is needed to obtain the same results as were given by
+    // isl_union_map_compute_flow. For large sets this may add some compile-time
+    // cost. As there does not seem to be a need to distinguish between WAW and
+    // WAR, refactoring Polly to only track general non-flow dependences may
+    // improve performance.
+    WAR = isl_union_map_subtract(WAR, isl_union_map_copy(WAW));
+    isl_union_flow_free(Flow);
+  } else {
+    isl_union_access_info *AI;
+    isl_union_flow *Flow;
+
+    Write = isl_union_map_union(Write, isl_union_map_copy(MayWrite));
+
+    AI = isl_union_access_info_from_sink(isl_union_map_copy(Read));
+    AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(Write));
+    AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule));
+    Flow = isl_union_access_info_compute_flow(AI);
+
+    RAW = isl_union_flow_get_may_dependence(Flow);
+    isl_union_flow_free(Flow);
+
+    AI = isl_union_access_info_from_sink(isl_union_map_copy(Write));
+    AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(Read));
+    AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule));
+    Flow = isl_union_access_info_compute_flow(AI);
+
+    WAR = isl_union_flow_get_may_dependence(Flow);
+    isl_union_flow_free(Flow);
+
+    AI = isl_union_access_info_from_sink(isl_union_map_copy(Write));
+    AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(Write));
+    AI = isl_union_access_info_set_schedule(AI, Schedule);
+    Flow = isl_union_access_info_compute_flow(AI);
+
+    WAW = isl_union_flow_get_may_dependence(Flow);
+    isl_union_flow_free(Flow);
+  }
+
+  isl_union_map_free(MayWrite);
+  isl_union_map_free(Write);
+  isl_union_map_free(Read);
+
+  RAW = isl_union_map_coalesce(RAW);
+  WAW = isl_union_map_coalesce(WAW);
+  WAR = isl_union_map_coalesce(WAR);
+
+  if (isl_ctx_last_error(S.getIslCtx()) == isl_error_quota) {
+    isl_union_map_free(RAW);
+    isl_union_map_free(WAW);
+    isl_union_map_free(WAR);
+    RAW = WAW = WAR = nullptr;
+    isl_ctx_reset_error(S.getIslCtx());
+  }
+  isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_ABORT);
+  isl_ctx_reset_operations(S.getIslCtx());
+  isl_ctx_set_max_operations(S.getIslCtx(), MaxOpsOld);
+
+  isl_union_map *STMT_RAW, *STMT_WAW, *STMT_WAR;
+  STMT_RAW = isl_union_map_intersect_domain(
+      isl_union_map_copy(RAW),
+      isl_union_map_domain(isl_union_map_copy(StmtSchedule)));
+  STMT_WAW = isl_union_map_intersect_domain(
+      isl_union_map_copy(WAW),
+      isl_union_map_domain(isl_union_map_copy(StmtSchedule)));
+  STMT_WAR = isl_union_map_intersect_domain(isl_union_map_copy(WAR),
+                                            isl_union_map_domain(StmtSchedule));
+  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 and WAW dependences by subtracting the actual
+  //    reduction dependences. Binary reductions (sum += A[i]) cause both, and
+  //    the same, RAW and WAW 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());
+      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, isl_union_map_copy(WAW));
+
+  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));
+
+    // 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());
+      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();
+  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();
+    else
+      StmtScat = isl_map_copy((*NewSchedule)[&Stmt]);
+
+    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_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_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;
+}
+
+void DependenceInfo::recomputeDependences() {
+  releaseMemory();
+  D.calculateDependences(*S);
+}
+
+bool DependenceInfo::runOnScop(Scop &ScopVar) {
+  S = &ScopVar;
+  recomputeDependences();
+  return false;
+}
+
+void DependenceInfo::getAnalysisUsage(AnalysisUsage &AU) const {
+  ScopPass::getAnalysisUsage(AU);
+}
+
+char DependenceInfo::ID = 0;
+
+Pass *polly::createDependenceInfoPass() { return new DependenceInfo(); }
+
+INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences",
+                      "Polly - Calculate dependences", false, false);
+INITIALIZE_PASS_DEPENDENCY(ScopInfo);
+INITIALIZE_PASS_END(DependenceInfo, "polly-dependences",
+                    "Polly - Calculate dependences", false, false)
diff --git a/final/lib/Analysis/ScopDetection.cpp b/final/lib/Analysis/ScopDetection.cpp
new file mode 100644
index 0000000..36792e5
--- /dev/null
+++ b/final/lib/Analysis/ScopDetection.cpp
@@ -0,0 +1,1123 @@
+//===----- ScopDetection.cpp  - 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 fullfills 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.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopDetectionDiagnostic.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "polly/Support/ScopLocation.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/RegionIterator.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/Debug.h"
+#include <set>
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-detect"
+
+static cl::opt<bool>
+    DetectScopsWithoutLoops("polly-detect-scops-in-functions-without-loops",
+                            cl::desc("Detect scops in functions without loops"),
+                            cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                            cl::cat(PollyCategory));
+
+static cl::opt<bool>
+    DetectRegionsWithoutLoops("polly-detect-scops-in-regions-without-loops",
+                              cl::desc("Detect scops in regions without loops"),
+                              cl::Hidden, cl::init(false), cl::ZeroOrMore,
+                              cl::cat(PollyCategory));
+
+static cl::opt<bool> DetectUnprofitable("polly-detect-unprofitable",
+                                        cl::desc("Detect unprofitable scops"),
+                                        cl::Hidden, cl::init(false),
+                                        cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<std::string> OnlyFunction(
+    "polly-only-func",
+    cl::desc("Only run on functions that contain a certain string"),
+    cl::value_desc("string"), cl::ValueRequired, cl::init(""),
+    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::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>
+    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> 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> AllowUnsigned("polly-allow-unsigned",
+                                   cl::desc("Allow unsigned expressions"),
+                                   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::PollyTrackFailures = false;
+bool polly::PollyDelinearize = false;
+StringRef polly::PollySkipFnAttr = "polly.skip.fn";
+
+//===----------------------------------------------------------------------===//
+// Statistics.
+
+STATISTIC(ValidRegion, "Number of regions that a valid part of Scop");
+
+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) {}
+
+  virtual void print(DiagnosticPrinter &DP) const;
+
+  static bool classof(const DiagnosticInfo *DI) {
+    return DI->getKind() == PluginDiagnosticKind;
+  }
+};
+
+int DiagnosticScopFound::PluginDiagnosticKind = 10;
+
+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";
+}
+
+//===----------------------------------------------------------------------===//
+// ScopDetection.
+
+ScopDetection::ScopDetection() : FunctionPass(ID) {
+  if (!PollyUseRuntimeAliasChecks)
+    return;
+
+  // Disable runtime alias checks if we ignore aliasing all together.
+  if (IgnoreAliasing) {
+    PollyUseRuntimeAliasChecks = false;
+    return;
+  }
+
+  if (AllowNonAffine) {
+    DEBUG(errs() << "WARNING: We disable runtime alias checks as non affine "
+                    "accesses are enabled.\n");
+    PollyUseRuntimeAliasChecks = false;
+  }
+}
+
+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) {
+    BoxedLoopsSetTy DummyBoxedLoopsSet;
+    NonAffineSubRegionSetTy DummyNonAffineSubRegionSet;
+    DetectionContext Context(const_cast<Region &>(R), *AA,
+                             DummyNonAffineSubRegionSet, DummyBoxedLoopsSet,
+                             false /*verifying*/);
+    return isValidRegion(Context);
+  }
+
+  return true;
+}
+
+std::string ScopDetection::regionIsInvalidBecause(const Region *R) const {
+  if (!RejectLogs.count(R))
+    return "";
+
+  // Get the first error we found. Even in keep-going mode, this is the first
+  // reason that caused the candidate to be rejected.
+  RejectLog Errors = RejectLogs.at(R);
+
+  // This can happen when we marked a region invalid, but didn't track
+  // an error for it.
+  if (Errors.size() == 0)
+    return "";
+
+  RejectReasonPtr RR = *Errors.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::isValidCFG(BasicBlock &BB,
+                               DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  TerminatorInst *TI = BB.getTerminator();
+
+  // Return instructions are only valid if the region is the top level region.
+  if (isa<ReturnInst>(TI) && !CurRegion.getExit() && TI->getNumOperands() == 0)
+    return true;
+
+  BranchInst *Br = dyn_cast<BranchInst>(TI);
+
+  if (!Br)
+    return invalid<ReportNonBranchTerminator>(Context, /*Assert=*/true, &BB);
+
+  if (Br->isUnconditional())
+    return true;
+
+  Value *Condition = Br->getCondition();
+
+  // UndefValue is not allowed as condition.
+  if (isa<UndefValue>(Condition))
+    return invalid<ReportUndefCond>(Context, /*Assert=*/true, Br, &BB);
+
+  // Only Constant and ICmpInst are allowed as condition.
+  if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition))) {
+    if (!AllowNonAffineSubRegions ||
+        !addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
+      return invalid<ReportInvalidCond>(Context, /*Assert=*/true, Br, &BB);
+  }
+
+  // Allow perfectly nested conditions.
+  assert(Br->getNumSuccessors() == 2 && "Unexpected number of successors");
+
+  if (ICmpInst *ICmp = dyn_cast<ICmpInst>(Condition)) {
+    // Unsigned comparisons are not allowed. They trigger overflow problems
+    // in the code generation.
+    //
+    // TODO: This is not sufficient and just hides bugs. However it does pretty
+    // well.
+    if (ICmp->isUnsigned() && !AllowUnsigned)
+      return invalid<ReportUnsignedCond>(Context, /*Assert=*/true, Br, &BB);
+
+    // 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(ICmp->getParent());
+    const SCEV *LHS = SE->getSCEVAtScope(ICmp->getOperand(0), L);
+    const SCEV *RHS = SE->getSCEVAtScope(ICmp->getOperand(1), L);
+
+    if (!isAffineExpr(&CurRegion, LHS, *SE) ||
+        !isAffineExpr(&CurRegion, RHS, *SE)) {
+      if (!AllowNonAffineSubRegions ||
+          !addOverApproximatedRegion(RI->getRegionFor(&BB), Context))
+        return invalid<ReportNonAffBranch>(Context, /*Assert=*/true, &BB, LHS,
+                                           RHS, ICmp);
+    }
+  }
+
+  // Allow loop exit conditions.
+  Loop *L = LI->getLoopFor(&BB);
+  if (L && L->getExitingBlock() == &BB)
+    return true;
+
+  // Allow perfectly nested conditions.
+  Region *R = RI->getRegionFor(&BB);
+  if (R->getEntry() != &BB)
+    return invalid<ReportCondition>(Context, /*Assert=*/true, &BB);
+
+  return true;
+}
+
+bool ScopDetection::isValidCallInst(CallInst &CI) {
+  if (CI.doesNotReturn())
+    return false;
+
+  if (CI.doesNotAccessMemory())
+    return true;
+
+  Function *CalledFunction = CI.getCalledFunction();
+
+  // Indirect calls are not supported.
+  if (CalledFunction == 0)
+    return false;
+
+  // Check if we can handle the intrinsic call.
+  if (auto *IT = dyn_cast<IntrinsicInst>(&CI)) {
+    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:
+    case llvm::Intrinsic::expect:
+      return true;
+    default:
+      // Other intrinsics which may access the memory are not yet supported.
+      break;
+    }
+  }
+
+  return false;
+}
+
+bool ScopDetection::isInvariant(const Value &Val, const Region &Reg) const {
+  // A reference to function argument or constant value is invariant.
+  if (isa<Argument>(Val) || isa<Constant>(Val))
+    return true;
+
+  const Instruction *I = dyn_cast<Instruction>(&Val);
+  if (!I)
+    return false;
+
+  if (!Reg.contains(I))
+    return true;
+
+  if (I->mayHaveSideEffects())
+    return false;
+
+  // When Val is a Phi node, it is likely not invariant. We do not check whether
+  // Phi nodes are actually invariant, we assume that Phi nodes are usually not
+  // invariant. Recursively checking the operators of Phi nodes would lead to
+  // infinite recursion.
+  if (isa<PHINode>(*I))
+    return false;
+
+  for (const Use &Operand : I->operands())
+    if (!isInvariant(*Operand, Reg))
+      return false;
+
+  // When the instruction is a load instruction, check that no write to memory
+  // in the region aliases with the load.
+  if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {
+    auto Loc = MemoryLocation::get(LI);
+
+    // Check if any basic block in the region can modify the location pointed to
+    // by 'Loc'.  If so, 'Val' is (likely) not invariant in the region.
+    for (const BasicBlock *BB : Reg.blocks())
+      if (AA->canBasicBlockModify(*BB, Loc))
+        return false;
+  }
+
+  return true;
+}
+
+MapInsnToMemAcc InsnToMemAcc;
+
+bool ScopDetection::hasAffineMemoryAccesses(DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  for (const SCEVUnknown *BasePointer : Context.NonAffineAccesses) {
+    Value *BaseValue = BasePointer->getValue();
+    auto Shape = std::shared_ptr<ArrayShape>(new ArrayShape(BasePointer));
+    bool BasePtrHasNonAffine = false;
+
+    // First step: collect parametric terms in all array references.
+    SmallVector<const SCEV *, 4> Terms;
+    for (const auto &Pair : Context.Accesses[BasePointer]) {
+      if (auto *AF = dyn_cast<SCEVAddRecExpr>(Pair.second))
+        SE->collectParametricTerms(AF, Terms);
+
+      // 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;
+            bool TermsHasInRegionInst = false;
+
+            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
+                    TermsHasInRegionInst = true;
+
+                } else {
+                  Operands.push_back(MulOp);
+                }
+              }
+            }
+            Terms.push_back(SE->getMulExpr(Operands));
+          }
+        }
+      }
+    }
+
+    // Second step: find array shape.
+    SE->findArrayDimensions(Terms, Shape->DelinearizedSizes,
+                            Context.ElementSize[BasePointer]);
+
+    if (!AllowNonAffine)
+      for (const SCEV *DelinearizedSize : Shape->DelinearizedSizes)
+        if (hasScalarDepsInsideRegion(DelinearizedSize, &CurRegion))
+          invalid<ReportNonAffineAccess>(
+              Context, /*Assert=*/true, DelinearizedSize,
+              Context.Accesses[BasePointer].front().first, BaseValue);
+
+    // No array shape derived.
+    if (Shape->DelinearizedSizes.empty()) {
+      if (AllowNonAffine)
+        continue;
+
+      for (const auto &Pair : Context.Accesses[BasePointer]) {
+        const Instruction *Insn = Pair.first;
+        const SCEV *AF = Pair.second;
+
+        if (!isAffineExpr(&CurRegion, AF, *SE, BaseValue)) {
+          invalid<ReportNonAffineAccess>(Context, /*Assert=*/true, AF, Insn,
+                                         BaseValue);
+          if (!KeepGoing)
+            return false;
+        }
+      }
+      continue;
+    }
+
+    // Third step: compute the access functions for each subscript.
+    //
+    // 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.
+    MapInsnToMemAcc TempMemoryAccesses;
+    for (const auto &Pair : Context.Accesses[BasePointer]) {
+      const Instruction *Insn = Pair.first;
+      auto *AF = Pair.second;
+      bool IsNonAffine = false;
+      TempMemoryAccesses.insert(std::make_pair(Insn, MemAcc(Insn, Shape)));
+      MemAcc *Acc = &TempMemoryAccesses.find(Insn)->second;
+
+      if (!AF) {
+        if (isAffineExpr(&CurRegion, Pair.second, *SE, BaseValue))
+          Acc->DelinearizedSubscripts.push_back(Pair.second);
+        else
+          IsNonAffine = true;
+      } else {
+        SE->computeAccessFunctions(AF, Acc->DelinearizedSubscripts,
+                                   Shape->DelinearizedSizes);
+        if (Acc->DelinearizedSubscripts.size() == 0)
+          IsNonAffine = true;
+        for (const SCEV *S : Acc->DelinearizedSubscripts)
+          if (!isAffineExpr(&CurRegion, S, *SE, BaseValue))
+            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)
+      InsnToMemAcc.insert(TempMemoryAccesses.begin(), TempMemoryAccesses.end());
+  }
+  return true;
+}
+
+bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
+                                        DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  Value *Ptr = getPointerOperand(Inst);
+  Loop *L = LI->getLoopFor(Inst.getParent());
+  const SCEV *AccessFunction = SE->getSCEVAtScope(Ptr, L);
+  const SCEVUnknown *BasePointer;
+  Value *BaseValue;
+
+  BasePointer = dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
+
+  if (!BasePointer)
+    return invalid<ReportNoBasePtr>(Context, /*Assert=*/true, &Inst);
+
+  BaseValue = BasePointer->getValue();
+
+  if (isa<UndefValue>(BaseValue))
+    return invalid<ReportUndefBasePtr>(Context, /*Assert=*/true, &Inst);
+
+  // Check that the base address of the access is invariant in the current
+  // region.
+  if (!isInvariant(*BaseValue, CurRegion))
+    // Verification of this property is difficult as the independent blocks
+    // pass may introduce aliasing that we did not have when running the
+    // scop detection.
+    return invalid<ReportVariantBasePtr>(Context, /*Assert=*/false, BaseValue,
+                                         &Inst);
+
+  AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
+
+  const SCEV *Size = SE->getElementSize(&Inst);
+  if (Context.ElementSize.count(BasePointer)) {
+    if (Context.ElementSize[BasePointer] != Size)
+      return invalid<ReportDifferentArrayElementSize>(Context, /*Assert=*/true,
+                                                      &Inst, BaseValue);
+  } else {
+    Context.ElementSize[BasePointer] = Size;
+  }
+
+  bool isVariantInNonAffineLoop = false;
+  SetVector<const Loop *> Loops;
+  findLoops(AccessFunction, Loops);
+  for (const Loop *L : Loops)
+    if (Context.BoxedLoopsSet.count(L))
+      isVariantInNonAffineLoop = true;
+
+  if (PollyDelinearize && !isVariantInNonAffineLoop) {
+    Context.Accesses[BasePointer].push_back({&Inst, AccessFunction});
+
+    if (!isAffineExpr(&CurRegion, AccessFunction, *SE, BaseValue))
+      Context.NonAffineAccesses.insert(BasePointer);
+  } else if (!AllowNonAffine) {
+    if (isVariantInNonAffineLoop ||
+        !isAffineExpr(&CurRegion, AccessFunction, *SE, BaseValue))
+      return invalid<ReportNonAffineAccess>(Context, /*Assert=*/true,
+                                            AccessFunction, &Inst, BaseValue);
+  }
+
+  // FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
+  // created by IndependentBlocks Pass.
+  if (IntToPtrInst *Inst = dyn_cast<IntToPtrInst>(BaseValue))
+    return invalid<ReportIntToPtr>(Context, /*Assert=*/true, Inst);
+
+  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(
+      BaseValue, MemoryLocation::UnknownSize, AATags);
+
+  // INVALID triggers an assertion in verifying mode, if it detects that a
+  // SCoP was detected by SCoP detection and that this SCoP was invalidated by
+  // a pass that stated it would preserve the SCoPs. We disable this check as
+  // the independent blocks pass may create memory references which seem to
+  // alias, if -basicaa is not available. They actually do not, but as we can
+  // not proof this without -basicaa we would fail. We disable this check to
+  // not cause irrelevant verification failures.
+  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.
+      for (const auto &Ptr : AS) {
+        Instruction *Inst = dyn_cast<Instruction>(Ptr.getValue());
+        if (Inst && CurRegion.contains(Inst)) {
+          CanBuildRunTimeCheck = false;
+          break;
+        }
+      }
+
+      if (CanBuildRunTimeCheck)
+        return true;
+    }
+    return invalid<ReportAlias>(Context, /*Assert=*/false, &Inst, AS);
+  }
+
+  return true;
+}
+
+bool ScopDetection::isValidInstruction(Instruction &Inst,
+                                       DetectionContext &Context) const {
+  // We only check the call instruction but not invoke instruction.
+  if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
+    if (isValidCallInst(*CI))
+      return true;
+
+    return invalid<ReportFuncCall>(Context, /*Assert=*/true, &Inst);
+  }
+
+  if (!Inst.mayWriteToMemory() && !Inst.mayReadFromMemory()) {
+    if (!isa<AllocaInst>(Inst))
+      return true;
+
+    return invalid<ReportAlloca>(Context, /*Assert=*/true, &Inst);
+  }
+
+  // Check the access function.
+  if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst)) {
+    Context.hasStores |= isa<StoreInst>(Inst);
+    Context.hasLoads |= isa<LoadInst>(Inst);
+    return isValidMemoryAccess(Inst, Context);
+  }
+
+  // We do not know this instruction, therefore we assume it is invalid.
+  return invalid<ReportUnknownInst>(Context, /*Assert=*/true, &Inst);
+}
+
+bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
+  // Is the loop count affine?
+  const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
+  if (isAffineExpr(&Context.CurRegion, LoopCount, *SE)) {
+    Context.hasAffineLoops = true;
+    return true;
+  }
+
+  if (AllowNonAffineSubRegions) {
+    Region *R = RI->getRegionFor(L->getHeader());
+    if (R->contains(L))
+      if (addOverApproximatedRegion(R, Context))
+        return true;
+  }
+
+  return invalid<ReportLoopBound>(Context, /*Assert=*/true, L, LoopCount);
+}
+
+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) {
+    DetectionContext Context(
+        *ExpandedRegion, *AA, NonAffineSubRegionMap[ExpandedRegion.get()],
+        BoxedLoopsMap[ExpandedRegion.get()], false /* verifying */);
+    DEBUG(dbgs() << "\t\tTrying " << ExpandedRegion->getNameStr() << "\n");
+    // Only expand when we did not collect errors.
+
+    // Check the exit first (cheap)
+    if (isValidExit(Context) && !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())
+        break;
+
+      // Store this region, because it is the greatest valid (encountered so
+      // far).
+      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)
+      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;
+}
+
+// Remove all direct and indirect children of region R from the region set Regs,
+// but do not recurse further if the first child has been found.
+//
+// Return the number of regions erased from Regs.
+static unsigned eraseAllChildren(ScopDetection::RegionSet &Regs,
+                                 const Region &R) {
+  unsigned Count = 0;
+  for (auto &SubRegion : R) {
+    if (Regs.count(SubRegion.get())) {
+      ++Count;
+      Regs.remove(SubRegion.get());
+    } else {
+      Count += eraseAllChildren(Regs, *SubRegion);
+    }
+  }
+  return Count;
+}
+
+void ScopDetection::findScops(Region &R) {
+  DetectionContext Context(R, *AA, NonAffineSubRegionMap[&R], BoxedLoopsMap[&R],
+                           false /*verifying*/);
+
+  bool RegionIsValid = false;
+  if (!DetectRegionsWithoutLoops && regionWithoutLoops(R, LI))
+    invalid<ReportUnprofitable>(Context, /*Assert=*/true, &R);
+  else
+    RegionIsValid = isValidRegion(Context);
+
+  bool HasErrors = !RegionIsValid || Context.Log.size() > 0;
+
+  if (PollyTrackFailures && HasErrors)
+    RejectLogs.insert(std::make_pair(&R, Context.Log));
+
+  if (!HasErrors) {
+    ++ValidRegion;
+    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 regions that had errors.
+    bool HadErrors = RejectLogs.hasErrors(CurrentRegion);
+    if (HadErrors)
+      continue;
+
+    // Skip invalid regions. Regions may become invalid, if they are element of
+    // an already expanded region.
+    if (!ValidRegions.count(CurrentRegion))
+      continue;
+
+    Region *ExpandedR = expandRegion(*CurrentRegion);
+
+    if (!ExpandedR)
+      continue;
+
+    R.addSubRegion(ExpandedR, true);
+    ValidRegions.insert(ExpandedR);
+    ValidRegions.remove(CurrentRegion);
+
+    // Erase all (direct and indirect) children of ExpandedR from the valid
+    // regions and update the number of valid regions.
+    ValidRegion -= eraseAllChildren(ValidRegions, *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 && (!isValidLoop(L, Context) && !KeepGoing))
+      return false;
+  }
+
+  for (BasicBlock *BB : CurRegion.blocks())
+    if (!isValidCFG(*BB, Context) && !KeepGoing)
+      return false;
+
+  for (BasicBlock *BB : CurRegion.blocks())
+    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::isValidExit(DetectionContext &Context) const {
+
+  // PHI nodes are not allowed in the exit basic block.
+  if (BasicBlock *Exit = Context.CurRegion.getExit()) {
+    BasicBlock::iterator I = Exit->begin();
+    if (I != Exit->end() && isa<PHINode>(*I))
+      return invalid<ReportPHIinExit>(Context, /*Assert=*/true, I);
+  }
+
+  return true;
+}
+
+bool ScopDetection::isValidRegion(DetectionContext &Context) const {
+  Region &CurRegion = Context.CurRegion;
+
+  DEBUG(dbgs() << "Checking region: " << CurRegion.getNameStr() << "\n\t");
+
+  if (CurRegion.isTopLevelRegion()) {
+    DEBUG(dbgs() << "Top level region is invalid\n");
+    return false;
+  }
+
+  if (!CurRegion.getEntry()->getName().count(OnlyRegion)) {
+    DEBUG({
+      dbgs() << "Region entry does not match -polly-region-only";
+      dbgs() << "\n";
+    });
+    return false;
+  }
+
+  if (!CurRegion.getEnteringBlock()) {
+    BasicBlock *entry = CurRegion.getEntry();
+    Loop *L = LI->getLoopFor(entry);
+
+    if (L) {
+      if (!L->isLoopSimplifyForm())
+        return invalid<ReportSimpleLoop>(Context, /*Assert=*/true);
+
+      for (pred_iterator PI = pred_begin(entry), PE = pred_end(entry); PI != PE;
+           ++PI) {
+        // Region entering edges come from the same loop but outside the region
+        // are not allowed.
+        if (L->contains(*PI) && !CurRegion.contains(*PI))
+          return invalid<ReportIndEdge>(Context, /*Assert=*/true, *PI);
+      }
+    }
+  }
+
+  // SCoP cannot contain the entry block of the function, because we need
+  // to insert alloca instruction there when translate scalar to array.
+  if (CurRegion.getEntry() ==
+      &(CurRegion.getEntry()->getParent()->getEntryBlock()))
+    return invalid<ReportEntry>(Context, /*Assert=*/true, CurRegion.getEntry());
+
+  if (!isValidExit(Context))
+    return false;
+
+  if (!allBlocksValid(Context))
+    return false;
+
+  // We can probably not do a lot on scops that only write or only read
+  // data.
+  if (!DetectUnprofitable && (!Context.hasStores || !Context.hasLoads))
+    invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
+
+  // Check if there was at least one non-overapproximated loop in the region or
+  // we allow regions without loops.
+  if (!DetectRegionsWithoutLoops && !Context.hasAffineLoops)
+    invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
+
+  DEBUG(dbgs() << "OK\n");
+  return true;
+}
+
+void ScopDetection::markFunctionAsInvalid(Function *F) const {
+  F->addFnAttr(PollySkipFnAttr);
+}
+
+bool ScopDetection::isValidFunction(llvm::Function &F) {
+  return !F.hasFnAttribute(PollySkipFnAttr);
+}
+
+void ScopDetection::printLocations(llvm::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::emitMissedRemarksForValidRegions(
+    const Function &F, const RegionSet &ValidRegions) {
+  for (const Region *R : ValidRegions) {
+    const Region *Parent = R->getParent();
+    if (Parent && !Parent->isTopLevelRegion() && RejectLogs.count(Parent))
+      emitRejectionRemarks(F, RejectLogs.at(Parent));
+  }
+}
+
+void ScopDetection::emitMissedRemarksForLeaves(const Function &F,
+                                               const Region *R) {
+  for (const std::unique_ptr<Region> &Child : *R) {
+    bool IsValid = ValidRegions.count(Child.get());
+    if (IsValid)
+      continue;
+
+    bool IsLeaf = Child->begin() == Child->end();
+    if (!IsLeaf)
+      emitMissedRemarksForLeaves(F, Child.get());
+    else {
+      if (RejectLogs.count(Child.get())) {
+        emitRejectionRemarks(F, RejectLogs.at(Child.get()));
+      }
+    }
+  }
+}
+
+bool ScopDetection::runOnFunction(llvm::Function &F) {
+  LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  RI = &getAnalysis<RegionInfoPass>().getRegionInfo();
+  if (!DetectScopsWithoutLoops && LI->empty())
+    return false;
+
+  AA = &getAnalysis<AliasAnalysis>();
+  SE = &getAnalysis<ScalarEvolution>();
+  Region *TopRegion = RI->getTopLevelRegion();
+
+  releaseMemory();
+
+  if (OnlyFunction != "" && !F.getName().count(OnlyFunction))
+    return false;
+
+  if (!isValidFunction(F))
+    return false;
+
+  findScops(*TopRegion);
+
+  // Only makes sense when we tracked errors.
+  if (PollyTrackFailures) {
+    emitMissedRemarksForValidRegions(F, ValidRegions);
+    emitMissedRemarksForLeaves(F, TopRegion);
+  }
+
+  for (const Region *R : ValidRegions)
+    emitValidRemarks(F, R);
+
+  if (ReportLevel)
+    printLocations(F);
+
+  return false;
+}
+
+bool ScopDetection::isNonAffineSubRegion(const Region *SubR,
+                                         const Region *ScopR) const {
+  return NonAffineSubRegionMap.lookup(ScopR).count(SubR);
+}
+
+const ScopDetection::BoxedLoopsSetTy *
+ScopDetection::getBoxedLoops(const Region *R) const {
+  auto BLMIt = BoxedLoopsMap.find(R);
+  if (BLMIt == BoxedLoopsMap.end())
+    return nullptr;
+  return &BLMIt->second;
+}
+
+void polly::ScopDetection::verifyRegion(const Region &R) const {
+  assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
+
+  BoxedLoopsSetTy DummyBoxedLoopsSet;
+  NonAffineSubRegionSetTy DummyNonAffineSubRegionSet;
+  DetectionContext Context(const_cast<Region &>(R), *AA,
+                           DummyNonAffineSubRegionSet, DummyBoxedLoopsSet,
+                           true /*verifying*/);
+  isValidRegion(Context);
+}
+
+void polly::ScopDetection::verifyAnalysis() const {
+  if (!VerifyScops)
+    return;
+
+  for (const Region *R : ValidRegions)
+    verifyRegion(*R);
+}
+
+void ScopDetection::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequired<ScalarEvolution>();
+  // We also need AA and RegionInfo when we are verifying analysis.
+  AU.addRequiredTransitive<AliasAnalysis>();
+  AU.addRequiredTransitive<RegionInfoPass>();
+  AU.setPreservesAll();
+}
+
+void ScopDetection::print(raw_ostream &OS, const Module *) const {
+  for (const Region *R : ValidRegions)
+    OS << "Valid Region for Scop: " << R->getNameStr() << '\n';
+
+  OS << "\n";
+}
+
+void ScopDetection::releaseMemory() {
+  ValidRegions.clear();
+  RejectLogs.clear();
+  NonAffineSubRegionMap.clear();
+  InsnToMemAcc.clear();
+
+  // Do not clear the invalid function set.
+}
+
+char ScopDetection::ID = 0;
+
+Pass *polly::createScopDetectionPass() { return new ScopDetection(); }
+
+INITIALIZE_PASS_BEGIN(ScopDetection, "polly-detect",
+                      "Polly - Detect static control parts (SCoPs)", false,
+                      false);
+INITIALIZE_AG_DEPENDENCY(AliasAnalysis);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolution);
+INITIALIZE_PASS_END(ScopDetection, "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..4573e65
--- /dev/null
+++ b/final/lib/Analysis/ScopDetectionDiagnostic.cpp
@@ -0,0 +1,611 @@
+//=== ScopDetectionDiagnostic.cpp - Error diagnostics --------- -*- 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.
+//
+//===----------------------------------------------------------------------===//
+#include "polly/ScopDetectionDiagnostic.h"
+#include "polly/Support/ScopLocation.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/AliasSetTracker.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DebugInfo.h"
+#include "llvm/IR/DebugLoc.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Value.h"
+
+#define DEBUG_TYPE "polly-detect"
+#include "llvm/Support/Debug.h"
+
+#include <string>
+
+#define BADSCOP_STAT(NAME, DESC)                                               \
+  STATISTIC(Bad##NAME##ForScop, "Number of bad regions for Scop: " DESC)
+
+BADSCOP_STAT(CFG, "CFG too complex");
+BADSCOP_STAT(IndVar, "Non canonical induction variable in loop");
+BADSCOP_STAT(IndEdge, "Found invalid region entering edges");
+BADSCOP_STAT(LoopBound, "Loop bounds can not be computed");
+BADSCOP_STAT(FuncCall, "Function call with side effects appeared");
+BADSCOP_STAT(AffFunc, "Expression not affine");
+BADSCOP_STAT(Alias, "Found base address alias");
+BADSCOP_STAT(SimpleLoop, "Loop not in -loop-simplify form");
+BADSCOP_STAT(Other, "Others");
+
+namespace polly {
+/// @brief 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 llvm {
+// @brief Lexicographic order on (line, col) of our debug locations.
+static bool operator<(const llvm::DebugLoc &LHS, const llvm::DebugLoc &RHS) {
+  return LHS.getLine() < RHS.getLine() ||
+         (LHS.getLine() == RHS.getLine() && LHS.getCol() < RHS.getCol());
+}
+}
+
+namespace polly {
+static void getDebugLocations(const Region *R, DebugLoc &Begin, DebugLoc &End) {
+  for (const BasicBlock *BB : R->blocks())
+    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 llvm::Function &F, const RejectLog &Log) {
+  LLVMContext &Ctx = F.getContext();
+
+  const Region *R = Log.region();
+  DebugLoc Begin, End;
+
+  getDebugLocations(R, Begin, End);
+
+  emitOptimizationRemarkMissed(
+      Ctx, DEBUG_TYPE, F, Begin,
+      "The following errors keep this region from being a Scop.");
+
+  for (RejectReasonPtr RR : Log) {
+    if (const DebugLoc &Loc = RR->getDebugLoc())
+      emitOptimizationRemarkMissed(Ctx, DEBUG_TYPE, F, Loc,
+                                   RR->getEndUserMessage());
+  }
+
+  emitOptimizationRemarkMissed(Ctx, DEBUG_TYPE, F, End,
+                               "Invalid Scop candidate ends here.");
+}
+
+void emitValidRemarks(const llvm::Function &F, const Region *R) {
+  LLVMContext &Ctx = F.getContext();
+
+  DebugLoc Begin, End;
+  getDebugLocations(R, Begin, End);
+
+  emitOptimizationRemark(Ctx, DEBUG_TYPE, F, Begin,
+                         "A valid Scop begins here.");
+  emitOptimizationRemark(Ctx, DEBUG_TYPE, F, End, "A valid Scop ends here.");
+}
+
+//===----------------------------------------------------------------------===//
+// RejectReason.
+const DebugLoc RejectReason::Unknown = DebugLoc();
+
+const llvm::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) {
+  ++BadCFGForScop;
+}
+
+bool ReportCFG::classof(const RejectReason *RR) {
+  return RR->getKind() >= rrkCFG && RR->getKind() <= rrkLastCFG;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNonBranchTerminator.
+
+std::string ReportNonBranchTerminator::getMessage() const {
+  return ("Non branch instruction terminates BB: " + BB->getName()).str();
+}
+
+const DebugLoc &ReportNonBranchTerminator::getDebugLoc() const {
+  return BB->getTerminator()->getDebugLoc();
+}
+
+bool ReportNonBranchTerminator::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkNonBranchTerminator;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportCondition.
+
+std::string ReportCondition::getMessage() const {
+  return ("Not well structured condition at BB: " + BB->getName()).str();
+}
+
+const DebugLoc &ReportCondition::getDebugLoc() const {
+  return BB->getTerminator()->getDebugLoc();
+}
+
+bool ReportCondition::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkCondition;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportAffFunc.
+
+ReportAffFunc::ReportAffFunc(const RejectReasonKind K, const Instruction *Inst)
+    : RejectReason(K), Inst(Inst) {
+  ++BadAffFuncForScop;
+}
+
+bool ReportAffFunc::classof(const RejectReason *RR) {
+  return RR->getKind() >= rrkAffFunc && RR->getKind() <= rrkLastAffFunc;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUndefCond.
+
+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() == rrkUndefCond;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportInvalidCond.
+
+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() == rrkInvalidCond;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUnsignedCond.
+
+std::string ReportUnsignedCond::getMessage() const {
+  return ("Condition in BB '" + BB->getName()).str() +
+         "' performs a comparision on (not yet supported) unsigned integers.";
+}
+
+std::string ReportUnsignedCond::getEndUserMessage() const {
+  return "Unsupported comparision on unsigned integers encountered";
+}
+
+bool ReportUnsignedCond::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkUnsignedCond;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUndefOperand.
+
+std::string ReportUndefOperand::getMessage() const {
+  return ("undef operand in branch at BB: " + BB->getName()).str();
+}
+
+bool ReportUndefOperand::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkUndefOperand;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNonAffBranch.
+
+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() == rrkNonAffBranch;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNoBasePtr.
+
+std::string ReportNoBasePtr::getMessage() const { return "No base pointer"; }
+
+bool ReportNoBasePtr::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkNoBasePtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUndefBasePtr.
+
+std::string ReportUndefBasePtr::getMessage() const {
+  return "Undefined base pointer";
+}
+
+bool ReportUndefBasePtr::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkUndefBasePtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportVariantBasePtr.
+
+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() == rrkVariantBasePtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportDifferentArrayElementSize
+
+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() == rrkDifferentElementSize;
+}
+
+std::string ReportDifferentArrayElementSize::getEndUserMessage() const {
+  llvm::StringRef BaseName = BaseValue->getName();
+  std::string Name = (BaseName.size() > 0) ? BaseName : "UNKNOWN";
+  return "The array \"" + Name + "\" is accessed through elements that differ "
+                                 "in size";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportNonAffineAccess.
+
+std::string ReportNonAffineAccess::getMessage() const {
+  return "Non affine access function: " + *AccessFunction;
+}
+
+bool ReportNonAffineAccess::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkNonAffineAccess;
+}
+
+std::string ReportNonAffineAccess::getEndUserMessage() const {
+  llvm::StringRef BaseName = BaseValue->getName();
+  std::string Name = (BaseName.size() > 0) ? BaseName : "UNKNOWN";
+  return "The array subscript of \"" + Name + "\" is not affine";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportIndVar.
+
+ReportIndVar::ReportIndVar(const RejectReasonKind K) : RejectReason(K) {
+  ++BadIndVarForScop;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportPhiNodeRefInRegion.
+
+ReportPhiNodeRefInRegion::ReportPhiNodeRefInRegion(Instruction *Inst)
+    : ReportIndVar(rrkPhiNodeRefInRegion), Inst(Inst) {}
+
+std::string ReportPhiNodeRefInRegion::getMessage() const {
+  return "SCEV of PHI node refers to SSA names in region: " + *Inst;
+}
+
+const DebugLoc &ReportPhiNodeRefInRegion::getDebugLoc() const {
+  return Inst->getDebugLoc();
+}
+
+bool ReportPhiNodeRefInRegion::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkPhiNodeRefInRegion;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportIndEdge.
+
+ReportIndEdge::ReportIndEdge(BasicBlock *BB)
+    : RejectReason(rrkIndEdge), BB(BB) {
+  ++BadIndEdgeForScop;
+}
+
+std::string ReportIndEdge::getMessage() const {
+  return "Region has invalid entering edges!";
+}
+
+const DebugLoc &ReportIndEdge::getDebugLoc() const {
+  return BB->getTerminator()->getDebugLoc();
+}
+
+bool ReportIndEdge::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkIndEdge;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportLoopBound.
+
+ReportLoopBound::ReportLoopBound(Loop *L, const SCEV *LoopCount)
+    : RejectReason(rrkLoopBound), L(L), LoopCount(LoopCount),
+      Loc(L->getStartLoc()) {
+  ++BadLoopBoundForScop;
+}
+
+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() == rrkLoopBound;
+}
+
+std::string ReportLoopBound::getEndUserMessage() const {
+  return "Failed to derive an affine function from the loop bounds.";
+}
+
+//===----------------------------------------------------------------------===//
+// ReportFuncCall.
+
+ReportFuncCall::ReportFuncCall(Instruction *Inst)
+    : RejectReason(rrkFuncCall), Inst(Inst) {
+  ++BadFuncCallForScop;
+}
+
+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() == rrkFuncCall;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportAlias.
+
+ReportAlias::ReportAlias(Instruction *Inst, AliasSet &AS)
+    : RejectReason(rrkAlias), Inst(Inst) {
+
+  for (const auto &I : AS)
+    Pointers.push_back(I.getValue());
+
+  ++BadAliasForScop;
+}
+
+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().size() == 0)
+      OS << "\"" << *V << "\"";
+    else
+      OS << "\"" << V->getName() << "\"";
+
+    ++PI;
+
+    if (PI != PE)
+      OS << ", ";
+    else
+      break;
+  }
+
+  OS << Suffix;
+
+  return OS.str();
+}
+
+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() == rrkAlias;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportSimpleLoop.
+
+ReportSimpleLoop::ReportSimpleLoop() : RejectReason(rrkSimpleLoop) {
+  ++BadSimpleLoopForScop;
+}
+
+std::string ReportSimpleLoop::getMessage() const {
+  return "Loop not in simplify form is invalid!";
+}
+
+bool ReportSimpleLoop::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkSimpleLoop;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportOther.
+
+std::string ReportOther::getMessage() const { return "Unknown reject reason"; }
+
+ReportOther::ReportOther(const RejectReasonKind K) : RejectReason(K) {
+  ++BadOtherForScop;
+}
+
+bool ReportOther::classof(const RejectReason *RR) {
+  return RR->getKind() >= rrkOther && RR->getKind() <= rrkLastOther;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportIntToPtr.
+ReportIntToPtr::ReportIntToPtr(Instruction *BaseValue)
+    : ReportOther(rrkIntToPtr), BaseValue(BaseValue) {}
+
+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() == rrkIntToPtr;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportAlloca.
+
+ReportAlloca::ReportAlloca(Instruction *Inst)
+    : ReportOther(rrkAlloca), Inst(Inst) {}
+
+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() == rrkAlloca;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUnknownInst.
+
+ReportUnknownInst::ReportUnknownInst(Instruction *Inst)
+    : ReportOther(rrkUnknownInst), Inst(Inst) {}
+
+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() == rrkUnknownInst;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportPHIinExit.
+
+ReportPHIinExit::ReportPHIinExit(Instruction *Inst)
+    : ReportOther(rrkPHIinExit), Inst(Inst) {}
+
+std::string ReportPHIinExit::getMessage() const {
+  return "PHI node in exit BB";
+}
+
+const DebugLoc &ReportPHIinExit::getDebugLoc() const {
+  return Inst->getDebugLoc();
+}
+
+bool ReportPHIinExit::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkPHIinExit;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportEntry.
+ReportEntry::ReportEntry(BasicBlock *BB) : ReportOther(rrkEntry), BB(BB) {}
+
+std::string ReportEntry::getMessage() const {
+  return "Region containing entry block of function is invalid!";
+}
+
+const DebugLoc &ReportEntry::getDebugLoc() const {
+  return BB->getTerminator()->getDebugLoc();
+}
+
+bool ReportEntry::classof(const RejectReason *RR) {
+  return RR->getKind() == rrkEntry;
+}
+
+//===----------------------------------------------------------------------===//
+// ReportUnprofitable.
+ReportUnprofitable::ReportUnprofitable(Region *R)
+    : ReportOther(rrkUnprofitable), R(R) {}
+
+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() == rrkUnprofitable;
+}
+} // namespace polly
diff --git a/final/lib/Analysis/ScopGraphPrinter.cpp b/final/lib/Analysis/ScopGraphPrinter.cpp
new file mode 100644
index 0000000..f39893e
--- /dev/null
+++ b/final/lib/Analysis/ScopGraphPrinter.cpp
@@ -0,0 +1,219 @@
+//===- 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"
+
+using namespace polly;
+using namespace llvm;
+
+namespace llvm {
+template <>
+struct GraphTraits<ScopDetection *> : public GraphTraits<RegionInfo *> {
+  static NodeType *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 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<ScopDetection *> : public DOTGraphTraits<RegionNode *> {
+  DOTGraphTraits(bool isSimple = false)
+      : DOTGraphTraits<RegionNode *>(isSimple) {}
+  static std::string getGraphName(ScopDetection *SD) { return "Scop Graph"; }
+
+  std::string getEdgeAttributes(RegionNode *srcNode,
+                                GraphTraits<RegionInfo *>::ChildIteratorType CI,
+                                ScopDetection *SD) {
+    RegionNode *destNode = *CI;
+
+    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, ScopDetection *SD) {
+    return DOTGraphTraits<RegionNode *>::getNodeLabel(
+        Node, reinterpret_cast<RegionNode *>(SD->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 ScopDetection *SD,
+                                     GraphWriter<ScopDetection *> &GW) {
+    raw_ostream &O = GW.getOStream();
+    O << "\tcolorscheme = \"paired12\"\n";
+    printRegionCluster(SD, SD->getRI()->getTopLevelRegion(), O, 4);
+  }
+};
+
+} // end namespace llvm
+
+struct ScopViewer : public DOTGraphTraitsViewer<ScopDetection, false> {
+  static char ID;
+  ScopViewer() : DOTGraphTraitsViewer<ScopDetection, false>("scops", ID) {}
+};
+char ScopViewer::ID = 0;
+
+struct ScopOnlyViewer : public DOTGraphTraitsViewer<ScopDetection, true> {
+  static char ID;
+  ScopOnlyViewer()
+      : DOTGraphTraitsViewer<ScopDetection, true>("scopsonly", ID) {}
+};
+char ScopOnlyViewer::ID = 0;
+
+struct ScopPrinter : public DOTGraphTraitsPrinter<ScopDetection, false> {
+  static char ID;
+  ScopPrinter() : DOTGraphTraitsPrinter<ScopDetection, false>("scops", ID) {}
+};
+char ScopPrinter::ID = 0;
+
+struct ScopOnlyPrinter : public DOTGraphTraitsPrinter<ScopDetection, true> {
+  static char ID;
+  ScopOnlyPrinter()
+      : DOTGraphTraitsPrinter<ScopDetection, 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..5771c9b
--- /dev/null
+++ b/final/lib/Analysis/ScopInfo.cpp
@@ -0,0 +1,2176 @@
+//===--------- ScopInfo.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 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/LinkAllPasses.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/TempScopInfo.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionIterator.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/Support/Debug.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 <sstream>
+#include <string>
+#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");
+
+// 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));
+
+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));
+
+/// Translate a 'const SCEV *' expression in an isl_pw_aff.
+struct SCEVAffinator : public SCEVVisitor<SCEVAffinator, isl_pw_aff *> {
+public:
+  /// @brief Translate a 'const SCEV *' to an isl_pw_aff.
+  ///
+  /// @param Stmt The location at which the scalar evolution expression
+  ///             is evaluated.
+  /// @param Expr The expression that is translated.
+  static __isl_give isl_pw_aff *getPwAff(ScopStmt *Stmt, const SCEV *Expr);
+
+private:
+  isl_ctx *Ctx;
+  int NbLoopSpaces;
+  const Scop *S;
+
+  SCEVAffinator(const ScopStmt *Stmt);
+  int getLoopDepth(const Loop *L);
+
+  __isl_give isl_pw_aff *visit(const SCEV *Expr);
+  __isl_give isl_pw_aff *visitConstant(const SCEVConstant *Expr);
+  __isl_give isl_pw_aff *visitTruncateExpr(const SCEVTruncateExpr *Expr);
+  __isl_give isl_pw_aff *visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr);
+  __isl_give isl_pw_aff *visitSignExtendExpr(const SCEVSignExtendExpr *Expr);
+  __isl_give isl_pw_aff *visitAddExpr(const SCEVAddExpr *Expr);
+  __isl_give isl_pw_aff *visitMulExpr(const SCEVMulExpr *Expr);
+  __isl_give isl_pw_aff *visitUDivExpr(const SCEVUDivExpr *Expr);
+  __isl_give isl_pw_aff *visitAddRecExpr(const SCEVAddRecExpr *Expr);
+  __isl_give isl_pw_aff *visitSMaxExpr(const SCEVSMaxExpr *Expr);
+  __isl_give isl_pw_aff *visitUMaxExpr(const SCEVUMaxExpr *Expr);
+  __isl_give isl_pw_aff *visitUnknown(const SCEVUnknown *Expr);
+  __isl_give isl_pw_aff *visitSDivInstruction(Instruction *SDiv);
+  __isl_give isl_pw_aff *visitSRemInstruction(Instruction *SDiv);
+
+  friend struct SCEVVisitor<SCEVAffinator, isl_pw_aff *>;
+};
+
+SCEVAffinator::SCEVAffinator(const ScopStmt *Stmt)
+    : Ctx(Stmt->getIslCtx()), NbLoopSpaces(Stmt->getNumIterators()),
+      S(Stmt->getParent()) {}
+
+__isl_give isl_pw_aff *SCEVAffinator::getPwAff(ScopStmt *Stmt,
+                                               const SCEV *Scev) {
+  Scop *S = Stmt->getParent();
+  const Region *Reg = &S->getRegion();
+
+  S->addParams(getParamsInAffineExpr(Reg, Scev, *S->getSE()));
+
+  SCEVAffinator Affinator(Stmt);
+  return Affinator.visit(Scev);
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visit(const SCEV *Expr) {
+  // 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)) {
+    isl_space *Space = isl_space_set_alloc(Ctx, 1, NbLoopSpaces);
+    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);
+
+    return isl_pw_aff_alloc(Domain, Affine);
+  }
+
+  return SCEVVisitor<SCEVAffinator, isl_pw_aff *>::visit(Expr);
+}
+
+__isl_give isl_pw_aff *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, Value->getValue(), /* isSigned */ true);
+
+  isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces);
+  isl_local_space *ls = isl_local_space_from_space(Space);
+  return isl_pw_aff_from_aff(isl_aff_val_on_domain(ls, v));
+}
+
+__isl_give isl_pw_aff *
+SCEVAffinator::visitTruncateExpr(const SCEVTruncateExpr *Expr) {
+  llvm_unreachable("SCEVTruncateExpr not yet supported");
+}
+
+__isl_give isl_pw_aff *
+SCEVAffinator::visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
+  llvm_unreachable("SCEVZeroExtendExpr not yet supported");
+}
+
+__isl_give isl_pw_aff *
+SCEVAffinator::visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
+  // Assuming the value is signed, a sign extension is basically a noop.
+  // TODO: Reconsider this as soon as we support unsigned values.
+  return visit(Expr->getOperand());
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitAddExpr(const SCEVAddExpr *Expr) {
+  isl_pw_aff *Sum = visit(Expr->getOperand(0));
+
+  for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) {
+    isl_pw_aff *NextSummand = visit(Expr->getOperand(i));
+    Sum = isl_pw_aff_add(Sum, NextSummand);
+  }
+
+  // TODO: Check for NSW and NUW.
+
+  return Sum;
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitMulExpr(const SCEVMulExpr *Expr) {
+  // Divide Expr into a constant part and the rest. Then visit both and multiply
+  // the result to obtain the representation for Expr. While the second part of
+  // ConstantAndLeftOverPair might still be a SCEVMulExpr we will not get to
+  // this point again. The reason is that if it is a multiplication it consists
+  // only of parameters and we will stop in the visit(const SCEV *) function and
+  // return the isl_pw_aff for that parameter.
+  auto ConstantAndLeftOverPair = extractConstantFactor(Expr, *S->getSE());
+  return isl_pw_aff_mul(visit(ConstantAndLeftOverPair.first),
+                        visit(ConstantAndLeftOverPair.second));
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitUDivExpr(const SCEVUDivExpr *Expr) {
+  llvm_unreachable("SCEVUDivExpr not yet supported");
+}
+
+__isl_give isl_pw_aff *
+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->getRegion().contains(Expr->getLoop()) &&
+           "Scop does not contain the loop referenced in this AddRec");
+
+    isl_pw_aff *Start = visit(Expr->getStart());
+    isl_pw_aff *Step = visit(Expr->getOperand(1));
+    isl_space *Space = isl_space_set_alloc(Ctx, 0, NbLoopSpaces);
+    isl_local_space *LocalSpace = isl_local_space_from_space(Space);
+
+    int loopDimension = getLoopDepth(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);
+
+    // TODO: Do we need to check for NSW and NUW?
+    return isl_pw_aff_add(Start, isl_pw_aff_mul(Step, LPwAff));
+  }
+
+  // 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.
+  ScalarEvolution &SE = *S->getSE();
+  const SCEV *ZeroStartExpr =
+      SE.getAddRecExpr(SE.getConstant(Expr->getStart()->getType(), 0),
+                       Expr->getStepRecurrence(SE), Expr->getLoop(), Flags);
+
+  isl_pw_aff *ZeroStartResult = visit(ZeroStartExpr);
+  isl_pw_aff *Start = visit(Expr->getStart());
+
+  return isl_pw_aff_add(ZeroStartResult, Start);
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitSMaxExpr(const SCEVSMaxExpr *Expr) {
+  isl_pw_aff *Max = visit(Expr->getOperand(0));
+
+  for (int i = 1, e = Expr->getNumOperands(); i < e; ++i) {
+    isl_pw_aff *NextOperand = visit(Expr->getOperand(i));
+    Max = isl_pw_aff_max(Max, NextOperand);
+  }
+
+  return Max;
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitUMaxExpr(const SCEVUMaxExpr *Expr) {
+  llvm_unreachable("SCEVUMaxExpr not yet supported");
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitSDivInstruction(Instruction *SDiv) {
+  assert(SDiv->getOpcode() == Instruction::SDiv && "Assumed SDiv instruction!");
+  auto *SE = S->getSE();
+
+  auto *Divisor = SDiv->getOperand(1);
+  auto *DivisorSCEV = SE->getSCEV(Divisor);
+  auto *DivisorPWA = visit(DivisorSCEV);
+  assert(isa<ConstantInt>(Divisor) &&
+         "SDiv is no parameter but has a non-constant RHS.");
+
+  auto *Dividend = SDiv->getOperand(0);
+  auto *DividendSCEV = SE->getSCEV(Dividend);
+  auto *DividendPWA = visit(DividendSCEV);
+  return isl_pw_aff_tdiv_q(DividendPWA, DivisorPWA);
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitSRemInstruction(Instruction *SRem) {
+  assert(SRem->getOpcode() == Instruction::SRem && "Assumed SRem instruction!");
+  auto *SE = S->getSE();
+
+  auto *Divisor = dyn_cast<ConstantInt>(SRem->getOperand(1));
+  assert(Divisor && "SRem is no parameter but has a non-constant RHS.");
+  auto *DivisorVal = isl_valFromAPInt(Ctx, Divisor->getValue(),
+                                      /* isSigned */ true);
+
+  auto *Dividend = SRem->getOperand(0);
+  auto *DividendSCEV = SE->getSCEV(Dividend);
+  auto *DividendPWA = visit(DividendSCEV);
+
+  return isl_pw_aff_mod_val(DividendPWA, isl_val_abs(DivisorVal));
+}
+
+__isl_give isl_pw_aff *SCEVAffinator::visitUnknown(const SCEVUnknown *Expr) {
+  if (Instruction *I = dyn_cast<Instruction>(Expr->getValue())) {
+    switch (I->getOpcode()) {
+    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.");
+}
+
+int SCEVAffinator::getLoopDepth(const Loop *L) {
+  Loop *outerLoop = S->getRegion().outermostLoopInRegion(const_cast<Loop *>(L));
+  assert(outerLoop && "Scop does not contain this loop");
+  return L->getLoopDepth() - outerLoop->getLoopDepth();
+}
+
+/// @brief Add the bounds of @p Range to the set @p S for dimension @p dim.
+static __isl_give isl_set *addRangeBoundsToSet(__isl_take isl_set *S,
+                                               const ConstantRange &Range,
+                                               int dim,
+                                               enum isl_dim_type type) {
+  isl_val *V;
+  isl_ctx *ctx = isl_set_get_ctx(S);
+
+  bool useLowerUpperBound = Range.isSignWrappedSet() && !Range.isFullSet();
+  const auto LB = useLowerUpperBound ? Range.getLower() : Range.getSignedMin();
+  V = isl_valFromAPInt(ctx, LB, true);
+  isl_set *SLB = isl_set_lower_bound_val(isl_set_copy(S), type, dim, V);
+
+  const auto UB = useLowerUpperBound ? Range.getUpper() : Range.getSignedMax();
+  V = isl_valFromAPInt(ctx, UB, true);
+  if (useLowerUpperBound)
+    V = isl_val_sub_ui(V, 1);
+  isl_set *SUB = isl_set_upper_bound_val(S, type, dim, V);
+
+  if (useLowerUpperBound)
+    return isl_set_union(SLB, SUB);
+  else
+    return isl_set_intersect(SLB, SUB);
+}
+
+ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx,
+                             const SmallVector<const SCEV *, 4> &DimensionSizes)
+    : BasePtr(BasePtr), ElementType(ElementType),
+      DimensionSizes(DimensionSizes) {
+  const std::string BasePtrName = getIslCompatibleName("MemRef_", BasePtr, "");
+  Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this);
+}
+
+ScopArrayInfo::~ScopArrayInfo() { isl_id_free(Id); }
+
+std::string ScopArrayInfo::getName() const { return isl_id_get_name(Id); }
+
+int ScopArrayInfo::getElemSizeInBytes() const {
+  return ElementType->getPrimitiveSizeInBits() / 8;
+}
+
+isl_id *ScopArrayInfo::getBasePtrId() const { return isl_id_copy(Id); }
+
+void ScopArrayInfo::dump() const { print(errs()); }
+
+void ScopArrayInfo::print(raw_ostream &OS) const {
+  OS.indent(8) << *getElementType() << " " << getName() << "[*]";
+  for (unsigned u = 0; u < getNumberOfDimensions(); u++)
+    OS << "[" << *DimensionSizes[u] << "]";
+  OS << " // Element size " << getElemSizeInBytes() << "\n";
+}
+
+const ScopArrayInfo *
+ScopArrayInfo::getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA) {
+  isl_id *Id = isl_pw_multi_aff_get_tuple_id(PMA, isl_dim_out);
+  assert(Id && "Output dimension didn't have an ID");
+  return getFromId(Id);
+}
+
+const ScopArrayInfo *ScopArrayInfo::getFromId(isl_id *Id) {
+  void *User = isl_id_get_user(Id);
+  const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
+  isl_id_free(Id);
+  return SAI;
+}
+
+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");
+  return "";
+}
+
+/// @brief 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->hasUnsafeAlgebra())
+      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->hasUnsafeAlgebra())
+      return MemoryAccess::RT_NONE;
+  // Fall through
+  case Instruction::Mul:
+    if (DisableMultiplicativeReductions)
+      return MemoryAccess::RT_NONE;
+    return MemoryAccess::RT_MUL;
+  default:
+    return MemoryAccess::RT_NONE;
+  }
+}
+//===----------------------------------------------------------------------===//
+
+MemoryAccess::~MemoryAccess() {
+  isl_id_free(Id);
+  isl_map_free(AccessRelation);
+  isl_map_free(newAccessRelation);
+}
+
+static MemoryAccess::AccessType getMemoryAccessType(const IRAccess &Access) {
+  switch (Access.getType()) {
+  case IRAccess::READ:
+    return MemoryAccess::READ;
+  case IRAccess::MUST_WRITE:
+    return MemoryAccess::MUST_WRITE;
+  case IRAccess::MAY_WRITE:
+    return MemoryAccess::MAY_WRITE;
+  }
+  llvm_unreachable("Unknown IRAccess type!");
+}
+
+const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
+  isl_id *ArrayId = getArrayId();
+  void *User = isl_id_get_user(ArrayId);
+  const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
+  isl_id_free(ArrayId);
+  return SAI;
+}
+
+__isl_give isl_id *MemoryAccess::getArrayId() const {
+  return isl_map_get_tuple_id(AccessRelation, isl_dim_out);
+}
+
+__isl_give isl_pw_multi_aff *MemoryAccess::applyScheduleToAccessRelation(
+    __isl_take isl_union_map *USchedule) const {
+  isl_map *Schedule, *ScheduledAccRel;
+  isl_union_set *UDomain;
+
+  UDomain = isl_union_set_from_set(getStatement()->getDomain());
+  USchedule = isl_union_map_intersect_domain(USchedule, UDomain);
+  Schedule = isl_map_from_union_map(USchedule);
+  ScheduledAccRel = isl_map_apply_domain(getAccessRelation(), Schedule);
+  return isl_pw_multi_aff_from_map(ScheduledAccRel);
+}
+
+__isl_give isl_map *MemoryAccess::getOriginalAccessRelation() const {
+  return isl_map_copy(AccessRelation);
+}
+
+std::string MemoryAccess::getOriginalAccessRelationStr() const {
+  return stringFromIslObj(AccessRelation);
+}
+
+__isl_give isl_space *MemoryAccess::getOriginalAccessRelationSpace() const {
+  return isl_map_get_space(AccessRelation);
+}
+
+__isl_give isl_map *MemoryAccess::getNewAccessRelation() const {
+  return isl_map_copy(newAccessRelation);
+}
+
+__isl_give isl_basic_map *
+MemoryAccess::createBasicAccessMap(ScopStmt *Statement) {
+  isl_space *Space = isl_space_set_alloc(Statement->getIslCtx(), 0, 1);
+  Space = isl_space_align_params(Space, 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(const IRAccess &Access) {
+  isl_space *Space = isl_space_range(getOriginalAccessRelationSpace());
+  isl_set *Outside = isl_set_empty(isl_space_copy(Space));
+  for (int i = 1, Size = Access.Subscripts.size(); i < Size; ++i) {
+    isl_local_space *LS = isl_local_space_from_space(isl_space_copy(Space));
+    isl_pw_aff *Var =
+        isl_pw_aff_var_on_domain(isl_local_space_copy(LS), isl_dim_set, i);
+    isl_pw_aff *Zero = isl_pw_aff_zero_on_domain(LS);
+
+    isl_set *DimOutside;
+
+    DimOutside = isl_pw_aff_lt_set(isl_pw_aff_copy(Var), Zero);
+    isl_pw_aff *SizeE = SCEVAffinator::getPwAff(Statement, Access.Sizes[i - 1]);
+
+    SizeE = isl_pw_aff_drop_dims(SizeE, isl_dim_in, 0,
+                                 Statement->getNumIterators());
+    SizeE = isl_pw_aff_add_dims(SizeE, isl_dim_in,
+                                isl_space_dim(Space, isl_dim_set));
+    SizeE = isl_pw_aff_set_tuple_id(SizeE, isl_dim_in,
+                                    isl_space_get_tuple_id(Space, isl_dim_set));
+
+    DimOutside = isl_set_union(DimOutside, isl_pw_aff_le_set(SizeE, Var));
+
+    Outside = isl_set_union(Outside, DimOutside);
+  }
+
+  Outside = isl_set_apply(Outside, isl_map_reverse(getAccessRelation()));
+  Outside = isl_set_intersect(Outside, Statement->getDomain());
+  Outside = isl_set_params(Outside);
+
+  // 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 = isl_set_remove_divs(Outside);
+  Outside = isl_set_complement(Outside);
+  Statement->getParent()->addAssumption(Outside);
+  isl_space_free(Space);
+}
+
+void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) {
+  ScalarEvolution *SE = Statement->getParent()->getSE();
+
+  Value *Ptr = getPointerOperand(*getAccessInstruction());
+  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;
+
+  bool isWrapping = Range.isSignWrappedSet();
+  unsigned BW = Range.getBitWidth();
+  const auto LB = isWrapping ? Range.getLower() : Range.getSignedMin();
+  const auto UB = isWrapping ? Range.getUpper() : Range.getSignedMax();
+
+  auto Min = LB.sdiv(APInt(BW, ElementSize));
+  auto Max = (UB - APInt(BW, 1)).sdiv(APInt(BW, ElementSize));
+
+  isl_set *AccessRange = isl_map_range(isl_map_copy(AccessRelation));
+  AccessRange =
+      addRangeBoundsToSet(AccessRange, ConstantRange(Min, Max), 0, isl_dim_set);
+  AccessRelation = isl_map_intersect_range(AccessRelation, AccessRange);
+}
+
+__isl_give isl_map *MemoryAccess::foldAccess(const IRAccess &Access,
+                                             __isl_take isl_map *AccessRelation,
+                                             ScopStmt *Statement) {
+  int Size = Access.Subscripts.size();
+
+  for (int i = Size - 2; i >= 0; --i) {
+    isl_space *Space;
+    isl_map *MapOne, *MapTwo;
+    isl_pw_aff *DimSize = SCEVAffinator::getPwAff(Statement, Access.Sizes[i]);
+
+    isl_space *SpaceSize = isl_pw_aff_get_space(DimSize);
+    isl_pw_aff_free(DimSize);
+    isl_id *ParamId = isl_space_get_dim_id(SpaceSize, isl_dim_param, 0);
+
+    Space = isl_map_get_space(AccessRelation);
+    Space = isl_space_map_from_set(isl_space_range(Space));
+    Space = isl_space_align_params(Space, SpaceSize);
+
+    int ParamLocation = isl_space_find_dim_by_id(Space, isl_dim_param, ParamId);
+    isl_id_free(ParamId);
+
+    MapOne = isl_map_universe(isl_space_copy(Space));
+    for (int j = 0; j < Size; ++j)
+      MapOne = isl_map_equate(MapOne, isl_dim_in, j, isl_dim_out, j);
+    MapOne = isl_map_lower_bound_si(MapOne, isl_dim_in, i + 1, 0);
+
+    MapTwo = isl_map_universe(isl_space_copy(Space));
+    for (int j = 0; j < Size; ++j)
+      if (j < i || j > i + 1)
+        MapTwo = isl_map_equate(MapTwo, isl_dim_in, j, isl_dim_out, j);
+
+    isl_local_space *LS = isl_local_space_from_space(Space);
+    isl_constraint *C;
+    C = isl_equality_alloc(isl_local_space_copy(LS));
+    C = isl_constraint_set_constant_si(C, -1);
+    C = isl_constraint_set_coefficient_si(C, isl_dim_in, i, 1);
+    C = isl_constraint_set_coefficient_si(C, isl_dim_out, i, -1);
+    MapTwo = isl_map_add_constraint(MapTwo, C);
+    C = isl_equality_alloc(LS);
+    C = isl_constraint_set_coefficient_si(C, isl_dim_in, i + 1, 1);
+    C = isl_constraint_set_coefficient_si(C, isl_dim_out, i + 1, -1);
+    C = isl_constraint_set_coefficient_si(C, isl_dim_param, ParamLocation, 1);
+    MapTwo = isl_map_add_constraint(MapTwo, C);
+    MapTwo = isl_map_upper_bound_si(MapTwo, isl_dim_in, i + 1, -1);
+
+    MapOne = isl_map_union(MapOne, MapTwo);
+    AccessRelation = isl_map_apply_range(AccessRelation, MapOne);
+  }
+  return AccessRelation;
+}
+
+MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
+                           ScopStmt *Statement, const ScopArrayInfo *SAI,
+                           int Identifier)
+    : AccType(getMemoryAccessType(Access)), Statement(Statement), Inst(AccInst),
+      newAccessRelation(nullptr) {
+
+  isl_ctx *Ctx = Statement->getIslCtx();
+  BaseAddr = Access.getBase();
+  BaseName = getIslCompatibleName("MemRef_", getBaseAddr(), "");
+
+  isl_id *BaseAddrId = SAI->getBasePtrId();
+
+  auto IdName = "__polly_array_ref_ " + std::to_string(Identifier);
+  Id = isl_id_alloc(Ctx, IdName.c_str(), nullptr);
+
+  if (!Access.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.
+    AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement));
+    AccessRelation =
+        isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
+
+    computeBoundsOnAccessRelation(Access.getElemSizeInBytes());
+    return;
+  }
+
+  isl_space *Space = isl_space_alloc(Ctx, 0, Statement->getNumIterators(), 0);
+  AccessRelation = isl_map_universe(Space);
+
+  for (int i = 0, Size = Access.Subscripts.size(); i < Size; ++i) {
+    isl_pw_aff *Affine =
+        SCEVAffinator::getPwAff(Statement, Access.Subscripts[i]);
+
+    if (Size == 1) {
+      // 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.
+      isl_val *v = isl_val_int_from_si(Ctx, Access.getElemSizeInBytes());
+      Affine = isl_pw_aff_scale_down_val(Affine, v);
+    }
+
+    isl_map *SubscriptMap = isl_map_from_pw_aff(Affine);
+
+    AccessRelation = isl_map_flat_range_product(AccessRelation, SubscriptMap);
+  }
+
+  AccessRelation = foldAccess(Access, AccessRelation, Statement);
+
+  Space = Statement->getDomainSpace();
+  AccessRelation = isl_map_set_tuple_id(
+      AccessRelation, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set));
+  AccessRelation =
+      isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
+
+  assumeNoOutOfBound(Access);
+  AccessRelation = isl_map_gist_domain(AccessRelation, Statement->getDomain());
+  isl_space_free(Space);
+}
+
+void MemoryAccess::realignParams() {
+  isl_space *ParamSpace = Statement->getParent()->getParamSpace();
+  AccessRelation = isl_map_align_params(AccessRelation, ParamSpace);
+}
+
+const std::string MemoryAccess::getReductionOperatorStr() const {
+  return MemoryAccess::getReductionOperatorStr(getReductionType());
+}
+
+__isl_give isl_id *MemoryAccess::getId() const { return isl_id_copy(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::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() << "] ";
+  OS << "[Scalar: " << isScalar() << "]\n";
+  OS.indent(16) << getOriginalAccessRelationStr() << ";\n";
+}
+
+void MemoryAccess::dump() const { print(errs()); }
+
+// 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 = isl_space_map_from_set(setDomain);
+  isl_map *Map = isl_map_universe(Space);
+  unsigned lastDimension = isl_map_dim(Map, 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 = isl_map_equate(Map, 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 = isl_map_order_lt(Map, isl_dim_in, lastDimension, isl_dim_out,
+                         lastDimension);
+  return Map;
+}
+
+__isl_give isl_set *
+MemoryAccess::getStride(__isl_take const isl_map *Schedule) const {
+  isl_map *S = const_cast<isl_map *>(Schedule);
+  isl_map *AccessRelation = getAccessRelation();
+  isl_space *Space = isl_space_range(isl_map_get_space(S));
+  isl_map *NextScatt = getEqualAndLarger(Space);
+
+  S = isl_map_reverse(S);
+  NextScatt = isl_map_lexmin(NextScatt);
+
+  NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(S));
+  NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(AccessRelation));
+  NextScatt = isl_map_apply_domain(NextScatt, S);
+  NextScatt = isl_map_apply_domain(NextScatt, AccessRelation);
+
+  isl_set *Deltas = isl_map_deltas(NextScatt);
+  return Deltas;
+}
+
+bool MemoryAccess::isStrideX(__isl_take const isl_map *Schedule,
+                             int StrideWidth) const {
+  isl_set *Stride, *StrideX;
+  bool IsStrideX;
+
+  Stride = getStride(Schedule);
+  StrideX = isl_set_universe(isl_set_get_space(Stride));
+  StrideX = isl_set_fix_si(StrideX, isl_dim_set, 0, StrideWidth);
+  IsStrideX = isl_set_is_equal(Stride, StrideX);
+
+  isl_set_free(StrideX);
+  isl_set_free(Stride);
+
+  return IsStrideX;
+}
+
+bool MemoryAccess::isStrideZero(const isl_map *Schedule) const {
+  return isStrideX(Schedule, 0);
+}
+
+bool MemoryAccess::isScalar() const {
+  return isl_map_n_out(AccessRelation) == 0;
+}
+
+bool MemoryAccess::isStrideOne(const isl_map *Schedule) const {
+  return isStrideX(Schedule, 1);
+}
+
+void MemoryAccess::setNewAccessRelation(isl_map *newAccess) {
+  isl_map_free(newAccessRelation);
+  newAccessRelation = newAccess;
+}
+
+//===----------------------------------------------------------------------===//
+
+isl_map *ScopStmt::getSchedule() const {
+  isl_set *Domain = getDomain();
+  if (isl_set_is_empty(Domain)) {
+    isl_set_free(Domain);
+    return isl_map_from_aff(
+        isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace())));
+  }
+  auto *Schedule = getParent()->getSchedule();
+  Schedule = isl_union_map_intersect_domain(
+      Schedule, isl_union_set_from_set(isl_set_copy(Domain)));
+  if (isl_union_map_is_empty(Schedule)) {
+    isl_set_free(Domain);
+    isl_union_map_free(Schedule);
+    return isl_map_from_aff(
+        isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace())));
+  }
+  auto *M = isl_map_from_union_map(Schedule);
+  M = isl_map_coalesce(M);
+  M = isl_map_gist_domain(M, Domain);
+  M = isl_map_coalesce(M);
+  return M;
+}
+
+void ScopStmt::restrictDomain(__isl_take isl_set *NewDomain) {
+  assert(isl_set_is_subset(NewDomain, Domain) &&
+         "New domain is not a subset of old domain!");
+  isl_set_free(Domain);
+  Domain = NewDomain;
+}
+
+void ScopStmt::buildAccesses(TempScop &tempScop, BasicBlock *Block,
+                             bool isApproximated) {
+  AccFuncSetType *AFS = tempScop.getAccessFunctions(Block);
+  if (!AFS)
+    return;
+
+  for (auto &AccessPair : *AFS) {
+    IRAccess &Access = AccessPair.first;
+    Instruction *AccessInst = AccessPair.second;
+
+    Type *ElementType = getAccessInstType(AccessInst);
+    const ScopArrayInfo *SAI = getParent()->getOrCreateScopArrayInfo(
+        Access.getBase(), ElementType, Access.Sizes);
+
+    if (isApproximated && Access.isWrite())
+      Access.setMayWrite();
+
+    MemoryAccessList *&MAL = InstructionToAccess[AccessInst];
+    if (!MAL)
+      MAL = new MemoryAccessList();
+    MAL->emplace_front(Access, AccessInst, this, SAI, MemAccs.size());
+    MemAccs.push_back(&MAL->front());
+  }
+}
+
+void ScopStmt::realignParams() {
+  for (MemoryAccess *MA : *this)
+    MA->realignParams();
+
+  Domain = isl_set_align_params(Domain, Parent.getParamSpace());
+}
+
+__isl_give isl_set *ScopStmt::buildConditionSet(const Comparison &Comp) {
+  isl_pw_aff *L = SCEVAffinator::getPwAff(this, Comp.getLHS());
+  isl_pw_aff *R = SCEVAffinator::getPwAff(this, Comp.getRHS());
+
+  switch (Comp.getPred()) {
+  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");
+  }
+}
+
+__isl_give isl_set *ScopStmt::addLoopBoundsToDomain(__isl_take isl_set *Domain,
+                                                    TempScop &tempScop) {
+  isl_space *Space;
+  isl_local_space *LocalSpace;
+
+  Space = isl_set_get_space(Domain);
+  LocalSpace = isl_local_space_from_space(Space);
+
+  ScalarEvolution *SE = getParent()->getSE();
+  for (int i = 0, e = getNumIterators(); i != e; ++i) {
+    isl_aff *Zero = isl_aff_zero_on_domain(isl_local_space_copy(LocalSpace));
+    isl_pw_aff *IV =
+        isl_pw_aff_from_aff(isl_aff_set_coefficient_si(Zero, isl_dim_in, i, 1));
+
+    // 0 <= IV.
+    isl_set *LowerBound = isl_pw_aff_nonneg_set(isl_pw_aff_copy(IV));
+    Domain = isl_set_intersect(Domain, LowerBound);
+
+    // IV <= LatchExecutions.
+    const Loop *L = getLoopForDimension(i);
+    const SCEV *LatchExecutions = SE->getBackedgeTakenCount(L);
+    isl_pw_aff *UpperBound = SCEVAffinator::getPwAff(this, LatchExecutions);
+    isl_set *UpperBoundSet = isl_pw_aff_le_set(IV, UpperBound);
+    Domain = isl_set_intersect(Domain, UpperBoundSet);
+  }
+
+  isl_local_space_free(LocalSpace);
+  return Domain;
+}
+
+__isl_give isl_set *ScopStmt::addConditionsToDomain(__isl_take isl_set *Domain,
+                                                    TempScop &tempScop,
+                                                    const Region &CurRegion) {
+  const Region *TopRegion = tempScop.getMaxRegion().getParent(),
+               *CurrentRegion = &CurRegion;
+  const BasicBlock *BranchingBB = BB ? BB : R->getEntry();
+
+  do {
+    if (BranchingBB != CurrentRegion->getEntry()) {
+      if (const BBCond *Condition = tempScop.getBBCond(BranchingBB))
+        for (const auto &C : *Condition) {
+          isl_set *ConditionSet = buildConditionSet(C);
+          Domain = isl_set_intersect(Domain, ConditionSet);
+        }
+    }
+    BranchingBB = CurrentRegion->getEntry();
+    CurrentRegion = CurrentRegion->getParent();
+  } while (TopRegion != CurrentRegion);
+
+  return Domain;
+}
+
+__isl_give isl_set *ScopStmt::buildDomain(TempScop &tempScop,
+                                          const Region &CurRegion) {
+  isl_space *Space;
+  isl_set *Domain;
+  isl_id *Id;
+
+  Space = isl_space_set_alloc(getIslCtx(), 0, getNumIterators());
+
+  Id = isl_id_alloc(getIslCtx(), getBaseName(), this);
+
+  Domain = isl_set_universe(Space);
+  Domain = addLoopBoundsToDomain(Domain, tempScop);
+  Domain = addConditionsToDomain(Domain, tempScop, CurRegion);
+  Domain = isl_set_set_tuple_id(Domain, Id);
+
+  return Domain;
+}
+
+void ScopStmt::deriveAssumptionsFromGEP(GetElementPtrInst *GEP) {
+  int Dimension = 0;
+  isl_ctx *Ctx = Parent.getIslCtx();
+  isl_local_space *LSpace = isl_local_space_from_space(getDomainSpace());
+  Type *Ty = GEP->getPointerOperandType();
+  ScalarEvolution &SE = *Parent.getSE();
+
+  if (auto *PtrTy = dyn_cast<PointerType>(Ty)) {
+    Dimension = 1;
+    Ty = PtrTy->getElementType();
+  }
+
+  while (auto ArrayTy = dyn_cast<ArrayType>(Ty)) {
+    unsigned int Operand = 1 + Dimension;
+
+    if (GEP->getNumOperands() <= Operand)
+      break;
+
+    const SCEV *Expr = SE.getSCEV(GEP->getOperand(Operand));
+
+    if (isAffineExpr(&Parent.getRegion(), Expr, SE)) {
+      isl_pw_aff *AccessOffset = SCEVAffinator::getPwAff(this, Expr);
+      AccessOffset =
+          isl_pw_aff_set_tuple_id(AccessOffset, isl_dim_in, getDomainId());
+
+      isl_pw_aff *DimSize = isl_pw_aff_from_aff(isl_aff_val_on_domain(
+          isl_local_space_copy(LSpace),
+          isl_val_int_from_si(Ctx, ArrayTy->getNumElements())));
+
+      isl_set *OutOfBound = isl_pw_aff_ge_set(AccessOffset, DimSize);
+      OutOfBound = isl_set_intersect(getDomain(), OutOfBound);
+      OutOfBound = isl_set_params(OutOfBound);
+      isl_set *InBound = isl_set_complement(OutOfBound);
+      isl_set *Executed = isl_set_params(getDomain());
+
+      // A => B == !A or B
+      isl_set *InBoundIfExecuted =
+          isl_set_union(isl_set_complement(Executed), InBound);
+
+      Parent.addAssumption(InBoundIfExecuted);
+    }
+
+    Dimension += 1;
+    Ty = ArrayTy->getElementType();
+  }
+
+  isl_local_space_free(LSpace);
+}
+
+void ScopStmt::deriveAssumptions(BasicBlock *Block) {
+  for (Instruction &Inst : *Block)
+    if (auto *GEP = dyn_cast<GetElementPtrInst>(&Inst))
+      deriveAssumptionsFromGEP(GEP);
+}
+
+ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
+                   Region &R, SmallVectorImpl<Loop *> &Nest)
+    : Parent(parent), BB(nullptr), R(&R), Build(nullptr),
+      NestLoops(Nest.size()) {
+  // Setup the induction variables.
+  for (unsigned i = 0, e = Nest.size(); i < e; ++i)
+    NestLoops[i] = Nest[i];
+
+  BaseName = getIslCompatibleName("Stmt_", R.getNameStr(), "");
+
+  Domain = buildDomain(tempScop, CurRegion);
+
+  BasicBlock *EntryBB = R.getEntry();
+  for (BasicBlock *Block : R.blocks()) {
+    buildAccesses(tempScop, Block, Block != EntryBB);
+    deriveAssumptions(Block);
+  }
+  checkForReductions();
+}
+
+ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
+                   BasicBlock &bb, SmallVectorImpl<Loop *> &Nest)
+    : Parent(parent), BB(&bb), R(nullptr), Build(nullptr),
+      NestLoops(Nest.size()) {
+  // Setup the induction variables.
+  for (unsigned i = 0, e = Nest.size(); i < e; ++i)
+    NestLoops[i] = Nest[i];
+
+  BaseName = getIslCompatibleName("Stmt_", &bb, "");
+
+  Domain = buildDomain(tempScop, CurRegion);
+  buildAccesses(tempScop, BB);
+  deriveAssumptions(BB);
+  checkForReductions();
+}
+
+/// @brief 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 ScopStmt::collectCandiateReductionLoads(
+    MemoryAccess *StoreMA, SmallVectorImpl<MemoryAccess *> &Loads) {
+  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(lookupAccessFor(PossibleLoad0));
+  if (PossibleLoad1 && PossibleLoad1->getNumUses() == 1)
+    if (PossibleLoad1->getParent() == Store->getParent())
+      Loads.push_back(lookupAccessFor(PossibleLoad1));
+}
+
+/// @brief Check for reductions in this ScopStmt
+///
+/// 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 collectCandiateReductionLoads,
+/// 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 ScopStmt::checkForReductions() {
+  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 : MemAccs) {
+    if (StoreMA->isRead())
+      continue;
+
+    Loads.clear();
+    collectCandiateReductionLoads(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 (!isl_map_has_equal_space(LoadAccs, StoreAccs)) {
+      isl_map_free(LoadAccs);
+      isl_map_free(StoreAccs);
+      continue;
+    }
+
+    // And check if the remaining for overlap with other memory accesses.
+    isl_map *AllAccsRel = isl_map_union(LoadAccs, StoreAccs);
+    AllAccsRel = isl_map_intersect_domain(AllAccsRel, getDomain());
+    isl_set *AllAccs = isl_map_range(AllAccsRel);
+
+    for (MemoryAccess *MA : MemAccs) {
+      if (MA == CandidatePair.first || MA == CandidatePair.second)
+        continue;
+
+      isl_map *AccRel =
+          isl_map_intersect_domain(MA->getAccessRelation(), getDomain());
+      isl_set *Accs = isl_map_range(AccRel);
+
+      if (isl_set_has_equal_space(AllAccs, Accs) || isl_set_free(Accs)) {
+        isl_set *OverlapAccs = isl_set_intersect(Accs, isl_set_copy(AllAccs));
+        Valid = Valid && isl_set_is_empty(OverlapAccs);
+        isl_set_free(OverlapAccs);
+      }
+    }
+
+    isl_set_free(AllAccs);
+    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);
+  }
+}
+
+std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); }
+
+std::string ScopStmt::getScheduleStr() const {
+  auto *S = getSchedule();
+  auto Str = stringFromIslObj(S);
+  isl_map_free(S);
+  return Str;
+}
+
+unsigned ScopStmt::getNumParams() const { return Parent.getNumParams(); }
+
+unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); }
+
+const char *ScopStmt::getBaseName() const { return BaseName.c_str(); }
+
+const Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const {
+  return NestLoops[Dimension];
+}
+
+isl_ctx *ScopStmt::getIslCtx() const { return Parent.getIslCtx(); }
+
+__isl_give isl_set *ScopStmt::getDomain() const { return isl_set_copy(Domain); }
+
+__isl_give isl_space *ScopStmt::getDomainSpace() const {
+  return isl_set_get_space(Domain);
+}
+
+__isl_give isl_id *ScopStmt::getDomainId() const {
+  return isl_set_get_tuple_id(Domain);
+}
+
+ScopStmt::~ScopStmt() {
+  DeleteContainerSeconds(InstructionToAccess);
+  isl_set_free(Domain);
+}
+
+void ScopStmt::print(raw_ostream &OS) 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);
+}
+
+void ScopStmt::dump() const { print(dbgs()); }
+
+//===----------------------------------------------------------------------===//
+/// Scop class implement
+
+void Scop::setContext(__isl_take isl_set *NewContext) {
+  NewContext = isl_set_align_params(NewContext, isl_set_get_space(Context));
+  isl_set_free(Context);
+  Context = NewContext;
+}
+
+void Scop::addParams(std::vector<const SCEV *> NewParameters) {
+  for (const SCEV *Parameter : NewParameters) {
+    Parameter = extractConstantFactor(Parameter, *SE).second;
+    if (ParameterIds.find(Parameter) != ParameterIds.end())
+      continue;
+
+    int dimension = Parameters.size();
+
+    Parameters.push_back(Parameter);
+    ParameterIds[Parameter] = dimension;
+  }
+}
+
+__isl_give isl_id *Scop::getIdForParam(const SCEV *Parameter) const {
+  ParamIdType::const_iterator IdIter = ParameterIds.find(Parameter);
+
+  if (IdIter == ParameterIds.end())
+    return nullptr;
+
+  std::string ParameterName;
+
+  if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) {
+    Value *Val = ValueParameter->getValue();
+    ParameterName = Val->getName();
+  }
+
+  if (ParameterName == "" || ParameterName.substr(0, 2) == "p_")
+    ParameterName = "p_" + utostr_32(IdIter->second);
+
+  return isl_id_alloc(getIslCtx(), ParameterName.c_str(),
+                      const_cast<void *>((const void *)Parameter));
+}
+
+void Scop::buildContext() {
+  isl_space *Space = isl_space_params_alloc(IslCtx, 0);
+  Context = isl_set_universe(isl_space_copy(Space));
+  AssumedContext = isl_set_universe(Space);
+}
+
+void Scop::addParameterBounds() {
+  for (const auto &ParamID : ParameterIds) {
+    int dim = ParamID.second;
+
+    ConstantRange SRange = SE->getSignedRange(ParamID.first);
+
+    Context = addRangeBoundsToSet(Context, SRange, dim, isl_dim_param);
+  }
+}
+
+void Scop::realignParams() {
+  // Add all parameters into a common model.
+  isl_space *Space = isl_space_params_alloc(IslCtx, ParameterIds.size());
+
+  for (const auto &ParamID : ParameterIds) {
+    const SCEV *Parameter = ParamID.first;
+    isl_id *id = getIdForParam(Parameter);
+    Space = isl_space_set_dim_id(Space, isl_dim_param, ParamID.second, id);
+  }
+
+  // Align the parameters of all data structures to the model.
+  Context = isl_set_align_params(Context, Space);
+
+  for (ScopStmt &Stmt : *this)
+    Stmt.realignParams();
+}
+
+void Scop::simplifyAssumedContext() {
+  // 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 =
+      isl_set_gist_params(AssumedContext, isl_union_set_params(getDomains()));
+  AssumedContext = isl_set_gist_params(AssumedContext, getContext());
+}
+
+/// @brief Add the minimal/maximal access in @p Set to @p User.
+static isl_stat buildMinMaxAccess(__isl_take isl_set *Set, void *User) {
+  Scop::MinMaxVectorTy *MinMaxAccesses = (Scop::MinMaxVectorTy *)User;
+  isl_pw_multi_aff *MinPMA, *MaxPMA;
+  isl_pw_aff *LastDimAff;
+  isl_aff *OneAff;
+  unsigned Pos;
+
+  // 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) > RunTimeChecksMaxParameters) {
+    unsigned InvolvedParams = 0;
+    for (unsigned u = 0, e = isl_set_n_param(Set); u < e; u++)
+      if (isl_set_involves_dims(Set, isl_dim_param, u, 1))
+        InvolvedParams++;
+
+    if (InvolvedParams > RunTimeChecksMaxParameters) {
+      isl_set_free(Set);
+      return isl_stat_error;
+    }
+  }
+
+  Set = isl_set_remove_divs(Set);
+
+  MinPMA = isl_set_lexmin_pw_multi_aff(isl_set_copy(Set));
+  MaxPMA = isl_set_lexmax_pw_multi_aff(isl_set_copy(Set));
+
+  MinPMA = isl_pw_multi_aff_coalesce(MinPMA);
+  MaxPMA = isl_pw_multi_aff_coalesce(MaxPMA);
+
+  // 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(isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) &&
+         "Assumed at least one output dimension");
+  Pos = isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) - 1;
+  LastDimAff = isl_pw_multi_aff_get_pw_aff(MaxPMA, Pos);
+  OneAff = isl_aff_zero_on_domain(
+      isl_local_space_from_space(isl_pw_aff_get_domain_space(LastDimAff)));
+  OneAff = isl_aff_add_constant_si(OneAff, 1);
+  LastDimAff = isl_pw_aff_add(LastDimAff, isl_pw_aff_from_aff(OneAff));
+  MaxPMA = isl_pw_multi_aff_set_pw_aff(MaxPMA, Pos, LastDimAff);
+
+  MinMaxAccesses->push_back(std::make_pair(MinPMA, MaxPMA));
+
+  isl_set_free(Set);
+  return isl_stat_ok;
+}
+
+static __isl_give isl_set *getAccessDomain(MemoryAccess *MA) {
+  isl_set *Domain = MA->getStatement()->getDomain();
+  Domain = isl_set_project_out(Domain, isl_dim_set, 0, isl_set_n_dim(Domain));
+  return isl_set_reset_tuple_id(Domain);
+}
+
+bool Scop::buildAliasGroups(AliasAnalysis &AA) {
+  // To create sound alias checks we perform the following steps:
+  //   o) Use the alias analysis and an alias set tracker to build alias sets
+  //      for all memory accesses inside the SCoP.
+  //   o) 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.
+  //   o) We divide 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
+  //      ones.
+  //   o) We split groups such that they contain at most one read only base
+  //      address.
+  //   o) For each group with more than one base pointer we then compute minimal
+  //      and maximal accesses to each array in this group.
+  using AliasGroupTy = SmallVector<MemoryAccess *, 4>;
+
+  AliasSetTracker AST(AA);
+
+  DenseMap<Value *, MemoryAccess *> PtrToAcc;
+  DenseSet<Value *> HasWriteAccess;
+  for (ScopStmt &Stmt : *this) {
+
+    // Skip statements with an empty domain as they will never be executed.
+    isl_set *StmtDomain = Stmt.getDomain();
+    bool StmtDomainEmpty = isl_set_is_empty(StmtDomain);
+    isl_set_free(StmtDomain);
+    if (StmtDomainEmpty)
+      continue;
+
+    for (MemoryAccess *MA : Stmt) {
+      if (MA->isScalar())
+        continue;
+      if (!MA->isRead())
+        HasWriteAccess.insert(MA->getBaseAddr());
+      Instruction *Acc = MA->getAccessInstruction();
+      PtrToAcc[getPointerOperand(*Acc)] = MA;
+      AST.add(Acc);
+    }
+  }
+
+  SmallVector<AliasGroupTy, 4> AliasGroups;
+  for (AliasSet &AS : AST) {
+    if (AS.isMustAlias() || AS.isForwardingAliasSet())
+      continue;
+    AliasGroupTy AG;
+    for (auto PR : AS)
+      AG.push_back(PtrToAcc[PR.getValue()]);
+    assert(AG.size() > 1 &&
+           "Alias groups should contain at least two accesses");
+    AliasGroups.push_back(std::move(AG));
+  }
+
+  // Split the alias groups based on their domain.
+  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);
+  }
+
+  MapVector<const Value *, SmallPtrSet<MemoryAccess *, 8>> ReadOnlyPairs;
+  SmallPtrSet<const Value *, 4> NonReadOnlyBaseValues;
+  for (AliasGroupTy &AG : AliasGroups) {
+    NonReadOnlyBaseValues.clear();
+    ReadOnlyPairs.clear();
+
+    if (AG.size() < 2) {
+      AG.clear();
+      continue;
+    }
+
+    for (auto II = AG.begin(); II != AG.end();) {
+      Value *BaseAddr = (*II)->getBaseAddr();
+      if (HasWriteAccess.count(BaseAddr)) {
+        NonReadOnlyBaseValues.insert(BaseAddr);
+        II++;
+      } else {
+        ReadOnlyPairs[BaseAddr].insert(*II);
+        II = AG.erase(II);
+      }
+    }
+
+    // If we don't have read only pointers check if there are at least two
+    // non read only pointers, otherwise clear the alias group.
+    if (ReadOnlyPairs.empty()) {
+      if (NonReadOnlyBaseValues.size() <= 1)
+        AG.clear();
+      continue;
+    }
+
+    // If we don't have non read only pointers clear the alias group.
+    if (NonReadOnlyBaseValues.empty()) {
+      AG.clear();
+      continue;
+    }
+
+    // If we have both read only and non read only base pointers we combine
+    // the non read only ones with exactly one read only one at a time into a
+    // new alias group and clear the old alias group in the end.
+    for (const auto &ReadOnlyPair : ReadOnlyPairs) {
+      AliasGroupTy AGNonReadOnly = AG;
+      for (MemoryAccess *MA : ReadOnlyPair.second)
+        AGNonReadOnly.push_back(MA);
+      AliasGroups.push_back(std::move(AGNonReadOnly));
+    }
+    AG.clear();
+  }
+
+  for (AliasGroupTy &AG : AliasGroups) {
+    if (AG.empty())
+      continue;
+
+    MinMaxVectorTy *MinMaxAccesses = new MinMaxVectorTy();
+    MinMaxAccesses->reserve(AG.size());
+
+    isl_union_map *Accesses = isl_union_map_empty(getParamSpace());
+    for (MemoryAccess *MA : AG)
+      Accesses = isl_union_map_add_map(Accesses, MA->getAccessRelation());
+    Accesses = isl_union_map_intersect_domain(Accesses, getDomains());
+
+    isl_union_set *Locations = isl_union_map_range(Accesses);
+    Locations = isl_union_set_intersect_params(Locations, getAssumedContext());
+    Locations = isl_union_set_coalesce(Locations);
+    Locations = isl_union_set_detect_equalities(Locations);
+    bool Valid = (0 == isl_union_set_foreach_set(Locations, buildMinMaxAccess,
+                                                 MinMaxAccesses));
+    isl_union_set_free(Locations);
+    MinMaxAliasGroups.push_back(MinMaxAccesses);
+
+    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 comparisions grows quadratically with
+  // the number of values we need to compare.
+  for (const auto *Values : MinMaxAliasGroups)
+    if (Values->size() > RunTimeChecksMaxArraysPerGroup)
+      return false;
+
+  return true;
+}
+
+static unsigned getMaxLoopDepthInRegion(const Region &R, LoopInfo &LI,
+                                        ScopDetection &SD) {
+
+  const ScopDetection::BoxedLoopsSetTy *BoxedLoops = SD.getBoxedLoops(&R);
+
+  unsigned MinLD = INT_MAX, MaxLD = 0;
+  for (BasicBlock *BB : R.blocks()) {
+    if (Loop *L = LI.getLoopFor(BB)) {
+      if (!R.contains(L))
+        continue;
+      if (BoxedLoops && BoxedLoops->count(L))
+        continue;
+      unsigned LD = L->getLoopDepth();
+      MinLD = std::min(MinLD, LD);
+      MaxLD = std::max(MaxLD, LD);
+    }
+  }
+
+  // Handle the case that there is no loop in the SCoP first.
+  if (MaxLD == 0)
+    return 1;
+
+  assert(MinLD >= 1 && "Minimal loop depth should be at least one");
+  assert(MaxLD >= MinLD &&
+         "Maximal loop depth was smaller than mininaml loop depth?");
+  return MaxLD - MinLD + 1;
+}
+
+Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution,
+           ScopDetection &SD, isl_ctx *Context)
+    : SE(&ScalarEvolution), R(tempScop.getMaxRegion()), IsOptimized(false),
+      MaxLoopDepth(getMaxLoopDepthInRegion(tempScop.getMaxRegion(), LI, SD)) {
+  IslCtx = Context;
+
+  buildContext();
+
+  SmallVector<Loop *, 8> NestLoops;
+
+  // Build the iteration domain, access functions and schedule functions
+  // traversing the region tree.
+  Schedule = buildScop(tempScop, getRegion(), NestLoops, LI, SD);
+  if (!Schedule)
+    Schedule = isl_schedule_empty(getParamSpace());
+
+  realignParams();
+  addParameterBounds();
+  simplifyAssumedContext();
+
+  assert(NestLoops.empty() && "NestLoops not empty at top level!");
+}
+
+Scop::~Scop() {
+  isl_set_free(Context);
+  isl_set_free(AssumedContext);
+  isl_schedule_free(Schedule);
+
+  // Free the alias groups
+  for (MinMaxVectorTy *MinMaxAccesses : MinMaxAliasGroups) {
+    for (MinMaxAccessTy &MMA : *MinMaxAccesses) {
+      isl_pw_multi_aff_free(MMA.first);
+      isl_pw_multi_aff_free(MMA.second);
+    }
+    delete MinMaxAccesses;
+  }
+}
+
+const ScopArrayInfo *
+Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *AccessType,
+                               const SmallVector<const SCEV *, 4> &Sizes) {
+  auto &SAI = ScopArrayInfoMap[BasePtr];
+  if (!SAI)
+    SAI.reset(new ScopArrayInfo(BasePtr, AccessType, getIslCtx(), Sizes));
+  return SAI.get();
+}
+
+const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr) {
+  const ScopArrayInfo *SAI = ScopArrayInfoMap[BasePtr].get();
+  assert(SAI && "No ScopArrayInfo available for this base pointer");
+  return SAI;
+}
+
+std::string Scop::getContextStr() const { return stringFromIslObj(Context); }
+std::string Scop::getAssumedContextStr() const {
+  return stringFromIslObj(AssumedContext);
+}
+
+std::string Scop::getNameStr() 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 EntryName + "---" + ExitName;
+}
+
+__isl_give isl_set *Scop::getContext() const { return isl_set_copy(Context); }
+__isl_give isl_space *Scop::getParamSpace() const {
+  return isl_set_get_space(Context);
+}
+
+__isl_give isl_set *Scop::getAssumedContext() const {
+  return isl_set_copy(AssumedContext);
+}
+
+void Scop::addAssumption(__isl_take isl_set *Set) {
+  AssumedContext = isl_set_intersect(AssumedContext, Set);
+  AssumedContext = isl_set_coalesce(AssumedContext);
+}
+
+void Scop::printContext(raw_ostream &OS) const {
+  OS << "Context:\n";
+
+  if (!Context) {
+    OS.indent(4) << "n/a\n\n";
+    return;
+  }
+
+  OS.indent(4) << getContextStr() << "\n";
+
+  OS.indent(4) << "Assumed Context:\n";
+  if (!AssumedContext) {
+    OS.indent(4) << "n/a\n\n";
+    return;
+  }
+
+  OS.indent(4) << getAssumedContextStr() << "\n";
+
+  for (const SCEV *Parameter : Parameters) {
+    int Dim = ParameterIds.find(Parameter)->second;
+    OS.indent(4) << "p" << Dim << ": " << *Parameter << "\n";
+  }
+}
+
+void Scop::printAliasAssumptions(raw_ostream &OS) const {
+  OS.indent(4) << "Alias Groups (" << MinMaxAliasGroups.size() << "):\n";
+  if (MinMaxAliasGroups.empty()) {
+    OS.indent(8) << "n/a\n";
+    return;
+  }
+  for (MinMaxVectorTy *MinMaxAccesses : MinMaxAliasGroups) {
+    OS.indent(8) << "[[";
+    for (MinMaxAccessTy &MinMacAccess : *MinMaxAccesses)
+      OS << " <" << MinMacAccess.first << ", " << MinMacAccess.second << ">";
+    OS << " ]]\n";
+  }
+}
+
+void Scop::printStatements(raw_ostream &OS) const {
+  OS << "Statements {\n";
+
+  for (const ScopStmt &Stmt : *this)
+    OS.indent(4) << Stmt;
+
+  OS.indent(4) << "}\n";
+}
+
+void Scop::printArrayInfo(raw_ostream &OS) const {
+  OS << "Arrays {\n";
+
+  for (auto &Array : arrays())
+    Array.second->print(OS);
+
+  OS.indent(4) << "}\n";
+}
+
+void Scop::print(raw_ostream &OS) const {
+  OS.indent(4) << "Function: " << getRegion().getEntry()->getParent()->getName()
+               << "\n";
+  OS.indent(4) << "Region: " << getNameStr() << "\n";
+  OS.indent(4) << "Max Loop Depth:  " << getMaxLoopDepth() << "\n";
+  printContext(OS.indent(4));
+  printArrayInfo(OS.indent(4));
+  printAliasAssumptions(OS);
+  printStatements(OS.indent(4));
+}
+
+void Scop::dump() const { print(dbgs()); }
+
+isl_ctx *Scop::getIslCtx() const { return IslCtx; }
+
+__isl_give isl_union_set *Scop::getDomains() const {
+  isl_union_set *Domain = isl_union_set_empty(getParamSpace());
+
+  for (const ScopStmt &Stmt : *this)
+    Domain = isl_union_set_add_set(Domain, Stmt.getDomain());
+
+  return Domain;
+}
+
+__isl_give isl_union_map *Scop::getMustWrites() {
+  isl_union_map *Write = isl_union_map_empty(getParamSpace());
+
+  for (ScopStmt &Stmt : *this) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isMustWrite())
+        continue;
+
+      isl_set *Domain = Stmt.getDomain();
+      isl_map *AccessDomain = MA->getAccessRelation();
+      AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
+      Write = isl_union_map_add_map(Write, AccessDomain);
+    }
+  }
+  return isl_union_map_coalesce(Write);
+}
+
+__isl_give isl_union_map *Scop::getMayWrites() {
+  isl_union_map *Write = isl_union_map_empty(getParamSpace());
+
+  for (ScopStmt &Stmt : *this) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isMayWrite())
+        continue;
+
+      isl_set *Domain = Stmt.getDomain();
+      isl_map *AccessDomain = MA->getAccessRelation();
+      AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
+      Write = isl_union_map_add_map(Write, AccessDomain);
+    }
+  }
+  return isl_union_map_coalesce(Write);
+}
+
+__isl_give isl_union_map *Scop::getWrites() {
+  isl_union_map *Write = isl_union_map_empty(getParamSpace());
+
+  for (ScopStmt &Stmt : *this) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isWrite())
+        continue;
+
+      isl_set *Domain = Stmt.getDomain();
+      isl_map *AccessDomain = MA->getAccessRelation();
+      AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
+      Write = isl_union_map_add_map(Write, AccessDomain);
+    }
+  }
+  return isl_union_map_coalesce(Write);
+}
+
+__isl_give isl_union_map *Scop::getReads() {
+  isl_union_map *Read = isl_union_map_empty(getParamSpace());
+
+  for (ScopStmt &Stmt : *this) {
+    for (MemoryAccess *MA : Stmt) {
+      if (!MA->isRead())
+        continue;
+
+      isl_set *Domain = Stmt.getDomain();
+      isl_map *AccessDomain = MA->getAccessRelation();
+
+      AccessDomain = isl_map_intersect_domain(AccessDomain, Domain);
+      Read = isl_union_map_add_map(Read, AccessDomain);
+    }
+  }
+  return isl_union_map_coalesce(Read);
+}
+
+__isl_give isl_union_map *Scop::getSchedule() const {
+  auto Tree = getScheduleTree();
+  auto S = isl_schedule_get_map(Tree);
+  isl_schedule_free(Tree);
+  return S;
+}
+
+__isl_give isl_schedule *Scop::getScheduleTree() const {
+  return isl_schedule_intersect_domain(isl_schedule_copy(Schedule),
+                                       getDomains());
+}
+
+void Scop::setSchedule(__isl_take isl_union_map *NewSchedule) {
+  auto *S = isl_schedule_from_domain(getDomains());
+  S = isl_schedule_insert_partial_schedule(
+      S, isl_multi_union_pw_aff_from_union_map(NewSchedule));
+  isl_schedule_free(Schedule);
+  Schedule = S;
+}
+
+void Scop::setScheduleTree(__isl_take isl_schedule *NewSchedule) {
+  isl_schedule_free(Schedule);
+  Schedule = NewSchedule;
+}
+
+bool Scop::restrictDomains(__isl_take isl_union_set *Domain) {
+  bool Changed = false;
+  for (ScopStmt &Stmt : *this) {
+    isl_union_set *StmtDomain = isl_union_set_from_set(Stmt.getDomain());
+    isl_union_set *NewStmtDomain = isl_union_set_intersect(
+        isl_union_set_copy(StmtDomain), isl_union_set_copy(Domain));
+
+    if (isl_union_set_is_subset(StmtDomain, NewStmtDomain)) {
+      isl_union_set_free(StmtDomain);
+      isl_union_set_free(NewStmtDomain);
+      continue;
+    }
+
+    Changed = true;
+
+    isl_union_set_free(StmtDomain);
+    NewStmtDomain = isl_union_set_coalesce(NewStmtDomain);
+
+    if (isl_union_set_is_empty(NewStmtDomain)) {
+      Stmt.restrictDomain(isl_set_empty(Stmt.getDomainSpace()));
+      isl_union_set_free(NewStmtDomain);
+    } else
+      Stmt.restrictDomain(isl_set_from_union_set(NewStmtDomain));
+  }
+  isl_union_set_free(Domain);
+  return Changed;
+}
+
+ScalarEvolution *Scop::getSE() const { return SE; }
+
+bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) {
+  if (tempScop.getAccessFunctions(BB))
+    return false;
+
+  return true;
+}
+
+struct MapToDimensionDataTy {
+  int N;
+  isl_union_pw_multi_aff *Res;
+};
+
+// @brief Create a function that maps the elements of 'Set' to its N-th
+//        dimension.
+//
+// The result is added to 'User->Res'.
+//
+// @param Set The input set.
+// @param N   The dimension to map to.
+//
+// @returns   Zero if no error occurred, non-zero otherwise.
+static isl_stat mapToDimension_AddSet(__isl_take isl_set *Set, void *User) {
+  struct MapToDimensionDataTy *Data = (struct MapToDimensionDataTy *)User;
+  int Dim;
+  isl_space *Space;
+  isl_pw_multi_aff *PMA;
+
+  Dim = isl_set_dim(Set, isl_dim_set);
+  Space = isl_set_get_space(Set);
+  PMA = isl_pw_multi_aff_project_out_map(Space, isl_dim_set, Data->N,
+                                         Dim - Data->N);
+  if (Data->N > 1)
+    PMA = isl_pw_multi_aff_drop_dims(PMA, isl_dim_out, 0, Data->N - 1);
+  Data->Res = isl_union_pw_multi_aff_add_pw_multi_aff(Data->Res, PMA);
+
+  isl_set_free(Set);
+
+  return isl_stat_ok;
+}
+
+// @brief Create a function that maps the elements of Domain to their Nth
+//        dimension.
+//
+// @param Domain The set of elements to map.
+// @param N      The dimension to map to.
+static __isl_give isl_multi_union_pw_aff *
+mapToDimension(__isl_take isl_union_set *Domain, int N) {
+  struct MapToDimensionDataTy Data;
+  isl_space *Space;
+
+  Space = isl_union_set_get_space(Domain);
+  Data.N = N;
+  Data.Res = isl_union_pw_multi_aff_empty(Space);
+  if (isl_union_set_foreach_set(Domain, &mapToDimension_AddSet, &Data) < 0)
+    Data.Res = isl_union_pw_multi_aff_free(Data.Res);
+
+  isl_union_set_free(Domain);
+  return isl_multi_union_pw_aff_from_union_pw_multi_aff(Data.Res);
+}
+
+ScopStmt *Scop::addScopStmt(BasicBlock *BB, Region *R, TempScop &tempScop,
+                            const Region &CurRegion,
+                            SmallVectorImpl<Loop *> &NestLoops) {
+  ScopStmt *Stmt;
+  if (BB) {
+    Stmts.emplace_back(*this, tempScop, CurRegion, *BB, NestLoops);
+    Stmt = &Stmts.back();
+    StmtMap[BB] = Stmt;
+  } else {
+    assert(R && "Either basic block or a region expected.");
+    Stmts.emplace_back(*this, tempScop, CurRegion, *R, NestLoops);
+    Stmt = &Stmts.back();
+    for (BasicBlock *BB : R->blocks())
+      StmtMap[BB] = Stmt;
+  }
+  return Stmt;
+}
+
+__isl_give isl_schedule *Scop::buildScop(TempScop &tempScop,
+                                         const Region &CurRegion,
+                                         SmallVectorImpl<Loop *> &NestLoops,
+                                         LoopInfo &LI, ScopDetection &SD) {
+  if (SD.isNonAffineSubRegion(&CurRegion, &getRegion())) {
+    auto *Stmt = addScopStmt(nullptr, const_cast<Region *>(&CurRegion),
+                             tempScop, CurRegion, NestLoops);
+    auto *Domain = Stmt->getDomain();
+    return isl_schedule_from_domain(isl_union_set_from_set(Domain));
+  }
+
+  Loop *L = castToLoop(CurRegion, LI);
+
+  if (L)
+    NestLoops.push_back(L);
+
+  unsigned loopDepth = NestLoops.size();
+  isl_schedule *Schedule = nullptr;
+
+  for (Region::const_element_iterator I = CurRegion.element_begin(),
+                                      E = CurRegion.element_end();
+       I != E; ++I) {
+    isl_schedule *StmtSchedule = nullptr;
+    if (I->isSubRegion()) {
+      StmtSchedule =
+          buildScop(tempScop, *I->getNodeAs<Region>(), NestLoops, LI, SD);
+    } else {
+      BasicBlock *BB = I->getNodeAs<BasicBlock>();
+
+      if (isTrivialBB(BB, tempScop)) {
+        continue;
+      } else {
+        auto *Stmt = addScopStmt(BB, nullptr, tempScop, CurRegion, NestLoops);
+        auto *Domain = Stmt->getDomain();
+        StmtSchedule = isl_schedule_from_domain(isl_union_set_from_set(Domain));
+      }
+    }
+
+    if (!Schedule)
+      Schedule = StmtSchedule;
+    else if (StmtSchedule)
+      Schedule = isl_schedule_sequence(Schedule, StmtSchedule);
+  }
+
+  if (!L)
+    return Schedule;
+
+  auto *Domain = isl_schedule_get_domain(Schedule);
+  if (!isl_union_set_is_empty(Domain)) {
+    auto *MUPA = mapToDimension(isl_union_set_copy(Domain), loopDepth);
+    Schedule = isl_schedule_insert_partial_schedule(Schedule, MUPA);
+  }
+  isl_union_set_free(Domain);
+
+  NestLoops.pop_back();
+  return Schedule;
+}
+
+ScopStmt *Scop::getStmtForBasicBlock(BasicBlock *BB) const {
+  auto StmtMapIt = StmtMap.find(BB);
+  if (StmtMapIt == StmtMap.end())
+    return nullptr;
+  return StmtMapIt->second;
+}
+
+//===----------------------------------------------------------------------===//
+ScopInfo::ScopInfo() : RegionPass(ID), scop(0) {
+  ctx = isl_ctx_alloc();
+  isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT);
+}
+
+ScopInfo::~ScopInfo() {
+  clear();
+  isl_ctx_free(ctx);
+}
+
+void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequired<RegionInfoPass>();
+  AU.addRequired<ScalarEvolution>();
+  AU.addRequired<ScopDetection>();
+  AU.addRequired<TempScopInfo>();
+  AU.addRequired<AliasAnalysis>();
+  AU.setPreservesAll();
+}
+
+bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
+  LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
+  ScopDetection &SD = getAnalysis<ScopDetection>();
+  ScalarEvolution &SE = getAnalysis<ScalarEvolution>();
+
+  TempScop *tempScop = getAnalysis<TempScopInfo>().getTempScop(R);
+
+  // This region is no Scop.
+  if (!tempScop) {
+    scop = nullptr;
+    return false;
+  }
+
+  scop = new Scop(*tempScop, LI, SE, SD, ctx);
+
+  DEBUG(scop->print(dbgs()));
+
+  if (!PollyUseRuntimeAliasChecks) {
+    // Statistics.
+    ++ScopFound;
+    if (scop->getMaxLoopDepth() > 0)
+      ++RichScopFound;
+    return false;
+  }
+
+  // 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.
+  if (scop->buildAliasGroups(AA)) {
+    // Statistics.
+    ++ScopFound;
+    if (scop->getMaxLoopDepth() > 0)
+      ++RichScopFound;
+    return false;
+  }
+
+  DEBUG(dbgs()
+        << "\n\nNOTE: Run time checks for " << scop->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");
+
+  delete scop;
+  scop = nullptr;
+  return false;
+}
+
+char ScopInfo::ID = 0;
+
+Pass *polly::createScopInfoPass() { return new ScopInfo(); }
+
+INITIALIZE_PASS_BEGIN(ScopInfo, "polly-scops",
+                      "Polly - Create polyhedral description of Scops", false,
+                      false);
+INITIALIZE_AG_DEPENDENCY(AliasAnalysis);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolution);
+INITIALIZE_PASS_DEPENDENCY(ScopDetection);
+INITIALIZE_PASS_DEPENDENCY(TempScopInfo);
+INITIALIZE_PASS_END(ScopInfo, "polly-scops",
+                    "Polly - Create polyhedral description of Scops", false,
+                    false)
diff --git a/final/lib/Analysis/ScopPass.cpp b/final/lib/Analysis/ScopPass.cpp
new file mode 100644
index 0000000..1c0ddb0
--- /dev/null
+++ b/final/lib/Analysis/ScopPass.cpp
@@ -0,0 +1,37 @@
+//===- 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"
+
+using namespace llvm;
+using namespace polly;
+
+bool ScopPass::runOnRegion(Region *R, RGPassManager &RGM) {
+  S = nullptr;
+
+  if ((S = getAnalysis<ScopInfo>().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<ScopInfo>();
+  AU.setPreservesAll();
+}
diff --git a/final/lib/Analysis/TempScopInfo.cpp b/final/lib/Analysis/TempScopInfo.cpp
new file mode 100644
index 0000000..18eff7e
--- /dev/null
+++ b/final/lib/Analysis/TempScopInfo.cpp
@@ -0,0 +1,509 @@
+//===---------- TempScopInfo.cpp  - Extract TempScops ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Collect information about the control flow regions detected by the Scop
+// detection, such that this information can be translated info its polyhedral
+// representation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/TempScopInfo.h"
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/ScopDetection.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/RegionIterator.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-analyze-ir"
+
+//===----------------------------------------------------------------------===//
+/// Helper Classes
+
+void IRAccess::print(raw_ostream &OS) const {
+  if (isRead())
+    OS << "Read ";
+  else {
+    if (isMayWrite())
+      OS << "May";
+    OS << "Write ";
+  }
+  OS << BaseAddress->getName() << '[' << *Offset << "]\n";
+}
+
+void Comparison::print(raw_ostream &OS) const {
+  // Not yet implemented.
+}
+
+/// Helper function to print the condition
+static void printBBCond(raw_ostream &OS, const BBCond &Cond) {
+  assert(!Cond.empty() && "Unexpected empty condition!");
+  Cond[0].print(OS);
+  for (unsigned i = 1, e = Cond.size(); i != e; ++i) {
+    OS << " && ";
+    Cond[i].print(OS);
+  }
+}
+
+inline raw_ostream &operator<<(raw_ostream &OS, const BBCond &Cond) {
+  printBBCond(OS, Cond);
+  return OS;
+}
+
+//===----------------------------------------------------------------------===//
+// TempScop implementation
+TempScop::~TempScop() {}
+
+void TempScop::print(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI) const {
+  OS << "Scop: " << R.getNameStr() << "\n";
+
+  printDetail(OS, SE, LI, &R, 0);
+}
+
+void TempScop::printDetail(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI,
+                           const Region *CurR, unsigned ind) const {
+  // FIXME: Print other details rather than memory accesses.
+  for (const auto &CurBlock : CurR->blocks()) {
+    AccFuncMapType::const_iterator AccSetIt = AccFuncMap.find(CurBlock);
+
+    // Ignore trivial blocks that do not contain any memory access.
+    if (AccSetIt == AccFuncMap.end())
+      continue;
+
+    OS.indent(ind) << "BB: " << CurBlock->getName() << '\n';
+    typedef AccFuncSetType::const_iterator access_iterator;
+    const AccFuncSetType &AccFuncs = AccSetIt->second;
+
+    for (access_iterator AI = AccFuncs.begin(), AE = AccFuncs.end(); AI != AE;
+         ++AI)
+      AI->first.print(OS.indent(ind + 2));
+  }
+}
+
+void TempScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
+                                    AccFuncSetType &Functions,
+                                    Region *NonAffineSubRegion) {
+  if (canSynthesize(PHI, LI, SE, &R))
+    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 Written = false;
+  for (unsigned u = 0; u < PHI->getNumIncomingValues(); u++) {
+    Value *Op = PHI->getIncomingValue(u);
+    BasicBlock *OpBB = PHI->getIncomingBlock(u);
+
+    if (!R.contains(OpBB))
+      continue;
+
+    // Do not build scalar dependences inside a non-affine subregion.
+    if (NonAffineSubRegion && NonAffineSubRegion->contains(OpBB))
+      continue;
+
+    Instruction *OpI = dyn_cast<Instruction>(Op);
+    if (OpI) {
+      BasicBlock *OpIBB = OpI->getParent();
+      // As we pretend there is a use (or more precise a write) of OpI in OpBB
+      // we have to insert a scalar dependence from the definition of OpI to
+      // OpBB if the definition is not in OpBB.
+      if (OpIBB != OpBB) {
+        IRAccess ScalarRead(IRAccess::READ, OpI, ZeroOffset, 1, true);
+        AccFuncMap[OpBB].push_back(std::make_pair(ScalarRead, PHI));
+        IRAccess ScalarWrite(IRAccess::MUST_WRITE, OpI, ZeroOffset, 1, true);
+        AccFuncMap[OpIBB].push_back(std::make_pair(ScalarWrite, OpI));
+      }
+    }
+
+    // If the operand is a constant, global or argument we need an access
+    // instruction and just choose the PHI.
+    if (!OpI)
+      OpI = PHI;
+
+    Written = true;
+
+    IRAccess ScalarAccess(IRAccess::MUST_WRITE, PHI, ZeroOffset, 1, true);
+    AccFuncMap[OpBB].push_back(std::make_pair(ScalarAccess, OpI));
+  }
+
+  if (Written) {
+    IRAccess ScalarAccess(IRAccess::READ, PHI, ZeroOffset, 1, true);
+    Functions.push_back(std::make_pair(ScalarAccess, PHI));
+  }
+}
+
+bool TempScopInfo::buildScalarDependences(Instruction *Inst, Region *R,
+                                          Region *NonAffineSubRegion) {
+  bool canSynthesizeInst = canSynthesize(Inst, LI, SE, R);
+  if (isIgnoredIntrinsic(Inst))
+    return false;
+
+  bool AnyCrossStmtUse = false;
+  BasicBlock *ParentBB = Inst->getParent();
+
+  for (User *U : Inst->users()) {
+    Instruction *UI = dyn_cast<Instruction>(U);
+
+    // Ignore the strange user
+    if (UI == 0)
+      continue;
+
+    BasicBlock *UseParent = UI->getParent();
+
+    // Ignore the users in the same BB (statement)
+    if (UseParent == ParentBB)
+      continue;
+
+    // Do not build scalar dependences inside a non-affine subregion.
+    if (NonAffineSubRegion && NonAffineSubRegion->contains(UseParent))
+      continue;
+
+    // Check whether or not the use is in the SCoP.
+    if (!R->contains(UseParent)) {
+      AnyCrossStmtUse = true;
+      continue;
+    }
+
+    // If the instruction can be synthesized and the user is in the region
+    // we do not need to add scalar dependences.
+    if (canSynthesizeInst)
+      continue;
+
+    // No need to translate these scalar dependences into polyhedral form,
+    // because synthesizable scalars can be generated by the code generator.
+    if (canSynthesize(UI, LI, SE, R))
+      continue;
+
+    // Skip PHI nodes in the region as they handle their operands on their own.
+    if (isa<PHINode>(UI))
+      continue;
+
+    // Now U is used in another statement.
+    AnyCrossStmtUse = true;
+
+    // Do not build a read access that is not in the current SCoP
+    // Use the def instruction as base address of the IRAccess, so that it will
+    // become the name of the scalar access in the polyhedral form.
+    IRAccess ScalarAccess(IRAccess::READ, Inst, ZeroOffset, 1, true);
+    AccFuncMap[UseParent].push_back(std::make_pair(ScalarAccess, UI));
+  }
+
+  return AnyCrossStmtUse;
+}
+
+extern MapInsnToMemAcc InsnToMemAcc;
+
+IRAccess
+TempScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R,
+                            const ScopDetection::BoxedLoopsSetTy *BoxedLoops) {
+  unsigned Size;
+  Type *SizeType;
+  enum IRAccess::TypeKind Type;
+
+  if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
+    SizeType = Load->getType();
+    Size = TD->getTypeStoreSize(SizeType);
+    Type = IRAccess::READ;
+  } else {
+    StoreInst *Store = cast<StoreInst>(Inst);
+    SizeType = Store->getValueOperand()->getType();
+    Size = TD->getTypeStoreSize(SizeType);
+    Type = IRAccess::MUST_WRITE;
+  }
+
+  const SCEV *AccessFunction = SE->getSCEVAtScope(getPointerOperand(*Inst), L);
+  const SCEVUnknown *BasePointer =
+      dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
+
+  assert(BasePointer && "Could not find base pointer");
+  AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
+
+  auto AccItr = InsnToMemAcc.find(Inst);
+  if (PollyDelinearize && AccItr != InsnToMemAcc.end())
+    return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, true,
+                    AccItr->second.DelinearizedSubscripts,
+                    AccItr->second.Shape->DelinearizedSizes);
+
+  // Check if the access depends on a loop contained in a non-affine subregion.
+  bool isVariantInNonAffineLoop = false;
+  if (BoxedLoops) {
+    SetVector<const Loop *> Loops;
+    findLoops(AccessFunction, Loops);
+    for (const Loop *L : Loops)
+      if (BoxedLoops->count(L))
+        isVariantInNonAffineLoop = true;
+  }
+
+  bool IsAffine = !isVariantInNonAffineLoop &&
+                  isAffineExpr(R, AccessFunction, *SE, BasePointer->getValue());
+
+  SmallVector<const SCEV *, 4> Subscripts, Sizes;
+  Subscripts.push_back(AccessFunction);
+  Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size));
+
+  if (!IsAffine && Type == IRAccess::MUST_WRITE)
+    Type = IRAccess::MAY_WRITE;
+
+  return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, IsAffine,
+                  Subscripts, Sizes);
+}
+
+void TempScopInfo::buildAccessFunctions(Region &R, Region &SR) {
+
+  if (SD->isNonAffineSubRegion(&SR, &R)) {
+    for (BasicBlock *BB : SR.blocks())
+      buildAccessFunctions(R, *BB, &SR);
+    return;
+  }
+
+  for (auto I = SR.element_begin(), E = SR.element_end(); I != E; ++I)
+    if (I->isSubRegion())
+      buildAccessFunctions(R, *I->getNodeAs<Region>());
+    else
+      buildAccessFunctions(R, *I->getNodeAs<BasicBlock>());
+}
+
+void TempScopInfo::buildAccessFunctions(Region &R, BasicBlock &BB,
+                                        Region *NonAffineSubRegion) {
+  AccFuncSetType Functions;
+  Loop *L = LI->getLoopFor(&BB);
+
+  // The set of loops contained in non-affine subregions that are part of R.
+  const ScopDetection::BoxedLoopsSetTy *BoxedLoops = SD->getBoxedLoops(&R);
+
+  for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) {
+    Instruction *Inst = I;
+    if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
+      Functions.push_back(
+          std::make_pair(buildIRAccess(Inst, L, &R, BoxedLoops), Inst));
+
+    if (PHINode *PHI = dyn_cast<PHINode>(Inst))
+      buildPHIAccesses(PHI, R, Functions, NonAffineSubRegion);
+
+    if (!isa<StoreInst>(Inst) &&
+        buildScalarDependences(Inst, &R, NonAffineSubRegion)) {
+      // If the Instruction is used outside the statement, we need to build the
+      // write access.
+      IRAccess ScalarAccess(IRAccess::MUST_WRITE, Inst, ZeroOffset, 1, true);
+      Functions.push_back(std::make_pair(ScalarAccess, Inst));
+    }
+  }
+
+  if (Functions.empty())
+    return;
+
+  AccFuncSetType &Accs = AccFuncMap[&BB];
+  Accs.insert(Accs.end(), Functions.begin(), Functions.end());
+}
+
+Comparison TempScopInfo::buildAffineCondition(Value &V, bool inverted) {
+  if (ConstantInt *C = dyn_cast<ConstantInt>(&V)) {
+    // If this is always true condition, we will create 0 <= 1,
+    // otherwise we will create 0 >= 1.
+    const SCEV *LHS = SE->getConstant(C->getType(), 0);
+    const SCEV *RHS = SE->getConstant(C->getType(), 1);
+
+    if (C->isOne() == inverted)
+      return Comparison(LHS, RHS, ICmpInst::ICMP_SLE);
+    else
+      return Comparison(LHS, RHS, ICmpInst::ICMP_SGE);
+  }
+
+  ICmpInst *ICmp = dyn_cast<ICmpInst>(&V);
+  assert(ICmp && "Only ICmpInst of constant as condition supported!");
+
+  Loop *L = LI->getLoopFor(ICmp->getParent());
+  const SCEV *LHS = SE->getSCEVAtScope(ICmp->getOperand(0), L);
+  const SCEV *RHS = SE->getSCEVAtScope(ICmp->getOperand(1), L);
+
+  ICmpInst::Predicate Pred = ICmp->getPredicate();
+
+  // Invert the predicate if needed.
+  if (inverted)
+    Pred = ICmpInst::getInversePredicate(Pred);
+
+  switch (Pred) {
+  case ICmpInst::ICMP_UGT:
+  case ICmpInst::ICMP_UGE:
+  case ICmpInst::ICMP_ULT:
+  case ICmpInst::ICMP_ULE:
+    // TODO: At the moment we need to see everything as signed. This is an
+    //       correctness issue that needs to be solved.
+    // AffLHS->setUnsigned();
+    // AffRHS->setUnsigned();
+    break;
+  default:
+    break;
+  }
+
+  return Comparison(LHS, RHS, Pred);
+}
+
+void TempScopInfo::buildCondition(BasicBlock *BB, Region &R) {
+  BasicBlock *RegionEntry = R.getEntry();
+  BBCond Cond;
+
+  DomTreeNode *BBNode = DT->getNode(BB), *EntryNode = DT->getNode(RegionEntry);
+  assert(BBNode && EntryNode && "Get null node while building condition!");
+
+  // Walk up the dominance tree until reaching the entry node. Collect all
+  // branching blocks on the path to BB except if BB postdominates the block
+  // containing the condition.
+  SmallVector<BasicBlock *, 4> DominatorBrBlocks;
+  while (BBNode != EntryNode) {
+    BasicBlock *CurBB = BBNode->getBlock();
+    BBNode = BBNode->getIDom();
+    assert(BBNode && "BBNode should not reach the root node!");
+
+    if (PDT->dominates(CurBB, BBNode->getBlock()))
+      continue;
+
+    BranchInst *Br = dyn_cast<BranchInst>(BBNode->getBlock()->getTerminator());
+    assert(Br && "A Valid Scop should only contain branch instruction");
+
+    if (Br->isUnconditional())
+      continue;
+
+    DominatorBrBlocks.push_back(BBNode->getBlock());
+  }
+
+  RegionInfo *RI = R.getRegionInfo();
+  // Iterate in reverse order over the dominating blocks.  Until a non-affine
+  // branch was encountered add all conditions collected. If a non-affine branch
+  // was encountered, stop as we overapproximate from here on anyway.
+  for (auto BIt = DominatorBrBlocks.rbegin(), BEnd = DominatorBrBlocks.rend();
+       BIt != BEnd; BIt++) {
+
+    BasicBlock *BBNode = *BIt;
+    BranchInst *Br = dyn_cast<BranchInst>(BBNode->getTerminator());
+    assert(Br && "A Valid Scop should only contain branch instruction");
+    assert(Br->isConditional() && "Assumed a conditional branch");
+
+    if (SD->isNonAffineSubRegion(RI->getRegionFor(BBNode), &R))
+      break;
+
+    BasicBlock *TrueBB = Br->getSuccessor(0), *FalseBB = Br->getSuccessor(1);
+
+    // Is BB on the ELSE side of the branch?
+    bool inverted = DT->dominates(FalseBB, BB);
+
+    // If both TrueBB and FalseBB dominate BB, one of them must be the target of
+    // a back-edge, i.e. a loop header.
+    if (inverted && DT->dominates(TrueBB, BB)) {
+      assert(
+          (DT->dominates(TrueBB, FalseBB) || DT->dominates(FalseBB, TrueBB)) &&
+          "One of the successors should be the loop header and dominate the"
+          "other!");
+
+      // It is not an invert if the FalseBB is the header.
+      if (DT->dominates(FalseBB, TrueBB))
+        inverted = false;
+    }
+
+    Cond.push_back(buildAffineCondition(*(Br->getCondition()), inverted));
+  }
+
+  if (!Cond.empty())
+    BBConds[BB] = Cond;
+}
+
+TempScop *TempScopInfo::buildTempScop(Region &R) {
+  TempScop *TScop = new TempScop(R, BBConds, AccFuncMap);
+
+  buildAccessFunctions(R, R);
+
+  for (const auto &BB : R.blocks())
+    buildCondition(BB, R);
+
+  return TScop;
+}
+
+TempScop *TempScopInfo::getTempScop(const Region *R) const {
+  TempScopMapType::const_iterator at = TempScops.find(R);
+  return at == TempScops.end() ? 0 : at->second;
+}
+
+void TempScopInfo::print(raw_ostream &OS, const Module *) const {
+  for (TempScopMapType::const_iterator I = TempScops.begin(),
+                                       E = TempScops.end();
+       I != E; ++I)
+    I->second->print(OS, SE, LI);
+}
+
+bool TempScopInfo::runOnFunction(Function &F) {
+  DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+  PDT = &getAnalysis<PostDominatorTree>();
+  SE = &getAnalysis<ScalarEvolution>();
+  LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  SD = &getAnalysis<ScopDetection>();
+  AA = &getAnalysis<AliasAnalysis>();
+  TD = &F.getParent()->getDataLayout();
+  ZeroOffset = SE->getConstant(TD->getIntPtrType(F.getContext()), 0);
+
+  for (ScopDetection::iterator I = SD->begin(), E = SD->end(); I != E; ++I) {
+    if (!SD->isMaxRegionInScop(**I))
+      continue;
+    Region *R = const_cast<Region *>(*I);
+    TempScops.insert(std::make_pair(R, buildTempScop(*R)));
+  }
+
+  return false;
+}
+
+void TempScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequiredTransitive<DominatorTreeWrapperPass>();
+  AU.addRequiredTransitive<PostDominatorTree>();
+  AU.addRequiredTransitive<LoopInfoWrapperPass>();
+  AU.addRequiredTransitive<ScalarEvolution>();
+  AU.addRequiredTransitive<ScopDetection>();
+  AU.addRequiredID(IndependentBlocksID);
+  AU.addRequired<AliasAnalysis>();
+  AU.setPreservesAll();
+}
+
+TempScopInfo::~TempScopInfo() { clear(); }
+
+void TempScopInfo::clear() {
+  BBConds.clear();
+  AccFuncMap.clear();
+  DeleteContainerSeconds(TempScops);
+  TempScops.clear();
+}
+
+//===----------------------------------------------------------------------===//
+// TempScop information extraction pass implement
+char TempScopInfo::ID = 0;
+
+Pass *polly::createTempScopInfoPass() { return new TempScopInfo(); }
+
+INITIALIZE_PASS_BEGIN(TempScopInfo, "polly-analyze-ir",
+                      "Polly - Analyse the LLVM-IR in the detected regions",
+                      false, false);
+INITIALIZE_AG_DEPENDENCY(AliasAnalysis);
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(PostDominatorTree);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolution);
+INITIALIZE_PASS_END(TempScopInfo, "polly-analyze-ir",
+                    "Polly - Analyse the LLVM-IR in the detected regions",
+                    false, false)
diff --git a/final/lib/CMakeLists.txt b/final/lib/CMakeLists.txt
new file mode 100644
index 0000000..e2c50a2
--- /dev/null
+++ b/final/lib/CMakeLists.txt
@@ -0,0 +1,228 @@
+set(LLVM_NO_RTTI 1)
+
+set(POLLY_JSON_FILES
+    JSON/json_reader.cpp
+    JSON/json_value.cpp
+    JSON/json_writer.cpp
+)
+
+set(ISL_CODEGEN_FILES
+    CodeGen/IslAst.cpp
+    CodeGen/IslExprBuilder.cpp
+    CodeGen/IslNodeBuilder.cpp
+    CodeGen/CodeGeneration.cpp)
+
+if (GPU_CODEGEN)
+  set (GPGPU_CODEGEN_FILES)
+endif (GPU_CODEGEN)
+
+
+# External: Integer Set Library
+set(ISL_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/External/isl")
+set(ISL_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/External/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" GIT_HEAD_ID)
+  string(STRIP "${GIT_HEAD_ID}" 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" GIT_HEAD_ID "${GITVERSION_H}")
+elseif ()
+  # Unknown revision
+  set(GIT_HEAD_ID "UNKNOWN")
+endif ()
+
+message(STATUS "ISL version: ${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)
+
+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("
+  #include <strings.h>
+  int main() { ffs(0); return 0; }
+  " HAVE_DECL_FFS)
+if (NOT HAVE_DECL_FFS)
+  set(HAVE_DECL_FFS 0)
+endif ()
+
+check_c_source_compiles("
+  int main() { __builtin_ffs(0); return 0; }
+  " HAVE_DECL___BUILTIN_FFS)
+if (NOT HAVE_DECL___BUILTIN_FFS)
+  set(HAVE_DECL___BUILTIN_FFS 0)
+endif ()
+
+check_c_source_compiles("
+  static void foo(void) __attribute__ ((unused));
+  int main() { return 0; }
+  " HAVE___ATTRIBUTE__)
+
+# Write configure result
+configure_file("External/gitversion.h.cmake" "${ISL_BINARY_DIR}/gitversion.h")
+configure_file("External/isl_config.h.cmake" "${ISL_BINARY_DIR}/isl_config.h")
+file(WRITE "${ISL_BINARY_DIR}/include/isl/stdint.h" "#include <stdint.h>")
+
+# ISL files to compile
+set (ISL_FILES
+    External/isl/basis_reduction_tab.c
+    External/isl/isl_aff.c
+    External/isl/isl_affine_hull.c
+    External/isl/isl_arg.c
+    External/isl/isl_ast_build.c
+    External/isl/isl_ast_build_expr.c
+    External/isl/isl_ast.c
+    External/isl/isl_ast_codegen.c
+    External/isl/isl_ast_graft.c
+    External/isl/isl_band.c
+    External/isl/isl_bernstein.c
+    External/isl/isl_blk.c
+    External/isl/isl_bound.c
+    External/isl/isl_coalesce.c
+    External/isl/isl_constraint.c
+    External/isl/isl_convex_hull.c
+    External/isl/isl_ctx.c
+    External/isl/isl_deprecated.c
+    External/isl/isl_dim_map.c
+    External/isl/isl_equalities.c
+    External/isl/isl_factorization.c
+    External/isl/isl_farkas.c
+    External/isl/isl_flow.c
+    External/isl/isl_fold.c
+    External/isl/isl_hash.c
+    External/isl/isl_id.c
+    External/isl/isl_id_to_ast_expr.c
+    External/isl/isl_id_to_pw_aff.c
+    External/isl/isl_ilp.c
+    External/isl/isl_imath.c
+    External/isl/isl_input.c
+    External/isl/isl_int_sioimath.c
+    External/isl/isl_local_space.c
+    External/isl/isl_lp.c
+    External/isl/isl_map.c
+    External/isl/isl_map_list.c
+    External/isl/isl_map_simplify.c
+    External/isl/isl_map_subtract.c
+    External/isl/isl_map_to_basic_set.c
+    External/isl/isl_mat.c
+    External/isl/isl_morph.c
+    External/isl/isl_obj.c
+    External/isl/isl_options.c
+    External/isl/isl_output.c
+    External/isl/isl_point.c
+    External/isl/isl_polynomial.c
+    External/isl/isl_printer.c
+    External/isl/isl_range.c
+    External/isl/isl_reordering.c
+    External/isl/isl_sample.c
+    External/isl/isl_scan.c
+    External/isl/isl_schedule.c
+    External/isl/isl_schedule_band.c
+    External/isl/isl_schedule_node.c
+    External/isl/isl_schedule_read.c
+    External/isl/isl_schedule_tree.c
+    External/isl/isl_scheduler.c
+    External/isl/isl_seq.c
+    External/isl/isl_set_list.c
+    External/isl/isl_sort.c
+    External/isl/isl_space.c
+    External/isl/isl_stream.c
+    External/isl/isl_tab.c
+    External/isl/isl_tab_pip.c
+    External/isl/isl_tarjan.c
+    External/isl/isl_transitive_closure.c
+    External/isl/isl_union_map.c
+    External/isl/isl_val.c
+    External/isl/isl_val_sioimath.c
+    External/isl/isl_vec.c
+    External/isl/isl_version.c
+    External/isl/isl_vertices.c
+    External/isl/print.c
+    External/isl/imath/gmp_compat.c
+    External/isl/imath/imath.c
+    External/isl/imath/imrat.c
+    )
+
+
+add_polly_library(Polly
+  Analysis/DependenceInfo.cpp
+  Analysis/ScopDetection.cpp
+  Analysis/ScopDetectionDiagnostic.cpp
+  Analysis/ScopInfo.cpp
+  Analysis/ScopGraphPrinter.cpp
+  Analysis/ScopPass.cpp
+  Analysis/TempScopInfo.cpp
+  CodeGen/BlockGenerators.cpp
+  ${ISL_CODEGEN_FILES}
+  CodeGen/LoopGenerators.cpp
+  CodeGen/IRBuilder.cpp
+  CodeGen/Utils.cpp
+  CodeGen/RuntimeDebugBuilder.cpp
+  ${GPGPU_CODEGEN_FILES}
+  Exchange/JSONExporter.cpp
+  Support/GICHelper.cpp
+  Support/SCEVValidator.cpp
+  Support/RegisterPasses.cpp
+  Support/ScopHelper.cpp
+  Support/ScopLocation.cpp
+  ${POLLY_JSON_FILES}
+  Transform/Canonicalization.cpp
+  Transform/CodePreparation.cpp
+  Transform/DeadCodeElimination.cpp
+  Transform/IndependentBlocks.cpp
+  Transform/ScheduleOptimizer.cpp
+  ${ISL_FILES}
+  )
+
+# ISL requires at least C99 to compile. gcc < 5.0 use -std=gnu89 as default.
+target_enable_c99(Polly)
+
+if (BUILD_SHARED_LIBS)
+  target_link_libraries(Polly
+    LLVMSupport
+    LLVMCore
+    LLVMScalarOpts
+    LLVMInstCombine
+    LLVMTransformUtils
+    LLVMAnalysis
+    LLVMipo
+    LLVMMC
+  )
+  link_directories(
+    ${LLVM_LIBRARY_DIR}
+  )
+endif()
+
+# Build a monolithic Polly.a and a thin module LLVMPolly.moduleext that links to
+# that static library.
+add_polly_loadable_module(LLVMPolly
+  Polly.cpp
+)
+
+if (TARGET intrinsics_gen)
+  # Check if we are building as part of an LLVM build
+  add_dependencies(Polly intrinsics_gen)
+endif()
+
+target_link_libraries(LLVMPolly Polly)
+
+set_target_properties(LLVMPolly
+  PROPERTIES
+  LINKER_LANGUAGE CXX
+  PREFIX "")
diff --git a/final/lib/CodeGen/BlockGenerators.cpp b/final/lib/CodeGen/BlockGenerators.cpp
new file mode 100644
index 0000000..4c667dd
--- /dev/null
+++ b/final/lib/CodeGen/BlockGenerators.cpp
@@ -0,0 +1,1300 @@
+//===--- 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/ScopInfo.h"
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/IslExprBuilder.h"
+#include "polly/Options.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.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 polly::canSynthesize(const Instruction *I, const llvm::LoopInfo *LI,
+                          ScalarEvolution *SE, const Region *R) {
+  if (!I || !SE->isSCEVable(I->getType()))
+    return false;
+
+  if (const SCEV *Scev = SE->getSCEV(const_cast<Instruction *>(I)))
+    if (!isa<SCEVCouldNotCompute>(Scev))
+      if (!hasScalarDepsInsideRegion(Scev, R))
+        return true;
+
+  return false;
+}
+
+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:
+    case llvm::Intrinsic::expect:
+      return true;
+    default:
+      break;
+    }
+  }
+  return false;
+}
+
+BlockGenerator::BlockGenerator(PollyIRBuilder &B, LoopInfo &LI,
+                               ScalarEvolution &SE, DominatorTree &DT,
+                               ScalarAllocaMapTy &ScalarMap,
+                               ScalarAllocaMapTy &PHIOpMap,
+                               EscapeUsersAllocaMapTy &EscapeMap,
+                               IslExprBuilder *ExprBuilder)
+    : Builder(B), LI(LI), SE(SE), ExprBuilder(ExprBuilder), DT(DT),
+      EntryBB(nullptr), PHIOpMap(PHIOpMap), ScalarMap(ScalarMap),
+      EscapeMap(EscapeMap) {}
+
+Value *BlockGenerator::getNewValue(ScopStmt &Stmt, const Value *Old,
+                                   ValueMapT &BBMap, ValueMapT &GlobalMap,
+                                   LoopToScevMapT &LTS, Loop *L) const {
+  // We assume constants never change.
+  // This avoids map lookups for many calls to this function.
+  if (isa<Constant>(Old))
+    return const_cast<Value *>(Old);
+
+  if (Value *New = GlobalMap.lookup(Old)) {
+    if (Old->getType()->getScalarSizeInBits() <
+        New->getType()->getScalarSizeInBits())
+      New = Builder.CreateTruncOrBitCast(New, Old->getType());
+
+    return New;
+  }
+
+  if (Value *New = BBMap.lookup(Old))
+    return New;
+
+  if (SE.isSCEVable(Old->getType()))
+    if (const SCEV *Scev = SE.getSCEVAtScope(const_cast<Value *>(Old), L)) {
+      if (!isa<SCEVCouldNotCompute>(Scev)) {
+        const SCEV *NewScev = apply(Scev, LTS, SE);
+        ValueToValueMap VTV;
+        VTV.insert(BBMap.begin(), BBMap.end());
+        VTV.insert(GlobalMap.begin(), GlobalMap.end());
+        NewScev = SCEVParameterRewriter::rewrite(NewScev, SE, VTV);
+        SCEVExpander Expander(SE, Stmt.getParent()
+                                      ->getRegion()
+                                      .getEntry()
+                                      ->getParent()
+                                      ->getParent()
+                                      ->getDataLayout(),
+                              "polly");
+        assert(Builder.GetInsertPoint() != Builder.GetInsertBlock()->end() &&
+               "Only instructions can be insert points for SCEVExpander");
+        Value *Expanded = Expander.expandCodeFor(NewScev, Old->getType(),
+                                                 Builder.GetInsertPoint());
+
+        BBMap[Old] = Expanded;
+        return Expanded;
+      }
+    }
+
+  // A scop-constant value defined by a global or a function parameter.
+  if (isa<GlobalValue>(Old) || isa<Argument>(Old))
+    return const_cast<Value *>(Old);
+
+  // A scop-constant value defined by an instruction executed outside the scop.
+  if (const Instruction *Inst = dyn_cast<Instruction>(Old))
+    if (!Stmt.getParent()->getRegion().contains(Inst->getParent()))
+      return const_cast<Value *>(Old);
+
+  // The scalar dependence is neither available nor SCEVCodegenable.
+  llvm_unreachable("Unexpected scalar dependence in region!");
+  return nullptr;
+}
+
+void BlockGenerator::copyInstScalar(ScopStmt &Stmt, const Instruction *Inst,
+                                    ValueMapT &BBMap, ValueMapT &GlobalMap,
+                                    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, GlobalMap, LTS,
+                                    getLoopForInst(Inst));
+
+    if (!NewOperand) {
+      assert(!isa<StoreInst>(NewInst) &&
+             "Store instructions are always needed!");
+      delete NewInst;
+      return;
+    }
+
+    NewInst->replaceUsesOfWith(OldOperand, NewOperand);
+  }
+
+  Builder.Insert(NewInst);
+  BBMap[Inst] = NewInst;
+
+  if (!NewInst->getType()->isVoidTy())
+    NewInst->setName("p_" + Inst->getName());
+}
+
+Value *BlockGenerator::getNewAccessOperand(ScopStmt &Stmt,
+                                           const MemoryAccess &MA) {
+  isl_pw_multi_aff *PWAccRel;
+  isl_union_map *Schedule;
+  isl_ast_expr *Expr;
+  isl_ast_build *Build = Stmt.getAstBuild();
+
+  assert(ExprBuilder && Build &&
+         "Cannot generate new value without IslExprBuilder!");
+
+  Schedule = isl_ast_build_get_schedule(Build);
+  PWAccRel = MA.applyScheduleToAccessRelation(Schedule);
+
+  Expr = isl_ast_build_access_from_pw_multi_aff(Build, PWAccRel);
+  Expr = isl_ast_expr_address_of(Expr);
+
+  return ExprBuilder->create(Expr);
+}
+
+Value *BlockGenerator::generateLocationAccessed(
+    ScopStmt &Stmt, const Instruction *Inst, const Value *Pointer,
+    ValueMapT &BBMap, ValueMapT &GlobalMap, LoopToScevMapT &LTS) {
+  const MemoryAccess &MA = Stmt.getAccessFor(Inst);
+
+  Value *NewPointer;
+  if (MA.hasNewAccessRelation())
+    NewPointer = getNewAccessOperand(Stmt, MA);
+  else
+    NewPointer =
+        getNewValue(Stmt, Pointer, BBMap, GlobalMap, LTS, getLoopForInst(Inst));
+
+  return NewPointer;
+}
+
+Loop *BlockGenerator::getLoopForInst(const llvm::Instruction *Inst) {
+  return LI.getLoopFor(Inst->getParent());
+}
+
+Value *BlockGenerator::generateScalarLoad(ScopStmt &Stmt, const LoadInst *Load,
+                                          ValueMapT &BBMap,
+                                          ValueMapT &GlobalMap,
+                                          LoopToScevMapT &LTS) {
+  const Value *Pointer = Load->getPointerOperand();
+  Value *NewPointer =
+      generateLocationAccessed(Stmt, Load, Pointer, BBMap, GlobalMap, LTS);
+  Value *ScalarLoad = Builder.CreateAlignedLoad(
+      NewPointer, Load->getAlignment(), Load->getName() + "_p_scalar_");
+  return ScalarLoad;
+}
+
+Value *BlockGenerator::generateScalarStore(ScopStmt &Stmt,
+                                           const StoreInst *Store,
+                                           ValueMapT &BBMap,
+                                           ValueMapT &GlobalMap,
+                                           LoopToScevMapT &LTS) {
+  const Value *Pointer = Store->getPointerOperand();
+  Value *NewPointer =
+      generateLocationAccessed(Stmt, Store, Pointer, BBMap, GlobalMap, LTS);
+  Value *ValueOperand = getNewValue(Stmt, Store->getValueOperand(), BBMap,
+                                    GlobalMap, LTS, getLoopForInst(Store));
+
+  Value *NewStore = Builder.CreateAlignedStore(ValueOperand, NewPointer,
+                                               Store->getAlignment());
+  return NewStore;
+}
+
+void BlockGenerator::copyInstruction(ScopStmt &Stmt, const Instruction *Inst,
+                                     ValueMapT &BBMap, ValueMapT &GlobalMap,
+                                     LoopToScevMapT &LTS) {
+
+  // First check for possible scalar dependences for this instruction.
+  generateScalarLoads(Stmt, Inst, BBMap);
+
+  // Terminator instructions control the control flow. They are explicitly
+  // expressed in the clast and do not need to be copied.
+  if (Inst->isTerminator())
+    return;
+
+  Loop *L = getLoopForInst(Inst);
+  if ((Stmt.isBlockStmt() || !Stmt.getRegion()->contains(L)) &&
+      canSynthesize(Inst, &LI, &SE, &Stmt.getParent()->getRegion())) {
+    Value *NewValue = getNewValue(Stmt, Inst, BBMap, GlobalMap, LTS, L);
+    BBMap[Inst] = NewValue;
+    return;
+  }
+
+  if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
+    Value *NewLoad = generateScalarLoad(Stmt, Load, BBMap, GlobalMap, LTS);
+    // Compute NewLoad before its insertion in BBMap to make the insertion
+    // deterministic.
+    BBMap[Load] = NewLoad;
+    return;
+  }
+
+  if (const StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
+    Value *NewStore = generateScalarStore(Stmt, Store, BBMap, GlobalMap, LTS);
+    // Compute NewStore before its insertion in BBMap to make the insertion
+    // deterministic.
+    BBMap[Store] = NewStore;
+    return;
+  }
+
+  if (const PHINode *PHI = dyn_cast<PHINode>(Inst)) {
+    copyPHIInstruction(Stmt, PHI, BBMap, GlobalMap, 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 (auto *IT = dyn_cast<IntrinsicInst>(Inst)) {
+    switch (IT->getIntrinsicID()) {
+    // Lifetime markers are ignored.
+    case llvm::Intrinsic::lifetime_start:
+    case llvm::Intrinsic::lifetime_end:
+    // Invariant markers are ignored.
+    case llvm::Intrinsic::invariant_start:
+    case llvm::Intrinsic::invariant_end:
+    // Some misc annotations are ignored.
+    case llvm::Intrinsic::var_annotation:
+    case llvm::Intrinsic::ptr_annotation:
+    case llvm::Intrinsic::annotation:
+    case llvm::Intrinsic::donothing:
+    case llvm::Intrinsic::assume:
+    case llvm::Intrinsic::expect:
+      return;
+    default:
+      // Other intrinsics are copied.
+      break;
+    }
+  }
+
+  copyInstScalar(Stmt, Inst, BBMap, GlobalMap, LTS);
+}
+
+void BlockGenerator::copyStmt(ScopStmt &Stmt, ValueMapT &GlobalMap,
+                              LoopToScevMapT &LTS) {
+  assert(Stmt.isBlockStmt() &&
+         "Only block statements can be copied by the block generator");
+
+  ValueMapT BBMap;
+
+  BasicBlock *BB = Stmt.getBasicBlock();
+  copyBB(Stmt, BB, BBMap, GlobalMap, LTS);
+}
+
+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, ValueMapT &GlobalMap,
+                                   LoopToScevMapT &LTS) {
+  BasicBlock *CopyBB = splitBB(BB);
+  copyBB(Stmt, BB, CopyBB, BBMap, GlobalMap, LTS);
+  return CopyBB;
+}
+
+void BlockGenerator::copyBB(ScopStmt &Stmt, BasicBlock *BB, BasicBlock *CopyBB,
+                            ValueMapT &BBMap, ValueMapT &GlobalMap,
+                            LoopToScevMapT &LTS) {
+  Builder.SetInsertPoint(CopyBB->begin());
+  EntryBB = &CopyBB->getParent()->getEntryBlock();
+
+  for (Instruction &Inst : *BB)
+    copyInstruction(Stmt, &Inst, BBMap, GlobalMap, LTS);
+
+  // After a basic block was copied store all scalars that escape this block
+  // in their alloca. First the scalars that have dependences inside the SCoP,
+  // then the ones that might escape the SCoP.
+  generateScalarStores(Stmt, BB, BBMap, GlobalMap);
+
+  const Region &R = Stmt.getParent()->getRegion();
+  for (Instruction &Inst : *BB)
+    handleOutsideUsers(R, &Inst, BBMap[&Inst]);
+}
+
+AllocaInst *BlockGenerator::getOrCreateAlloca(Instruction *ScalarBase,
+                                              ScalarAllocaMapTy &Map,
+                                              const char *NameExt,
+                                              bool *IsNew) {
+
+  // Check if an alloca was cached for the base instruction.
+  AllocaInst *&Addr = Map[ScalarBase];
+
+  // If needed indicate if it was found already or will be created.
+  if (IsNew)
+    *IsNew = (Addr == nullptr);
+
+  // If no alloca was found create one and insert it in the entry block.
+  if (!Addr) {
+    auto *Ty = ScalarBase->getType();
+    Addr = new AllocaInst(Ty, ScalarBase->getName() + NameExt);
+    Addr->insertBefore(EntryBB->getFirstInsertionPt());
+  }
+
+  return Addr;
+}
+
+void BlockGenerator::handleOutsideUsers(const Region &R, Instruction *Inst,
+                                        Value *InstCopy) {
+  BasicBlock *ExitBB = R.getExit();
+
+  EscapeUserVectorTy EscapeUsers;
+  for (User *U : Inst->users()) {
+
+    // Non-instruction user will never escape.
+    Instruction *UI = dyn_cast<Instruction>(U);
+    if (!UI)
+      continue;
+
+    if (R.contains(UI) && ExitBB != UI->getParent())
+      continue;
+
+    EscapeUsers.push_back(UI);
+  }
+
+  // Exit if no escape uses were found.
+  if (EscapeUsers.empty())
+    return;
+
+  // If there are escape users we get the alloca for this instruction and put
+  // it in the EscapeMap for later finalization. However, if the alloca was not
+  // created by an already handled scalar dependence we have to initialize it
+  // also. Lastly, if the instruction was copied multiple times we already did
+  // this and can exit.
+  if (EscapeMap.count(Inst))
+    return;
+
+  // Get or create an escape alloca for this instruction.
+  bool IsNew;
+  AllocaInst *ScalarAddr =
+      getOrCreateAlloca(Inst, ScalarMap, ".escape", &IsNew);
+
+  // Remember that this instruction has escape uses and the escape alloca.
+  EscapeMap[Inst] = std::make_pair(ScalarAddr, std::move(EscapeUsers));
+
+  // If the escape alloca was just created store the instruction in there,
+  // otherwise that happened already.
+  if (IsNew) {
+    assert(InstCopy && "Except PHIs every instruction should have a copy!");
+    Builder.CreateStore(InstCopy, ScalarAddr);
+  }
+}
+
+void BlockGenerator::generateScalarLoads(ScopStmt &Stmt,
+                                         const Instruction *Inst,
+                                         ValueMapT &BBMap) {
+
+  // Iterate over all memory accesses for the given instruction and handle all
+  // scalar reads.
+  if (ScopStmt::MemoryAccessList *MAL = Stmt.lookupAccessesFor(Inst)) {
+    for (MemoryAccess &MA : *MAL) {
+      if (!MA.isScalar() || !MA.isRead())
+        continue;
+
+      Instruction *ScalarBase = cast<Instruction>(MA.getBaseAddr());
+      Instruction *ScalarInst = MA.getAccessInstruction();
+
+      PHINode *ScalarBasePHI = dyn_cast<PHINode>(ScalarBase);
+
+      // This is either a common scalar use (second case) or the use of a phi
+      // operand by the PHI node (first case).
+      if (ScalarBasePHI == ScalarInst) {
+        AllocaInst *PHIOpAddr =
+            getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops");
+        LoadInst *LI =
+            Builder.CreateLoad(PHIOpAddr, PHIOpAddr->getName() + ".reload");
+        BBMap[ScalarBase] = LI;
+      } else {
+        // For non-PHI operand uses we look up the alloca in the ScalarMap,
+        // reload it and add the mapping to the ones in the current basic block.
+        AllocaInst *ScalarAddr =
+            getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
+        LoadInst *LI =
+            Builder.CreateLoad(ScalarAddr, ScalarAddr->getName() + ".reload");
+        BBMap[ScalarBase] = LI;
+      }
+    }
+  }
+}
+
+Value *BlockGenerator::getNewScalarValue(Value *ScalarValue, const Region &R,
+                                         ScalarAllocaMapTy &ReloadMap,
+                                         ValueMapT &BBMap,
+                                         ValueMapT &GlobalMap) {
+  // If the value we want to store is an instruction we might have demoted it
+  // in order to make it accessible here. In such a case a reload is
+  // necessary. If it is no instruction it will always be a value that
+  // dominates the current point and we can just use it. In total there are 4
+  // options:
+  //  (1) The value is no instruction ==> use the value.
+  //  (2) The value is an instruction that was split out of the region prior to
+  //      code generation  ==> use the instruction as it dominates the region.
+  //  (3) The value is an instruction:
+  //      (a) The value was defined in the current block, thus a copy is in
+  //          the BBMap ==> use the mapped value.
+  //      (b) The value was defined in a previous block, thus we demoted it
+  //          earlier ==> use the reloaded value.
+  Instruction *ScalarValueInst = dyn_cast<Instruction>(ScalarValue);
+  if (!ScalarValueInst)
+    return ScalarValue;
+
+  if (!R.contains(ScalarValueInst)) {
+    if (Value *ScalarValueCopy = GlobalMap.lookup(ScalarValueInst))
+      return /* Case (3a) */ ScalarValueCopy;
+    else
+      return /* Case 2 */ ScalarValue;
+  }
+
+  if (Value *ScalarValueCopy = BBMap.lookup(ScalarValueInst))
+    return /* Case (3a) */ ScalarValueCopy;
+
+  // Case (3b)
+  assert(ReloadMap.count(ScalarValueInst) &&
+         "ScalarInst not mapped in the block and not in the given reload map!");
+  Value *ReloadAddr = ReloadMap[ScalarValueInst];
+  ScalarValue =
+      Builder.CreateLoad(ReloadAddr, ReloadAddr->getName() + ".reload");
+
+  return ScalarValue;
+}
+
+void BlockGenerator::generateScalarStores(ScopStmt &Stmt, BasicBlock *BB,
+                                          ValueMapT &BBMap,
+                                          ValueMapT &GlobalMap) {
+  const Region &R = Stmt.getParent()->getRegion();
+
+  assert(Stmt.isBlockStmt() && BB == Stmt.getBasicBlock() &&
+         "Region statements need to use the generateScalarStores() "
+         "function in the RegionGenerator");
+
+  // Set to remember a store to the phiops alloca of a PHINode. It is needed as
+  // we might have multiple write accesses to the same PHI and while one is the
+  // self write of the PHI (to the ScalarMap alloca) the other is the write to
+  // the operand alloca (PHIOpMap).
+  SmallPtrSet<PHINode *, 4> SeenPHIs;
+
+  // Iterate over all accesses in the given statement.
+  for (MemoryAccess *MA : Stmt) {
+
+    // Skip non-scalar and read accesses.
+    if (!MA->isScalar() || MA->isRead())
+      continue;
+
+    Instruction *ScalarBase = cast<Instruction>(MA->getBaseAddr());
+    Instruction *ScalarInst = MA->getAccessInstruction();
+    PHINode *ScalarBasePHI = dyn_cast<PHINode>(ScalarBase);
+
+    // Get the alloca node for the base instruction and the value we want to
+    // store. In total there are 4 options:
+    //  (1) The base is no PHI, hence it is a simple scalar def-use chain.
+    //  (2) The base is a PHI,
+    //      (a) and the write is caused by an operand in the block.
+    //      (b) and it is the PHI self write (same as case (1)).
+    //      (c) (2a) and (2b) are not distinguishable.
+    // For case (1) and (2b) we get the alloca from the scalar map and the value
+    // we want to store is initialized with the instruction attached to the
+    // memory access. For case (2a) we get the alloca from the PHI operand map
+    // and the value we want to store is initialized with the incoming value for
+    // this block. The tricky case (2c) is when both (2a) and (2b) match. This
+    // happens if the PHI operand is in the same block as the PHI. To handle
+    // that we choose the alloca of (2a) first and (2b) for the next write
+    // access to that PHI (there must be 2).
+    Value *ScalarValue = nullptr;
+    AllocaInst *ScalarAddr = nullptr;
+
+    if (!ScalarBasePHI) {
+      // Case (1)
+      ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
+      ScalarValue = ScalarInst;
+    } else {
+      int PHIIdx = ScalarBasePHI->getBasicBlockIndex(BB);
+      if (ScalarBasePHI != ScalarInst) {
+        // Case (2a)
+        assert(PHIIdx >= 0 && "Bad scalar write to PHI operand");
+        SeenPHIs.insert(ScalarBasePHI);
+        ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops");
+        ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx);
+      } else if (PHIIdx < 0) {
+        // Case (2b)
+        ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
+        ScalarValue = ScalarInst;
+      } else {
+        // Case (2c)
+        if (SeenPHIs.insert(ScalarBasePHI).second) {
+          // First access ==> same as (2a)
+          ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops");
+          ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx);
+        } else {
+          // Second access ==> same as (2b)
+          ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
+          ScalarValue = ScalarInst;
+        }
+      }
+    }
+
+    ScalarValue =
+        getNewScalarValue(ScalarValue, R, ScalarMap, BBMap, GlobalMap);
+    Builder.CreateStore(ScalarValue, ScalarAddr);
+  }
+}
+
+void BlockGenerator::createScalarInitialization(Region &R,
+                                                ValueMapT &GlobalMap) {
+  // The split block __just before__ the region and optimized region.
+  BasicBlock *SplitBB = R.getEnteringBlock();
+  BranchInst *SplitBBTerm = cast<BranchInst>(SplitBB->getTerminator());
+  assert(SplitBBTerm->getNumSuccessors() == 2 && "Bad region entering block!");
+
+  // Get the start block of the __optimized__ region.
+  BasicBlock *StartBB = SplitBBTerm->getSuccessor(0);
+  if (StartBB == R.getEntry())
+    StartBB = SplitBBTerm->getSuccessor(1);
+
+  // For each PHI predecessor outside the region store the incoming operand
+  // value prior to entering the optimized region.
+  Builder.SetInsertPoint(StartBB->getTerminator());
+
+  ScalarAllocaMapTy EmptyMap;
+  for (const auto &PHIOpMapping : PHIOpMap) {
+    const PHINode *PHI = cast<PHINode>(PHIOpMapping.getFirst());
+
+    // Check if this PHI has the split block as predecessor (that is the only
+    // possible predecessor outside the SCoP).
+    int idx = PHI->getBasicBlockIndex(SplitBB);
+    if (idx < 0)
+      continue;
+
+    Value *ScalarValue = PHI->getIncomingValue(idx);
+    ScalarValue =
+        getNewScalarValue(ScalarValue, R, EmptyMap, GlobalMap, GlobalMap);
+
+    // If the split block is the predecessor initialize the PHI operator alloca.
+    Builder.CreateStore(ScalarValue, PHIOpMapping.getSecond());
+  }
+}
+
+void BlockGenerator::createScalarFinalization(Region &R) {
+  // The exit block of the __unoptimized__ region.
+  BasicBlock *ExitBB = R.getExitingBlock();
+  // The merge block __just after__ the region and the optimized region.
+  BasicBlock *MergeBB = R.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.getFirst();
+    const auto &EscapeMappingValue = EscapeMapping.getSecond();
+    const EscapeUserVectorTy &EscapeUsers = EscapeMappingValue.second;
+    AllocaInst *ScalarAddr = EscapeMappingValue.first;
+
+    // Reload the demoted instruction in the optimized version of the SCoP.
+    Instruction *EscapeInstReload =
+        Builder.CreateLoad(ScalarAddr, EscapeInst->getName() + ".final_reload");
+
+    // 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::finalizeSCoP(Scop &S, ValueMapT &GlobalMap) {
+  createScalarInitialization(S.getRegion(), GlobalMap);
+  createScalarFinalization(S.getRegion());
+}
+
+VectorBlockGenerator::VectorBlockGenerator(BlockGenerator &BlockGen,
+                                           VectorValueMapT &GlobalMaps,
+                                           std::vector<LoopToScevMapT> &VLTS,
+                                           isl_map *Schedule)
+    : BlockGenerator(BlockGen), GlobalMaps(GlobalMaps), VLTS(VLTS),
+      Schedule(Schedule) {
+  assert(GlobalMaps.size() > 1 && "Only one vector lane found");
+  assert(Schedule && "No statement domain provided");
+}
+
+Value *VectorBlockGenerator::getVectorValue(ScopStmt &Stmt, const 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], GlobalMaps[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, const LoadInst *Load, VectorValueMapT &ScalarMaps,
+    bool NegativeStride = false) {
+  unsigned VectorWidth = getVectorWidth();
+  const Value *Pointer = Load->getPointerOperand();
+  Type *VectorPtrType = getVectorPtrTy(Pointer, VectorWidth);
+  unsigned Offset = NegativeStride ? VectorWidth - 1 : 0;
+
+  Value *NewPointer = nullptr;
+  NewPointer = generateLocationAccessed(Stmt, Load, Pointer, ScalarMaps[Offset],
+                                        GlobalMaps[Offset], VLTS[Offset]);
+  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,
+                                                    const LoadInst *Load,
+                                                    ValueMapT &BBMap) {
+  const Value *Pointer = Load->getPointerOperand();
+  Type *VectorPtrType = getVectorPtrTy(Pointer, 1);
+  Value *NewPointer = generateLocationAccessed(Stmt, Load, Pointer, BBMap,
+                                               GlobalMaps[0], VLTS[0]);
+  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, const LoadInst *Load, VectorValueMapT &ScalarMaps) {
+  int VectorWidth = getVectorWidth();
+  const Value *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, Pointer, ScalarMaps[i], GlobalMaps[i], VLTS[i]);
+    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, const LoadInst *Load,
+                                        ValueMapT &VectorMap,
+                                        VectorValueMapT &ScalarMaps) {
+  if (!VectorType::isValidElementType(Load->getType())) {
+    for (int i = 0; i < getVectorWidth(); i++)
+      ScalarMaps[i][Load] =
+          generateScalarLoad(Stmt, Load, ScalarMaps[i], GlobalMaps[i], VLTS[i]);
+    return;
+  }
+
+  const MemoryAccess &Access = Stmt.getAccessFor(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_map_copy(Schedule)))
+    NewLoad = generateStrideZeroLoad(Stmt, Load, ScalarMaps[0]);
+  else if (Access.isStrideOne(isl_map_copy(Schedule)))
+    NewLoad = generateStrideOneLoad(Stmt, Load, ScalarMaps);
+  else if (Access.isStrideX(isl_map_copy(Schedule), -1))
+    NewLoad = generateStrideOneLoad(Stmt, Load, ScalarMaps, true);
+  else
+    NewLoad = generateUnknownStrideLoad(Stmt, Load, ScalarMaps);
+
+  VectorMap[Load] = NewLoad;
+}
+
+void VectorBlockGenerator::copyUnaryInst(ScopStmt &Stmt,
+                                         const UnaryInstruction *Inst,
+                                         ValueMapT &VectorMap,
+                                         VectorValueMapT &ScalarMaps) {
+  int VectorWidth = getVectorWidth();
+  Value *NewOperand = getVectorValue(Stmt, Inst->getOperand(0), VectorMap,
+                                     ScalarMaps, getLoopForInst(Inst));
+
+  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,
+                                          const BinaryOperator *Inst,
+                                          ValueMapT &VectorMap,
+                                          VectorValueMapT &ScalarMaps) {
+  Loop *L = getLoopForInst(Inst);
+  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, const StoreInst *Store,
+                                     ValueMapT &VectorMap,
+                                     VectorValueMapT &ScalarMaps) {
+  const MemoryAccess &Access = Stmt.getAccessFor(Store);
+
+  const Value *Pointer = Store->getPointerOperand();
+  Value *Vector = getVectorValue(Stmt, Store->getValueOperand(), VectorMap,
+                                 ScalarMaps, getLoopForInst(Store));
+
+  // Make sure we have scalar values available to access the pointer to
+  // the data location.
+  extractScalarValues(Store, VectorMap, ScalarMaps);
+
+  if (Access.isStrideOne(isl_map_copy(Schedule))) {
+    Type *VectorPtrType = getVectorPtrTy(Pointer, getVectorWidth());
+    Value *NewPointer = generateLocationAccessed(
+        Stmt, Store, Pointer, ScalarMaps[0], GlobalMaps[0], VLTS[0]);
+
+    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, Pointer, ScalarMaps[i], GlobalMaps[i], VLTS[i]);
+      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
+      // existance of all of them.
+      if (SM.count(Operand))
+        break;
+
+      SM[Operand] =
+          Builder.CreateExtractElement(NewVector, Builder.getInt32(i));
+    }
+  }
+
+  return HasVectorOperand;
+}
+
+void VectorBlockGenerator::copyInstScalarized(ScopStmt &Stmt,
+                                              const Instruction *Inst,
+                                              ValueMapT &VectorMap,
+                                              VectorValueMapT &ScalarMaps) {
+  bool HasVectorOperand;
+  int VectorWidth = getVectorWidth();
+
+  HasVectorOperand = extractScalarValues(Inst, VectorMap, ScalarMaps);
+
+  for (int VectorLane = 0; VectorLane < getVectorWidth(); VectorLane++)
+    BlockGenerator::copyInstruction(Stmt, Inst, ScalarMaps[VectorLane],
+                                    GlobalMaps[VectorLane], VLTS[VectorLane]);
+
+  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 GlobalMaps.size(); }
+
+void VectorBlockGenerator::copyInstruction(ScopStmt &Stmt,
+                                           const Instruction *Inst,
+                                           ValueMapT &VectorMap,
+                                           VectorValueMapT &ScalarMaps) {
+  // 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 (canSynthesize(Inst, &LI, &SE, &Stmt.getParent()->getRegion()))
+    return;
+
+  if (const LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
+    generateLoad(Stmt, Load, VectorMap, ScalarMaps);
+    return;
+  }
+
+  if (hasVectorOperands(Inst, VectorMap)) {
+    if (const StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
+      copyStore(Stmt, Store, VectorMap, ScalarMaps);
+      return;
+    }
+
+    if (const UnaryInstruction *Unary = dyn_cast<UnaryInstruction>(Inst)) {
+      copyUnaryInst(Stmt, Unary, VectorMap, ScalarMaps);
+      return;
+    }
+
+    if (const BinaryOperator *Binary = dyn_cast<BinaryOperator>(Inst)) {
+      copyBinaryInst(Stmt, Binary, VectorMap, ScalarMaps);
+      return;
+    }
+
+    // Falltrough: We generate scalar instructions, if we don't know how to
+    // generate vector code.
+  }
+
+  copyInstScalarized(Stmt, Inst, VectorMap, ScalarMaps);
+}
+
+void VectorBlockGenerator::copyStmt(ScopStmt &Stmt) {
+  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->begin());
+
+  // 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;
+
+  for (Instruction &Inst : *BB)
+    copyInstruction(Stmt, &Inst, VectorBlockMap, ScalarBlockMap);
+}
+
+BasicBlock *RegionGenerator::repairDominance(BasicBlock *BB,
+                                             BasicBlock *BBCopy) {
+
+  BasicBlock *BBIDom = DT.getNode(BB)->getIDom()->getBlock();
+  BasicBlock *BBCopyIDom = BlockMap.lookup(BBIDom);
+
+  if (BBCopyIDom)
+    DT.changeImmediateDominator(BBCopy, BBCopyIDom);
+
+  return BBCopyIDom;
+}
+
+void RegionGenerator::copyStmt(ScopStmt &Stmt, ValueMapT &GlobalMap,
+                               LoopToScevMapT &LTS) {
+  assert(Stmt.isRegionStmt() &&
+         "Only region statements can be copied by the block generator");
+
+  // Forget all old mappings.
+  BlockMap.clear();
+  RegionMaps.clear();
+  IncompletePHINodeMap.clear();
+
+  // 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->begin());
+
+  for (auto PI = pred_begin(EntryBB), PE = pred_end(EntryBB); PI != PE; ++PI)
+    if (!R->contains(*PI))
+      BlockMap[*PI] = EntryBBCopy;
+
+  // Iterate over all blocks in the region in a breadth-first search.
+  std::deque<BasicBlock *> Blocks;
+  SmallPtrSet<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);
+
+    // In order to remap PHI nodes we store also basic block mappings.
+    BlockMap[BB] = BBCopy;
+
+    // Get the mapping for this block and initialize it with the mapping
+    // available at its immediate dominator (in the new region).
+    ValueMapT &RegionMap = RegionMaps[BBCopy];
+    RegionMap = RegionMaps[BBCopyIDom];
+
+    // Copy the block with the BlockGenerator.
+    copyBB(Stmt, BB, BBCopy, RegionMap, GlobalMap, LTS);
+
+    // In order to remap PHI nodes we store also basic block mappings.
+    BlockMap[BB] = BBCopy;
+
+    // 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,
+                      GlobalMap, 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).second)
+        Blocks.push_back(*SI);
+  }
+
+  // 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");
+  BlockMap[R->getExit()] = ExitBBCopy;
+
+  repairDominance(R->getExit(), ExitBBCopy);
+
+  // 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) {
+
+    BranchInst *BI = cast<BranchInst>(BB->getTerminator());
+
+    BasicBlock *BBCopy = BlockMap[BB];
+    Instruction *BICopy = BBCopy->getTerminator();
+
+    ValueMapT &RegionMap = RegionMaps[BBCopy];
+    RegionMap.insert(BlockMap.begin(), BlockMap.end());
+
+    Builder.SetInsertPoint(BICopy);
+    copyInstScalar(Stmt, BI, RegionMap, GlobalMap, LTS);
+    BICopy->eraseFromParent();
+  }
+
+  // Add counting PHI nodes to all loops in the region that can be used as
+  // replacement for SCEVs refering to the old loop.
+  for (BasicBlock *BB : SeenBlocks) {
+    Loop *L = LI.getLoopFor(BB);
+    if (L == nullptr || L->getHeader() != BB)
+      continue;
+
+    BasicBlock *BBCopy = BlockMap[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->begin());
+    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, BlockMap[PredBB]);
+      else
+        LoopPHI->addIncoming(NullVal, BlockMap[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);
+  }
+
+  // Add all mappings from the region to the global map so outside uses will use
+  // the copied instructions.
+  for (auto &BBMap : RegionMaps)
+    GlobalMap.insert(BBMap.second.begin(), BBMap.second.end());
+
+  // Reset the old insert point for the build.
+  Builder.SetInsertPoint(ExitBBCopy->begin());
+}
+
+void RegionGenerator::generateScalarLoads(ScopStmt &Stmt,
+                                          const Instruction *Inst,
+                                          ValueMapT &BBMap) {
+
+  // Inside a non-affine region PHI nodes are copied not demoted. Once the
+  // phi is copied it will reload all inputs from outside the region, hence
+  // we do not need to generate code for the read access of the operands of a
+  // PHI.
+  if (isa<PHINode>(Inst))
+    return;
+
+  return BlockGenerator::generateScalarLoads(Stmt, Inst, BBMap);
+}
+
+void RegionGenerator::generateScalarStores(ScopStmt &Stmt, BasicBlock *BB,
+                                           ValueMapT &BBMap,
+                                           ValueMapT &GlobalMap) {
+  const Region &R = Stmt.getParent()->getRegion();
+
+  Region *StmtR = Stmt.getRegion();
+  assert(StmtR && "Block statements need to use the generateScalarStores() "
+                  "function in the BlockGenerator");
+
+  BasicBlock *ExitBB = StmtR->getExit();
+
+  // For region statements three kinds of scalar stores exists:
+  //  (1) A definition used by a non-phi instruction outside the region.
+  //  (2) A phi-instruction in the region entry.
+  //  (3) A write to a phi instruction in the region exit.
+  // The last case is the tricky one since we do not know anymore which
+  // predecessor of the exit needs to store the operand value that doesn't
+  // have a definition in the region. Therefore, we have to check in each
+  // block in the region if we should store the value or not.
+
+  // Iterate over all accesses in the given statement.
+  for (MemoryAccess *MA : Stmt) {
+
+    // Skip non-scalar and read accesses.
+    if (!MA->isScalar() || MA->isRead())
+      continue;
+
+    Instruction *ScalarBase = cast<Instruction>(MA->getBaseAddr());
+    Instruction *ScalarInst = MA->getAccessInstruction();
+    PHINode *ScalarBasePHI = dyn_cast<PHINode>(ScalarBase);
+
+    Value *ScalarValue = nullptr;
+    AllocaInst *ScalarAddr = nullptr;
+
+    if (!ScalarBasePHI) {
+      // Case (1)
+      ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
+      ScalarValue = ScalarInst;
+    } else if (ScalarBasePHI->getParent() != ExitBB) {
+      // Case (2)
+      assert(ScalarBasePHI->getParent() == StmtR->getEntry() &&
+             "Bad PHI self write in non-affine region");
+      assert(ScalarBase == ScalarInst &&
+             "Bad PHI self write in non-affine region");
+      ScalarAddr = getOrCreateAlloca(ScalarBase, ScalarMap, ".s2a");
+      ScalarValue = ScalarInst;
+    } else {
+      int PHIIdx = ScalarBasePHI->getBasicBlockIndex(BB);
+      // Skip accesses we will not handle in this basic block but in another one
+      // in the statement region.
+      if (PHIIdx < 0)
+        continue;
+
+      // Case (3)
+      ScalarAddr = getOrCreateAlloca(ScalarBase, PHIOpMap, ".phiops");
+      ScalarValue = ScalarBasePHI->getIncomingValue(PHIIdx);
+    }
+
+    ScalarValue =
+        getNewScalarValue(ScalarValue, R, ScalarMap, BBMap, GlobalMap);
+    Builder.CreateStore(ScalarValue, ScalarAddr);
+  }
+}
+
+void RegionGenerator::addOperandToPHI(ScopStmt &Stmt, const PHINode *PHI,
+                                      PHINode *PHICopy, BasicBlock *IncomingBB,
+                                      ValueMapT &GlobalMap,
+                                      LoopToScevMapT &LTS) {
+  Region *StmtR = Stmt.getRegion();
+
+  // 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 *BBCopy = BlockMap[IncomingBB];
+  if (!BBCopy) {
+    assert(StmtR->contains(IncomingBB) &&
+           "Bad incoming block for PHI in non-affine region");
+    IncompletePHINodeMap[IncomingBB].push_back(std::make_pair(PHI, PHICopy));
+    return;
+  }
+
+  Value *OpCopy = nullptr;
+  if (StmtR->contains(IncomingBB)) {
+    assert(RegionMaps.count(BBCopy) &&
+           "Incoming PHI block did not have a BBMap");
+    ValueMapT &BBCopyMap = RegionMaps[BBCopy];
+
+    Value *Op = PHI->getIncomingValueForBlock(IncomingBB);
+    OpCopy =
+        getNewValue(Stmt, Op, BBCopyMap, GlobalMap, LTS, getLoopForInst(PHI));
+  } else {
+
+    if (PHICopy->getBasicBlockIndex(BBCopy) >= 0)
+      return;
+
+    AllocaInst *PHIOpAddr =
+        getOrCreateAlloca(const_cast<PHINode *>(PHI), PHIOpMap, ".phiops");
+    OpCopy = new LoadInst(PHIOpAddr, PHIOpAddr->getName() + ".reload",
+                          BlockMap[IncomingBB]->getTerminator());
+  }
+
+  assert(OpCopy && "Incoming PHI value was not copied properly");
+  assert(BBCopy && "Incoming PHI block was not copied properly");
+  PHICopy->addIncoming(OpCopy, BBCopy);
+}
+
+Value *RegionGenerator::copyPHIInstruction(ScopStmt &Stmt, const PHINode *PHI,
+                                           ValueMapT &BBMap,
+                                           ValueMapT &GlobalMap,
+                                           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 (unsigned u = 0; u < NumIncoming; u++)
+    addOperandToPHI(Stmt, PHI, PHICopy, PHI->getIncomingBlock(u), GlobalMap,
+                    LTS);
+  return PHICopy;
+}
diff --git a/final/lib/CodeGen/CodeGeneration.cpp b/final/lib/CodeGen/CodeGeneration.cpp
new file mode 100644
index 0000000..aef6561
--- /dev/null
+++ b/final/lib/CodeGen/CodeGeneration.cpp
@@ -0,0 +1,183 @@
+//===------ 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 behaviour 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/IslNodeBuilder.h"
+#include "polly/CodeGen/IslAst.h"
+#include "polly/CodeGen/Utils.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/ScopHelper.h"
+#include "polly/TempScopInfo.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/Debug.h"
+
+using namespace polly;
+using namespace llvm;
+
+#define DEBUG_TYPE "polly-codegen"
+
+namespace {
+class CodeGeneration : public ScopPass {
+public:
+  static char ID;
+
+  CodeGeneration() : ScopPass(ID) {}
+
+  /// @brief The datalayout used
+  const DataLayout *DL;
+
+  /// @name The analysis passes we need to generate code.
+  ///
+  ///{
+  LoopInfo *LI;
+  IslAstInfo *AI;
+  DominatorTree *DT;
+  ScalarEvolution *SE;
+  ///}
+
+  /// @brief The loop annotator to generate llvm.loop metadata.
+  ScopAnnotator Annotator;
+
+  /// @brief Build the runtime condition.
+  ///
+  /// Build the condition that evaluates at run-time to true iff all
+  /// assumptions taken for the SCoP hold, and to false otherwise.
+  ///
+  /// @return A value evaluating to true/false if execution is save/unsafe.
+  Value *buildRTC(PollyIRBuilder &Builder, IslExprBuilder &ExprBuilder) {
+    Builder.SetInsertPoint(Builder.GetInsertBlock()->getTerminator());
+    Value *RTC = ExprBuilder.create(AI->getRunCondition());
+    if (!RTC->getType()->isIntegerTy(1))
+      RTC = Builder.CreateIsNotNull(RTC);
+    return RTC;
+  }
+
+  bool verifyGeneratedFunction(Scop &S, Function &F) {
+    if (!verifyFunction(F))
+      return false;
+
+    DEBUG({
+      errs() << "== ISL Codegen created an invalid function ==\n\n== The "
+                "SCoP ==\n";
+      S.print(errs());
+      errs() << "\n== The isl AST ==\n";
+      AI->printScop(errs(), S);
+      errs() << "\n== The invalid function ==\n";
+      F.print(errs());
+      errs() << "\n== The errors ==\n";
+      verifyFunction(F, &errs());
+    });
+
+    return true;
+  }
+
+  bool runOnScop(Scop &S) override {
+    AI = &getAnalysis<IslAstInfo>();
+
+    // Check if we created an isl_ast root node, otherwise exit.
+    isl_ast_node *AstRoot = AI->getAst();
+    if (!AstRoot)
+      return false;
+
+    LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+    DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+    SE = &getAnalysis<ScalarEvolution>();
+    DL = &S.getRegion().getEntry()->getParent()->getParent()->getDataLayout();
+
+    assert(!S.getRegion().isTopLevelRegion() &&
+           "Top level regions are not supported");
+
+    Annotator.buildAliasScopes(S);
+
+    BasicBlock *EnteringBB = simplifyRegion(&S, this);
+    PollyIRBuilder Builder = createPollyIRBuilder(EnteringBB, Annotator);
+
+    IslNodeBuilder NodeBuilder(Builder, Annotator, this, *DL, *LI, *SE, *DT, S);
+
+    // 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.
+    BasicBlock *StartBlock =
+        executeScopConditionally(S, this, Builder.getTrue());
+    auto SplitBlock = StartBlock->getSinglePredecessor();
+    Builder.SetInsertPoint(SplitBlock->getTerminator());
+    NodeBuilder.addParameters(S.getContext());
+    Value *RTC = buildRTC(Builder, NodeBuilder.getExprBuilder());
+    SplitBlock->getTerminator()->setOperand(0, RTC);
+    Builder.SetInsertPoint(StartBlock->begin());
+
+    NodeBuilder.create(AstRoot);
+
+    NodeBuilder.finalizeSCoP(S);
+
+    assert(!verifyGeneratedFunction(S, *EnteringBB->getParent()) &&
+           "Verification of generated function failed");
+    return true;
+  }
+
+  void printScop(raw_ostream &, Scop &) const override {}
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequired<DominatorTreeWrapperPass>();
+    AU.addRequired<IslAstInfo>();
+    AU.addRequired<RegionInfoPass>();
+    AU.addRequired<ScalarEvolution>();
+    AU.addRequired<ScopDetection>();
+    AU.addRequired<ScopInfo>();
+    AU.addRequired<LoopInfoWrapperPass>();
+
+    AU.addPreserved<DependenceInfo>();
+
+    AU.addPreserved<LoopInfoWrapperPass>();
+    AU.addPreserved<DominatorTreeWrapperPass>();
+    AU.addPreserved<IslAstInfo>();
+    AU.addPreserved<ScopDetection>();
+    AU.addPreserved<ScalarEvolution>();
+
+    // FIXME: We do not yet add regions for the newly generated code to the
+    //        region tree.
+    AU.addPreserved<RegionInfoPass>();
+    AU.addPreserved<TempScopInfo>();
+    AU.addPreserved<ScopInfo>();
+    AU.addPreservedID(IndependentBlocksID);
+  }
+};
+}
+
+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(ScalarEvolution);
+INITIALIZE_PASS_DEPENDENCY(ScopDetection);
+INITIALIZE_PASS_END(CodeGeneration, "polly-codegen",
+                    "Polly - Create LLVM-IR from SCoPs", false, false)
diff --git a/final/lib/CodeGen/IRBuilder.cpp b/final/lib/CodeGen/IRBuilder.cpp
new file mode 100644
index 0000000..65f6fe8
--- /dev/null
+++ b/final/lib/CodeGen/IRBuilder.cpp
@@ -0,0 +1,147 @@
+//===------ 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/IR/Metadata.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace polly;
+
+/// @brief 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();
+
+  SetVector<Value *> BasePtrs;
+  for (ScopStmt &Stmt : S)
+    for (MemoryAccess *MA : Stmt)
+      BasePtrs.insert(MA->getBaseAddr());
+
+  std::string AliasScopeStr = "polly.alias.scope.";
+  for (Value *BasePtr : BasePtrs)
+    AliasScopeMap[BasePtr] = getID(
+        Ctx, AliasScopeDomain,
+        MDString::get(Ctx, (AliasScopeStr + BasePtr->getName()).str().c_str()));
+
+  for (Value *BasePtr : BasePtrs) {
+    MDNode *AliasScopeList = MDNode::get(Ctx, {});
+    for (const auto &AliasScopePair : AliasScopeMap) {
+      if (BasePtr == AliasScopePair.first)
+        continue;
+
+      Metadata *Args = {AliasScopePair.second};
+      AliasScopeList =
+          MDNode::concatenate(AliasScopeList, MDNode::get(Ctx, Args));
+    }
+
+    OtherAliasScopeListMap[BasePtr] = 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) const {
+  if (!IsParallel)
+    return;
+
+  assert(!ParallelLoops.empty() && "Expected a parallel loop to annotate");
+  MDNode *Ids = ParallelLoops.back();
+  MDNode *Id = cast<MDNode>(Ids->getOperand(Ids->getNumOperands() - 1));
+  B->setMetadata("llvm.loop", Id);
+}
+
+void ScopAnnotator::annotate(Instruction *Inst) {
+  if (!Inst->mayReadOrWriteMemory())
+    return;
+
+  // TODO: Use the ScopArrayInfo once available here.
+  if (AliasScopeDomain) {
+    Value *BasePtr = nullptr;
+    if (isa<StoreInst>(Inst) || isa<LoadInst>(Inst)) {
+      const SCEV *PtrSCEV = SE->getSCEV(getPointerOperand(*Inst));
+      const SCEV *BaseSCEV = SE->getPointerBase(PtrSCEV);
+      if (const SCEVUnknown *SU = dyn_cast<SCEVUnknown>(BaseSCEV))
+        BasePtr = SU->getValue();
+    }
+
+    if (BasePtr) {
+      Inst->setMetadata("alias.scope", AliasScopeMap[BasePtr]);
+      Inst->setMetadata("noalias", OtherAliasScopeListMap[BasePtr]);
+    }
+  }
+
+  if (ParallelLoops.empty())
+    return;
+
+  Inst->setMetadata("llvm.mem.parallel_loop_access", ParallelLoops.back());
+}
diff --git a/final/lib/CodeGen/IslAst.cpp b/final/lib/CodeGen/IslAst.cpp
new file mode 100644
index 0000000..9f564bc
--- /dev/null
+++ b/final/lib/CodeGen/IslAst.cpp
@@ -0,0 +1,581 @@
+//===- 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 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);
+// }
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/CodeGen/CodeGeneration.h"
+#include "polly/CodeGen/IslAst.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/RegionInfo.h"
+#include "llvm/Support/Debug.h"
+#include "isl/aff.h"
+#include "isl/ast_build.h"
+#include "isl/list.h"
+#include "isl/map.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+
+#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> 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(false), 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));
+
+static cl::opt<bool> NoEarlyExit(
+    "polly-no-early-exit",
+    cl::desc("Do not exit early if no benefit of the Polly version was found."),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+namespace polly {
+class IslAst {
+public:
+  IslAst(Scop *Scop, const Dependences &D);
+
+  ~IslAst();
+
+  /// Print a source code representation of the program.
+  void pprint(llvm::raw_ostream &OS);
+
+  __isl_give isl_ast_node *getAst();
+
+  /// @brief Get the run-time conditions for the Scop.
+  __isl_give isl_ast_expr *getRunCondition();
+
+private:
+  Scop *S;
+  isl_ast_node *Root;
+  isl_ast_expr *RunCondition;
+
+  void buildRunCondition(__isl_keep isl_ast_build *Build);
+};
+} // End namespace polly.
+
+/// @brief 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);
+}
+
+/// @brief Temporary information used when building the ast.
+struct AstBuildUserInfo {
+  /// @brief Construct and initialize the helper struct for AST creation.
+  AstBuildUserInfo()
+      : Deps(nullptr), InParallelFor(false), LastForNodeId(nullptr) {}
+
+  /// @brief The dependence information used for the parallelism check.
+  const Dependences *Deps;
+
+  /// @brief Flag to indicate that we are inside a parallel for node.
+  bool InParallelFor;
+
+  /// @brief The last iterator id created for the current SCoP.
+  isl_id *LastForNodeId;
+};
+
+/// @brief 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);
+}
+
+/// @brief 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->getBaseAddr()->getName().str();
+
+  // 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;
+}
+
+/// @brief 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);
+}
+
+/// @brief 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 reveresal. 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
+      Payload->IsInnermostParallel =
+          astScheduleDimIsParallel(Build, BuildInfo->Deps, Payload);
+  }
+  if (Payload->IsOutermostParallel)
+    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);
+}
+
+void IslAst::buildRunCondition(__isl_keep isl_ast_build *Build) {
+  // The conditions that need to be checked at run-time for this scop are
+  // available as an isl_set in the AssumedContext from which we can directly
+  // derive a run-time condition.
+  RunCondition = isl_ast_build_expr_from_set(Build, S->getAssumedContext());
+
+  // Create the alias checks from the minimal/maximal accesses in each alias
+  // group. This operation is by construction quadratic in the number of
+  // elements in each alias group.
+  isl_ast_expr *NonAliasGroup, *MinExpr, *MaxExpr;
+  for (const Scop::MinMaxVectorTy *MinMaxAccesses : S->getAliasGroups()) {
+    auto AccEnd = MinMaxAccesses->end();
+    for (auto AccIt0 = MinMaxAccesses->begin(); AccIt0 != AccEnd; ++AccIt0) {
+      for (auto AccIt1 = AccIt0 + 1; AccIt1 != AccEnd; ++AccIt1) {
+        MinExpr =
+            isl_ast_expr_address_of(isl_ast_build_access_from_pw_multi_aff(
+                Build, isl_pw_multi_aff_copy(AccIt0->first)));
+        MaxExpr =
+            isl_ast_expr_address_of(isl_ast_build_access_from_pw_multi_aff(
+                Build, isl_pw_multi_aff_copy(AccIt1->second)));
+        NonAliasGroup = isl_ast_expr_le(MaxExpr, MinExpr);
+        MinExpr =
+            isl_ast_expr_address_of(isl_ast_build_access_from_pw_multi_aff(
+                Build, isl_pw_multi_aff_copy(AccIt1->first)));
+        MaxExpr =
+            isl_ast_expr_address_of(isl_ast_build_access_from_pw_multi_aff(
+                Build, isl_pw_multi_aff_copy(AccIt0->second)));
+        NonAliasGroup =
+            isl_ast_expr_or(NonAliasGroup, isl_ast_expr_le(MaxExpr, MinExpr));
+        RunCondition = isl_ast_expr_and(RunCondition, NonAliasGroup);
+      }
+    }
+  }
+}
+
+/// @brief 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) {
+
+  // First check the user choice.
+  if (NoEarlyExit)
+    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;
+}
+
+IslAst::IslAst(Scop *Scop, const Dependences &D)
+    : S(Scop), Root(nullptr), RunCondition(nullptr) {
+
+  bool PerformParallelTest = PollyParallel || DetectParallel ||
+                             PollyVectorizerChoice != VECTORIZER_NONE;
+
+  // Skip AST and code generation if there was no benefit achieved.
+  if (!benefitsFromPolly(Scop, PerformParallelTest))
+    return;
+
+  isl_ctx *Ctx = S->getIslCtx();
+  isl_options_set_ast_build_atomic_upper_bound(Ctx, true);
+  isl_ast_build *Build;
+  AstBuildUserInfo BuildInfo;
+
+  if (UseContext)
+    Build = isl_ast_build_from_context(S->getContext());
+  else
+    Build = isl_ast_build_from_context(isl_set_universe(S->getParamSpace()));
+
+  Build = isl_ast_build_set_at_each_domain(Build, AtEachDomain, nullptr);
+
+  if (PerformParallelTest) {
+    BuildInfo.Deps = &D;
+    BuildInfo.InParallelFor = 0;
+
+    Build = isl_ast_build_set_before_each_for(Build, &astBuildBeforeFor,
+                                              &BuildInfo);
+    Build =
+        isl_ast_build_set_after_each_for(Build, &astBuildAfterFor, &BuildInfo);
+  }
+
+  buildRunCondition(Build);
+
+  Root = isl_ast_build_node_from_schedule(Build, S->getScheduleTree());
+
+  isl_ast_build_free(Build);
+}
+
+IslAst::~IslAst() {
+  isl_ast_node_free(Root);
+  isl_ast_expr_free(RunCondition);
+}
+
+__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);
+}
+
+void IslAstInfo::releaseMemory() {
+  if (Ast) {
+    delete Ast;
+    Ast = nullptr;
+  }
+}
+
+bool IslAstInfo::runOnScop(Scop &Scop) {
+  if (Ast)
+    delete Ast;
+
+  S = &Scop;
+
+  const Dependences &D = getAnalysis<DependenceInfo>().getDependences();
+
+  Ast = new IslAst(&Scop, D);
+
+  DEBUG(printScop(dbgs(), Scop));
+  return false;
+}
+
+__isl_give isl_ast_node *IslAstInfo::getAst() const { return Ast->getAst(); }
+__isl_give isl_ast_expr *IslAstInfo::getRunCondition() const {
+  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_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_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;
+}
+
+void IslAstInfo::printScop(raw_ostream &OS, Scop &S) const {
+  isl_ast_print_options *Options;
+  isl_ast_node *RootNode = getAst();
+  Function *F = S.getRegion().getEntry()->getParent();
+
+  OS << ":: isl ast :: " << F->getName() << " :: " << S.getRegion().getNameStr()
+     << "\n";
+
+  if (!RootNode) {
+    OS << ":: isl ast generation and code generation was skipped!\n\n";
+    return;
+  }
+
+  isl_ast_expr *RunCondition = getRunCondition();
+  char *RtCStr, *AstStr;
+
+  Options = isl_ast_print_options_alloc(S.getIslCtx());
+  Options = isl_ast_print_options_set_print_for(Options, cbPrintFor, nullptr);
+
+  isl_printer *P = isl_printer_to_str(S.getIslCtx());
+  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_printer_set_output_format(P, ISL_FORMAT_C);
+  P = isl_ast_node_print(RootNode, P, Options);
+  AstStr = isl_printer_get_str(P);
+
+  isl_union_map *Schedule =
+      isl_union_map_intersect_domain(S.getSchedule(), S.getDomains());
+
+  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_union_map_free(Schedule);
+  isl_ast_node_free(RootNode);
+  isl_printer_free(P);
+}
+
+void IslAstInfo::getAnalysisUsage(AnalysisUsage &AU) const {
+  // Get the Common analysis usage of ScopPasses.
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequired<ScopInfo>();
+  AU.addRequired<DependenceInfo>();
+}
+
+char IslAstInfo::ID = 0;
+
+Pass *polly::createIslAstInfoPass() { return new IslAstInfo(); }
+
+INITIALIZE_PASS_BEGIN(IslAstInfo, "polly-ast",
+                      "Polly - Generate an AST of the SCoP (isl)", false,
+                      false);
+INITIALIZE_PASS_DEPENDENCY(ScopInfo);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_END(IslAstInfo, "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..a725d1c
--- /dev/null
+++ b/final/lib/CodeGen/IslExprBuilder.cpp
@@ -0,0 +1,655 @@
+//===------ 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/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+using namespace llvm;
+using namespace polly;
+
+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 Builder.CreateNSWNeg(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");
+
+  Value *V;
+
+  V = create(isl_ast_expr_get_op_arg(Expr, 0));
+
+  for (int i = 0; i < isl_ast_expr_get_op_n_arg(Expr); ++i) {
+    Value *OpV;
+    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);
+
+    switch (isl_ast_expr_get_op_type(Expr)) {
+    default:
+      llvm_unreachable("This is no n-ary isl ast expression");
+
+    case isl_ast_op_max: {
+      Value *Cmp = Builder.CreateICmpSGT(V, OpV);
+      V = Builder.CreateSelect(Cmp, V, OpV);
+      continue;
+    }
+    case isl_ast_op_min: {
+      Value *Cmp = Builder.CreateICmpSLT(V, OpV);
+      V = Builder.CreateSelect(Cmp, V, OpV);
+      continue;
+    }
+    }
+  }
+
+  // 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) >= 2 &&
+         "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 = ScopArrayInfo::getFromId(BaseId);
+  Base = SAI->getBasePtr();
+  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);
+  }
+
+  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 (!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 =
+          Builder.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 - 1);
+    Value *DimSize = Expander.expandCodeFor(DimSCEV, DimSCEV->getType(),
+                                            Builder.GetInsertPoint());
+
+    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 =
+        Builder.CreateMul(IndexOp, DimSize, "polly.access.mul." + BaseName);
+  }
+
+  Access = Builder.CreateGEP(Base, IndexOp, "polly.access." + BaseName);
+
+  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_expr *LOp, *ROp;
+  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);
+
+  LOp = isl_ast_expr_get_op_arg(Expr, 0);
+  ROp = isl_ast_expr_get_op_arg(Expr, 1);
+
+  // Catch the special case ((-<pointer>) + <pointer>) which is for
+  // isl the same as (<pointer> - <pointer>). We have to treat it here because
+  // there is no valid semantics for the (-<pointer>) expression, hence in
+  // createOpUnary such an expression will trigger a crash.
+  // FIXME: The same problem can now be triggered by a subexpression of the LHS,
+  //        however it is much less likely.
+  if (OpType == isl_ast_op_add &&
+      isl_ast_expr_get_type(LOp) == isl_ast_expr_op &&
+      isl_ast_expr_get_op_type(LOp) == isl_ast_op_minus) {
+    // Change the binary addition to a substraction.
+    OpType = isl_ast_op_sub;
+
+    // Extract the unary operand of the LHS.
+    auto *LOpOp = isl_ast_expr_get_op_arg(LOp, 0);
+    isl_ast_expr_free(LOp);
+
+    // Swap the unary operand of the LHS and the RHS.
+    LOp = ROp;
+    ROp = LOpOp;
+  }
+
+  LHS = create(LOp);
+  RHS = create(ROp);
+
+  Type *LHSType = LHS->getType();
+  Type *RHSType = RHS->getType();
+
+  // Handle <pointer> - <pointer>
+  if (LHSType->isPointerTy() && RHSType->isPointerTy()) {
+    isl_ast_expr_free(Expr);
+    assert(OpType == isl_ast_op_sub && "Substraction is the only valid binary "
+                                       "pointer <-> pointer operation.");
+
+    return Builder.CreatePtrDiff(LHS, RHS);
+  }
+
+  // Handle <pointer> +/- <integer> and <integer> +/- <pointer>
+  if (LHSType->isPointerTy() || RHSType->isPointerTy()) {
+    isl_ast_expr_free(Expr);
+
+    assert((LHSType->isIntegerTy() || RHSType->isIntegerTy()) &&
+           "Arithmetic operations might only performed on one but not two "
+           "pointer types.");
+
+    if (LHSType->isIntegerTy())
+      std::swap(LHS, RHS);
+
+    switch (OpType) {
+    default:
+      llvm_unreachable(
+          "Only additive binary operations are allowed on pointer types.");
+    case isl_ast_op_sub:
+      RHS = Builder.CreateNeg(RHS);
+    // Fall through
+    case isl_ast_op_add:
+      return Builder.CreateGEP(LHS, RHS);
+    }
+  }
+
+  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 = Builder.CreateNSWAdd(LHS, RHS);
+    break;
+  case isl_ast_op_sub:
+    Res = Builder.CreateNSWSub(LHS, RHS);
+    break;
+  case isl_ast_op_mul:
+    Res = Builder.CreateNSWMul(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 bordercases.
+    //
+    // floord(n,d) ((n < 0) ? (n - d + 1) : n) / d
+    Value *One = ConstantInt::get(MaxType, 1);
+    Value *Zero = ConstantInt::get(MaxType, 0);
+    Value *Sum1 = Builder.CreateSub(LHS, RHS, "pexp.fdiv_q.0");
+    Value *Sum2 = Builder.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.CreateURem(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;
+
+  LHS = create(isl_ast_expr_get_op_arg(Expr, 0));
+  RHS = create(isl_ast_expr_get_op_arg(Expr, 1));
+
+  bool IsPtrType =
+      LHS->getType()->isPointerTy() || RHS->getType()->isPointerTy();
+
+  if (LHS->getType() != RHS->getType()) {
+    if (IsPtrType) {
+      Type *I8PtrTy = Builder.getInt8PtrTy();
+      if (!LHS->getType()->isPointerTy())
+        LHS = Builder.CreateIntToPtr(LHS, I8PtrTy);
+      if (!RHS->getType()->isPointerTy())
+        RHS = Builder.CreateIntToPtr(RHS, I8PtrTy);
+      if (LHS->getType() != I8PtrTy)
+        LHS = Builder.CreateBitCast(LHS, I8PtrTy);
+      if (RHS->getType() != I8PtrTy)
+        RHS = Builder.CreateBitCast(RHS, I8PtrTy);
+    } else {
+      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][IsPtrType], 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 outweight 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];
+
+  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);
+  T = getType(Expr);
+  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..240a7ae
--- /dev/null
+++ b/final/lib/CodeGen/IslNodeBuilder.cpp
@@ -0,0 +1,746 @@
+//===------ 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/Utils.h"
+#include "polly/Config/config.h"
+#include "polly/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/SCEVValidator.h"
+#include "polly/Support/ScopHelper.h"
+#include "polly/TempScopInfo.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/ScalarEvolutionExpander.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "isl/aff.h"
+#include "isl/ast.h"
+#include "isl/ast_build.h"
+#include "isl/list.h"
+#include "isl/map.h"
+#include "isl/set.h"
+#include "isl/union_map.h"
+#include "isl/union_set.h"
+
+using namespace polly;
+using namespace llvm;
+
+__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);
+  isl_ast_expr_get_type(Cond);
+  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 comparision type in loop conditon");
+  }
+
+  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;
+}
+
+unsigned IslNodeBuilder::getNumberOfIterations(__isl_keep isl_ast_node *For) {
+  isl_union_map *Schedule = IslAstInfo::getSchedule(For);
+  isl_set *LoopDomain = isl_set_from_union_set(isl_union_map_range(Schedule));
+  if (isl_set_is_wrapping(LoopDomain))
+    LoopDomain = isl_map_range(isl_set_unwrap(LoopDomain));
+  int Dim = isl_set_dim(LoopDomain, isl_dim_set);
+
+  // Calculate a map similar to the identity map, but with the last input
+  // and output dimension not related.
+  //  [i0, i1, i2, i3] -> [i0, i1, i2, o0]
+  isl_space *Space = isl_set_get_space(LoopDomain);
+  Space = isl_space_drop_dims(Space, isl_dim_out, Dim - 1, 1);
+  Space = isl_space_map_from_set(Space);
+  isl_map *Identity = isl_map_identity(Space);
+  Identity = isl_map_add_dims(Identity, isl_dim_in, 1);
+  Identity = isl_map_add_dims(Identity, isl_dim_out, 1);
+
+  LoopDomain = isl_set_reset_tuple_id(LoopDomain);
+
+  isl_map *Map = isl_map_from_domain_and_range(isl_set_copy(LoopDomain),
+                                               isl_set_copy(LoopDomain));
+  isl_set_free(LoopDomain);
+  Map = isl_map_intersect(Map, Identity);
+
+  isl_map *LexMax = isl_map_lexmax(isl_map_copy(Map));
+  isl_map *LexMin = isl_map_lexmin(Map);
+  isl_map *Sub = isl_map_sum(LexMax, isl_map_neg(LexMin));
+
+  isl_set *Elements = isl_map_range(Sub);
+
+  if (!isl_set_is_singleton(Elements)) {
+    isl_set_free(Elements);
+    return -1;
+  }
+
+  isl_point *P = isl_set_sample_point(Elements);
+
+  isl_val *V;
+  V = isl_point_get_coordinate_val(P, isl_dim_set, Dim - 1);
+  int NumberIterations = isl_val_get_num_si(V);
+  isl_val_free(V);
+  isl_point_free(P);
+  if (NumberIterations == -1)
+    return -1;
+  return NumberIterations + 1;
+}
+
+struct FindValuesUser {
+  LoopInfo &LI;
+  ScalarEvolution &SE;
+  Region &R;
+  SetVector<Value *> &Values;
+  SetVector<const SCEV *> &SCEVs;
+};
+
+/// @brief Extract the values and SCEVs needed to generate code for a block.
+static int findValuesInBlock(struct FindValuesUser &User, const ScopStmt *Stmt,
+                             const BasicBlock *BB) {
+  // Check all the operands of instructions in the basic block.
+  for (const Instruction &Inst : *BB) {
+    for (Value *SrcVal : Inst.operands()) {
+      if (Instruction *OpInst = dyn_cast<Instruction>(SrcVal))
+        if (canSynthesize(OpInst, &User.LI, &User.SE, &User.R)) {
+          User.SCEVs.insert(
+              User.SE.getSCEVAtScope(OpInst, User.LI.getLoopFor(BB)));
+          continue;
+        }
+      if (Instruction *OpInst = dyn_cast<Instruction>(SrcVal))
+        if (Stmt->getParent()->getRegion().contains(OpInst))
+          continue;
+
+      if (isa<Instruction>(SrcVal) || isa<Argument>(SrcVal))
+        User.Values.insert(SrcVal);
+    }
+  }
+  return 0;
+}
+
+/// Extract the values and SCEVs needed to generate code for a ScopStmt.
+///
+/// This function extracts a ScopStmt from a given isl_set and computes the
+/// Values this statement depends on as well as a set of SCEV expressions that
+/// need to be synthesized when generating code for this statment.
+static isl_stat findValuesInStmt(isl_set *Set, void *UserPtr) {
+  isl_id *Id = isl_set_get_tuple_id(Set);
+  struct FindValuesUser &User = *static_cast<struct FindValuesUser *>(UserPtr);
+  const ScopStmt *Stmt = static_cast<const ScopStmt *>(isl_id_get_user(Id));
+
+  if (Stmt->isBlockStmt())
+    findValuesInBlock(User, Stmt, Stmt->getBasicBlock());
+  else {
+    assert(Stmt->isRegionStmt() &&
+           "Stmt was neither block nor region statement");
+    for (const BasicBlock *BB : Stmt->getRegion()->blocks())
+      findValuesInBlock(User, Stmt, BB);
+  }
+
+  isl_id_free(Id);
+  isl_set_free(Set);
+  return isl_stat_ok;
+}
+
+void IslNodeBuilder::getReferencesInSubtree(__isl_keep isl_ast_node *For,
+                                            SetVector<Value *> &Values,
+                                            SetVector<const Loop *> &Loops) {
+
+  SetVector<const SCEV *> SCEVs;
+  struct FindValuesUser FindValues = {LI, SE, S.getRegion(), Values, SCEVs};
+
+  for (const auto &I : IDToValue)
+    Values.insert(I.second);
+
+  for (const auto &I : OutsideLoopIterations)
+    Values.insert(cast<SCEVUnknown>(I.second)->getValue());
+
+  isl_union_set *Schedule = isl_union_map_domain(IslAstInfo::getSchedule(For));
+
+  isl_union_set_foreach_set(Schedule, findValuesInStmt, &FindValues);
+  isl_union_set_free(Schedule);
+
+  for (const SCEV *Expr : SCEVs) {
+    findValues(Expr, Values);
+    findLoops(Expr, Loops);
+  }
+
+  Values.remove_if([](const Value *V) { return isa<GlobalValue>(V); });
+
+  /// 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.
+  Loops.remove_if([this](const Loop *L) {
+    return S.getRegion().contains(L) || L->contains(S.getRegion().getEntry());
+  });
+}
+
+void IslNodeBuilder::updateValues(
+    ParallelLoopGenerator::ValueToValueMapTy &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;
+  }
+}
+
+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);
+  Stmt->setAstBuild(IslAstInfo::getBuild(User));
+  VectorValueMapT VectorMap(IVS.size());
+  std::vector<LoopToScevMapT> VLTS(IVS.size());
+
+  isl_union_set *Domain = isl_union_set_from_set(Stmt->getDomain());
+  Schedule = isl_union_map_intersect_domain(Schedule, Domain);
+  isl_map *S = isl_map_from_union_map(Schedule);
+
+  createSubstitutionsVector(Expr, Stmt, VectorMap, VLTS, IVS, IteratorID);
+  VectorBlockGenerator::generate(BlockGen, *Stmt, VectorMap, VLTS, S);
+
+  isl_map_free(S);
+  isl_id_free(Id);
+  isl_ast_node_free(User);
+}
+
+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 = IslAstInfo::getSchedule(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);
+}
+
+void IslNodeBuilder::createForSequential(__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;
+  BasicBlock *ExitBlock;
+  Value *IV;
+  CmpInst::Predicate Predicate;
+  bool Parallel;
+
+  Parallel =
+      IslAstInfo::isParallel(For) && !IslAstInfo::isReductionParallel(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, P, LI, DT, ExitBlock,
+                  Predicate, &Annotator, Parallel, UseGuardBB);
+  IDToValue[IteratorID] = IV;
+
+  create(Body);
+
+  Annotator.popLoop(Parallel);
+
+  IDToValue.erase(IDToValue.find(IteratorID));
+
+  Builder.SetInsertPoint(ExitBlock->begin());
+
+  isl_ast_node_free(For);
+  isl_ast_expr_free(Iterator);
+  isl_id_free(IteratorID);
+}
+
+/// @brief 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;
+
+  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 blound 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.
+  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);
+  }
+
+  ParallelLoopGenerator::ValueToValueMapTy NewValues;
+  ParallelLoopGenerator ParallelLoopGen(Builder, P, LI, DT, DL);
+
+  IV = ParallelLoopGen.createParallelLoop(ValueLB, ValueUB, ValueInc,
+                                          SubtreeValues, NewValues, &LoopBody);
+  BasicBlock::iterator AfterLoop = Builder.GetInsertPoint();
+  Builder.SetInsertPoint(LoopBody);
+
+  // Save the current values.
+  ValueMapT ValueMapCopy = ValueMap;
+  IslExprBuilder::IDToValueTy IDToValueCopy = IDToValue;
+
+  updateValues(NewValues);
+  IDToValue[IteratorID] = IV;
+
+  create(Body);
+
+  // 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);
+}
+
+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) {
+      createForVector(For, VectorWidth);
+      return;
+    }
+  }
+
+  if (IslAstInfo::isExecutedInParallel(For)) {
+    createForParallel(For);
+    return;
+  }
+  createForSequential(For);
+}
+
+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->begin(), &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->begin());
+
+  create(isl_ast_node_if_get_then(If));
+
+  Builder.SetInsertPoint(ElseBB->begin());
+
+  if (isl_ast_node_if_has_else(If))
+    create(isl_ast_node_if_get_else(If));
+
+  Builder.SetInsertPoint(MergeBB->begin());
+
+  isl_ast_node_free(If);
+}
+
+void IslNodeBuilder::createSubstitutions(isl_ast_expr *Expr, ScopStmt *Stmt,
+                                         ValueMapT &VMap, 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 &&
+         "Opertation 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);
+  }
+
+  // Add the current ValueMap to our per-statement value map.
+  //
+  // This is needed e.g. to rewrite array base addresses when moving code
+  // into a parallely executed subfunction.
+  VMap.insert(ValueMap.begin(), ValueMap.end());
+
+  isl_ast_expr_free(Expr);
+}
+
+void IslNodeBuilder::createSubstitutionsVector(
+    __isl_take isl_ast_expr *Expr, ScopStmt *Stmt, VectorValueMapT &VMap,
+    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, VMap[i], VLTS[i]);
+    i++;
+  }
+
+  IDToValue[IteratorID] = OldValue;
+  isl_id_free(IteratorID);
+  isl_ast_expr_free(Expr);
+}
+
+void IslNodeBuilder::createUser(__isl_take isl_ast_node *User) {
+  ValueMapT VMap;
+  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);
+  Stmt->setAstBuild(IslAstInfo::getBuild(User));
+
+  createSubstitutions(Expr, Stmt, VMap, LTS);
+  if (Stmt->isBlockStmt())
+    BlockGen.copyStmt(*Stmt, VMap, LTS);
+  else
+    RegionGen.copyStmt(*Stmt, VMap, LTS);
+
+  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:
+    llvm_unreachable("Mark node unexpected");
+  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");
+}
+
+void IslNodeBuilder::addParameters(__isl_take isl_set *Context) {
+
+  for (unsigned i = 0; i < isl_set_dim(Context, isl_dim_param); ++i) {
+    isl_id *Id;
+
+    Id = isl_set_get_dim_id(Context, isl_dim_param, i);
+    IDToValue[Id] = generateSCEV((const SCEV *)isl_id_get_user(Id));
+
+    isl_id_free(Id);
+  }
+
+  // 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.
+  Region &R = S.getRegion();
+  Loop *L = LI.getLoopFor(R.getEntry());
+
+  while (L != nullptr && R.contains(L))
+    L = L->getParentLoop();
+
+  while (L != nullptr) {
+    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);
+    L = L->getParentLoop();
+  }
+
+  isl_set_free(Context);
+}
+
+Value *IslNodeBuilder::generateSCEV(const SCEV *Expr) {
+  Instruction *InsertLocation = --(Builder.GetInsertBlock()->end());
+  return Rewriter.expandCodeFor(Expr, Expr->getType(), InsertLocation);
+}
diff --git a/final/lib/CodeGen/LoopGenerators.cpp b/final/lib/CodeGen/LoopGenerators.cpp
new file mode 100644
index 0000000..3bb61fa
--- /dev/null
+++ b/final/lib/CodeGen/LoopGenerators.cpp
@@ -0,0 +1,377 @@
+//===------ 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/ScopDetection.h"
+#include "polly/CodeGen/LoopGenerators.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.
+Value *polly::createLoop(Value *LB, Value *UB, Value *Stride,
+                         PollyIRBuilder &Builder, Pass *P, LoopInfo &LI,
+                         DominatorTree &DT, BasicBlock *&ExitBB,
+                         ICmpInst::Predicate Predicate,
+                         ScopAnnotator *Annotator, bool Parallel,
+                         bool UseGuard) {
+  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 = new Loop();
+
+  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;
+  UB = Builder.CreateSub(UB, Stride, "polly.adjust_ub");
+  LoopCondition = Builder.CreateICmp(Predicate, IV, UB);
+  LoopCondition->setName("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);
+
+  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,
+    ValueToValueMapTy &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();
+
+  // Mark the end of the lifetime for the parameter struct.
+  Type *Ty = Struct->getType();
+  ConstantInt *SizeOf = Builder.getInt64(DL.getTypeAllocSize(Ty));
+  Builder.CreateLifetimeEnd(Struct, SizeOf);
+
+  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);
+
+  // 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());
+
+  // 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, 0, "polly.par.userContext", IP);
+
+  // Mark the start of the lifetime for the parameter struct.
+  ConstantInt *SizeOf = Builder.getInt64(DL.getTypeAllocSize(Ty));
+  Builder.CreateLifetimeStart(Struct, SizeOf);
+
+  for (unsigned i = 0; i < Values.size(); i++) {
+    Value *Address = Builder.CreateStructGEP(Ty, Struct, i);
+    Builder.CreateStore(Values[i], Address);
+  }
+
+  return Struct;
+}
+
+void ParallelLoopGenerator::extractValuesFromStruct(
+    SetVector<Value *> OldValues, Type *Ty, Value *Struct,
+    ValueToValueMapTy &Map) {
+  for (unsigned i = 0; i < OldValues.size(); i++) {
+    Value *Address = Builder.CreateStructGEP(Ty, Struct, i);
+    Value *NewValue = Builder.CreateLoad(Address);
+    Map[OldValues[i]] = NewValue;
+  }
+}
+
+Value *ParallelLoopGenerator::createSubFn(Value *Stride, AllocaInst *StructData,
+                                          SetVector<Value *> Data,
+                                          ValueToValueMapTy &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, 0, "polly.par.LBPtr");
+  UBPtr = Builder.CreateAlloca(LongType, 0, "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 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, P, 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/RuntimeDebugBuilder.cpp b/final/lib/CodeGen/RuntimeDebugBuilder.cpp
new file mode 100644
index 0000000..f8503d4
--- /dev/null
+++ b/final/lib/CodeGen/RuntimeDebugBuilder.cpp
@@ -0,0 +1,225 @@
+//===--- 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::ptx_read_ctaid_x),
+      Intrinsic::getDeclaration(M, Intrinsic::ptx_read_ctaid_y),
+      Intrinsic::getDeclaration(M, Intrinsic::ptx_read_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::ptx_read_tid_x),
+      Intrinsic::getDeclaration(M, Intrinsic::ptx_read_tid_y),
+      Intrinsic::getDeclaration(M, Intrinsic::ptx_read_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::createGPUVAPrinter(PollyIRBuilder &Builder,
+                                             ArrayRef<Value *> Values) {
+  std::string str;
+
+  // Allocate print buffer (assuming 2*32 bit per element)
+  auto T = ArrayType::get(Builder.getInt32Ty(), Values.size() * 2);
+  Value *Data = new AllocaInst(
+      T, "polly.vprint.buffer",
+      Builder.GetInsertBlock()->getParent()->getEntryBlock().begin());
+
+  auto *Zero = Builder.getInt64(0);
+  auto *DataPtr = Builder.CreateGEP(Data, {Zero, Zero});
+
+  auto ToPrint = getGPUThreadIdentifiers(Builder);
+
+  ToPrint.push_back(Builder.CreateGlobalStringPtr("\n  ", "", 4));
+  ToPrint.insert(ToPrint.end(), Values.begin(), Values.end());
+
+  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()) {
+        Ty = Builder.getDoubleTy();
+        Val = Builder.CreateFPExt(Val, Ty);
+      }
+    } else if (Ty->isIntegerTy()) {
+      auto Int64Bitwidth = Builder.getInt64Ty()->getIntegerBitWidth();
+      assert(Ty->getIntegerBitWidth() <= Int64Bitwidth);
+      if (Ty->getIntegerBitWidth() < Int64Bitwidth) {
+        Ty = Builder.getInt64Ty();
+        Val = Builder.CreateSExt(Val, Ty);
+      }
+    } else {
+      // If it is not a number, it must be a string type.
+      Val = Builder.CreateGEP(Val, Builder.getInt64(0));
+      assert((Val->getType() == Builder.getInt8PtrTy(4)) &&
+             "Expected i8 ptr placed in constant address space");
+      auto F = RuntimeDebugBuilder::getAddressSpaceCast(Builder, 4, 0);
+      Val = Builder.CreateCall(F, Val);
+      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(), Builder.getInt8PtrTy(), true);
+    F = Function::Create(Ty, Linkage, Name, M);
+  }
+
+  return F;
+}
+
+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()));
+}
+
+void RuntimeDebugBuilder::createStrPrinter(PollyIRBuilder &Builder,
+                                           const std::string &String) {
+  Value *StringValue = Builder.CreateGlobalStringPtr(String);
+  Builder.CreateCall(getPrintF(Builder), StringValue);
+
+  createFlush(Builder);
+}
+
+void RuntimeDebugBuilder::createValuePrinter(PollyIRBuilder &Builder,
+                                             Value *V) {
+  const char *Format = nullptr;
+
+  Type *Ty = V->getType();
+  if (Ty->isIntegerTy())
+    Format = "%ld";
+  else if (Ty->isFloatingPointTy())
+    Format = "%lf";
+  else if (Ty->isPointerTy())
+    Format = "%p";
+
+  assert(Format && Ty->getPrimitiveSizeInBits() <= 64 && "Bad type to print.");
+
+  Value *FormatString = Builder.CreateGlobalStringPtr(Format);
+  Builder.CreateCall(getPrintF(Builder), {FormatString, V});
+  createFlush(Builder);
+}
diff --git a/final/lib/CodeGen/Utils.cpp b/final/lib/CodeGen/Utils.cpp
new file mode 100644
index 0000000..4fccbc3
--- /dev/null
+++ b/final/lib/CodeGen/Utils.cpp
@@ -0,0 +1,88 @@
+//===--- 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;
+
+BasicBlock *polly::executeScopConditionally(Scop &S, Pass *P, Value *RTC) {
+  BasicBlock *StartBlock, *SplitBlock, *NewBlock;
+  Region &R = S.getRegion();
+  PollyIRBuilder Builder(R.getEntry());
+  DominatorTree &DT = P->getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+  RegionInfo &RI = P->getAnalysis<RegionInfoPass>().getRegionInfo();
+  LoopInfo &LI = P->getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+
+  // Split the entry edge of the region and generate a new basic block on this
+  // edge. This function also updates ScopInfo and RegionInfo.
+  NewBlock = SplitEdge(R.getEnteringBlock(), R.getEntry(), &DT, &LI);
+  if (DT.dominates(R.getEntry(), NewBlock)) {
+    BasicBlock *OldBlock = R.getEntry();
+    std::string OldName = OldBlock->getName();
+
+    // Update ScopInfo.
+    for (ScopStmt &Stmt : S)
+      if (Stmt.getBasicBlock() == OldBlock) {
+        Stmt.setBasicBlock(NewBlock);
+        break;
+      }
+
+    // Update RegionInfo.
+    SplitBlock = OldBlock;
+    OldBlock->setName("polly.split");
+    NewBlock->setName(OldName);
+    R.replaceEntryRecursive(NewBlock);
+    RI.setRegionFor(NewBlock, &R);
+  } else {
+    RI.setRegionFor(NewBlock, R.getParent());
+    SplitBlock = NewBlock;
+  }
+
+  SplitBlock->setName("polly.split_new_and_old");
+  Function *F = SplitBlock->getParent();
+  StartBlock = BasicBlock::Create(F->getContext(), "polly.start", F);
+  SplitBlock->getTerminator()->eraseFromParent();
+  Builder.SetInsertPoint(SplitBlock);
+  Builder.CreateCondBr(RTC, StartBlock, R.getEntry());
+  if (Loop *L = LI.getLoopFor(SplitBlock))
+    L->addBasicBlockToLoop(StartBlock, LI);
+  DT.addNewBlock(StartBlock, SplitBlock);
+  Builder.SetInsertPoint(StartBlock);
+
+  BasicBlock *MergeBlock;
+
+  if (R.getExit()->getSinglePredecessor())
+    // No splitEdge required.  A block with a single predecessor cannot have
+    // PHI nodes that would complicate life.
+    MergeBlock = R.getExit();
+  else {
+    MergeBlock = SplitEdge(R.getExitingBlock(), R.getExit(), &DT, &LI);
+    // SplitEdge will never split R.getExit(), as R.getExit() has more than
+    // one predecessor. Hence, mergeBlock is always a newly generated block.
+    R.replaceExitRecursive(MergeBlock);
+    RI.setRegionFor(MergeBlock, &R);
+  }
+
+  Builder.CreateBr(MergeBlock);
+  MergeBlock->setName("polly.merge_new_and_old");
+
+  if (DT.dominates(SplitBlock, MergeBlock))
+    DT.changeImmediateDominator(MergeBlock, SplitBlock);
+  return StartBlock;
+}
diff --git a/final/lib/Exchange/JSONExporter.cpp b/final/lib/Exchange/JSONExporter.cpp
new file mode 100644
index 0000000..de9a4f3
--- /dev/null
+++ b/final/lib/Exchange/JSONExporter.cpp
@@ -0,0 +1,415 @@
+//===-- 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/LinkAllPasses.h"
+#include "polly/DependenceInfo.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 "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) {}
+
+  std::string getFileName(Scop &S) const;
+  Json::Value getJSON(Scop &S) const;
+  virtual bool runOnScop(Scop &S);
+  void printScop(raw_ostream &OS, Scop &S) const;
+  void getAnalysisUsage(AnalysisUsage &AU) const;
+};
+
+struct JSONImporter : public ScopPass {
+  static char ID;
+  std::vector<std::string> newAccessStrings;
+  explicit JSONImporter() : ScopPass(ID) {}
+
+  std::string getFileName(Scop &S) const;
+  virtual bool runOnScop(Scop &S);
+  void printScop(raw_ostream &OS, Scop &S) const;
+  void getAnalysisUsage(AnalysisUsage &AU) const;
+};
+}
+
+char JSONExporter::ID = 0;
+std::string JSONExporter::getFileName(Scop &S) const {
+  std::string FunctionName = S.getRegion().getEntry()->getParent()->getName();
+  std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop";
+  return FileName;
+}
+
+void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { S.print(OS); }
+
+Json::Value JSONExporter::getJSON(Scop &S) const {
+  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.getRegion().getNameStr();
+  root["context"] = S.getContextStr();
+  if (LineBegin != (unsigned)-1)
+    root["location"] = Location;
+  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->getOriginalAccessRelationStr();
+
+      statement["accesses"].append(access);
+    }
+
+    root["statements"].append(statement);
+  }
+
+  return root;
+}
+
+bool JSONExporter::runOnScop(Scop &S) {
+  Region &R = S.getRegion();
+
+  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;
+  tool_output_file F(FileName, EC, llvm::sys::fs::F_Text);
+
+  std::string FunctionName = R.getEntry()->getParent()->getName();
+  errs() << "Writing JScop '" << R.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 false;
+    }
+  }
+
+  errs() << "  error opening file for writing!\n";
+  F.os().clear_error();
+
+  return false;
+}
+
+void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.setPreservesAll();
+  AU.addRequired<ScopInfo>();
+}
+
+Pass *polly::createJSONExporterPass() { return new JSONExporter(); }
+
+char JSONImporter::ID = 0;
+std::string JSONImporter::getFileName(Scop &S) const {
+  std::string FunctionName = S.getRegion().getEntry()->getParent()->getName();
+  std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop";
+
+  if (ImportPostfix != "")
+    FileName += "." + ImportPostfix;
+
+  return FileName;
+}
+
+void JSONImporter::printScop(raw_ostream &OS, Scop &S) const {
+  S.print(OS);
+  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";
+}
+
+typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
+
+bool JSONImporter::runOnScop(Scop &S) {
+  Region &R = S.getRegion();
+  const Dependences &D = getAnalysis<DependenceInfo>().getDependences();
+  const DataLayout &DL =
+      S.getRegion().getEntry()->getParent()->getParent()->getDataLayout();
+
+  std::string FileName = ImportDir + "/" + getFileName(S);
+
+  std::string FunctionName = R.getEntry()->getParent()->getName();
+  errs() << "Reading JScop '" << R.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;
+  }
+
+  isl_set *OldContext = S.getContext();
+  isl_set *NewContext =
+      isl_set_read_from_str(S.getIslCtx(), jscop["context"].asCString());
+
+  for (unsigned i = 0; i < isl_set_dim(OldContext, isl_dim_param); i++) {
+    isl_id *id = isl_set_get_dim_id(OldContext, isl_dim_param, i);
+    NewContext = isl_set_set_dim_id(NewContext, isl_dim_param, i, id);
+  }
+
+  isl_set_free(OldContext);
+  S.setContext(NewContext);
+
+  StatementToIslMapTy NewSchedule;
+
+  int index = 0;
+
+  for (ScopStmt &Stmt : S) {
+    Json::Value schedule = jscop["statements"][index]["schedule"];
+    isl_map *m = isl_map_read_from_str(S.getIslCtx(), schedule.asCString());
+    isl_space *Space = Stmt.getDomainSpace();
+
+    // Copy the old tuple id. This is necessary to retain the user pointer,
+    // that stores the reference to the ScopStmt this schedule belongs to.
+    m = isl_map_set_tuple_id(m, 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);
+      m = isl_map_set_dim_id(m, isl_dim_param, i, id);
+    }
+    isl_space_free(Space);
+    NewSchedule[&Stmt] = m;
+    index++;
+  }
+
+  if (!D.isValidSchedule(S, &NewSchedule)) {
+    errs() << "JScop file contains a schedule that changes the "
+           << "dependences. Use -disable-polly-legality to continue anyways\n";
+    for (StatementToIslMapTy::iterator SI = NewSchedule.begin(),
+                                       SE = NewSchedule.end();
+         SI != SE; ++SI)
+      isl_map_free(SI->second);
+    return false;
+  }
+
+  auto ScheduleMap = isl_union_map_empty(S.getParamSpace());
+  for (ScopStmt &Stmt : S) {
+    if (NewSchedule.find(&Stmt) != NewSchedule.end())
+      ScheduleMap = isl_union_map_add_map(ScheduleMap, NewSchedule[&Stmt]);
+    else
+      ScheduleMap = isl_union_map_add_map(ScheduleMap, Stmt.getSchedule());
+  }
+
+  S.setSchedule(ScheduleMap);
+
+  int statementIdx = 0;
+  for (ScopStmt &Stmt : S) {
+    int memoryAccessIdx = 0;
+    for (MemoryAccess *MA : Stmt) {
+      Json::Value accesses = jscop["statements"][statementIdx]["accesses"]
+                                  [memoryAccessIdx]["relation"];
+      isl_map *newAccessMap =
+          isl_map_read_from_str(S.getIslCtx(), accesses.asCString());
+      isl_map *currentAccessMap = MA->getAccessRelation();
+
+      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 *OutId = isl_map_get_tuple_id(currentAccessMap, isl_dim_out);
+      newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_out, OutId);
+
+      // 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 =
+            DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment();
+      } else if (StoreInst *StoreI =
+                     dyn_cast<StoreInst>(MA->getAccessInstruction())) {
+        SpecialAlignment =
+            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);
+
+        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);
+
+      if (!isl_map_has_equal_space(currentAccessMap, newAccessMap)) {
+        errs() << "JScop file contains access function with incompatible "
+               << "dimensions\n";
+        isl_map_free(currentAccessMap);
+        isl_map_free(newAccessMap);
+        return false;
+      }
+      if (isl_map_dim(newAccessMap, isl_dim_out) != 1) {
+        errs() << "New access map in JScop file should be single dimensional\n";
+        isl_map_free(currentAccessMap);
+        isl_map_free(newAccessMap);
+        return false;
+      }
+
+      auto NewAccessDomain = isl_map_domain(isl_map_copy(newAccessMap));
+      auto CurrentAccessDomain = isl_map_domain(isl_map_copy(currentAccessMap));
+
+      NewAccessDomain =
+          isl_set_intersect_params(NewAccessDomain, S.getContext());
+      CurrentAccessDomain =
+          isl_set_intersect_params(CurrentAccessDomain, S.getContext());
+
+      if (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;
+        newAccessStrings.push_back(accesses.asCString());
+        MA->setNewAccessRelation(newAccessMap);
+      } else {
+        isl_map_free(newAccessMap);
+      }
+      isl_map_free(currentAccessMap);
+      memoryAccessIdx++;
+    }
+    statementIdx++;
+  }
+
+  return false;
+}
+
+void JSONImporter::getAnalysisUsage(AnalysisUsage &AU) const {
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequired<DependenceInfo>();
+}
+Pass *polly::createJSONImporterPass() { return new JSONImporter(); }
+
+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/README.txt b/final/lib/External/README.txt
new file mode 100644
index 0000000..806e8bb
--- /dev/null
+++ b/final/lib/External/README.txt
@@ -0,0 +1,17 @@
+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.
diff --git a/final/lib/External/gitversion.h.cmake b/final/lib/External/gitversion.h.cmake
new file mode 100644
index 0000000..8a6f36e
--- /dev/null
+++ b/final/lib/External/gitversion.h.cmake
@@ -0,0 +1 @@
+#define GIT_HEAD_ID "@GIT_HEAD_ID@"
diff --git a/final/lib/External/isl/AUTHORS b/final/lib/External/isl/AUTHORS
new file mode 100644
index 0000000..a6afd5a
--- /dev/null
+++ b/final/lib/External/isl/AUTHORS
@@ -0,0 +1,44 @@
+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	    INRIA Rocquencourt
+	    Domaine de Voluceau - Rocquencourt, B.P. 105
+	    78153 Le Chesnay
+	    France
+
+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
+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..828bbe3
--- /dev/null
+++ b/final/lib/External/isl/ChangeLog
@@ -0,0 +1,152 @@
+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..218fde0
--- /dev/null
+++ b/final/lib/External/isl/GIT_HEAD_ID
@@ -0,0 +1 @@
+isl-0.15-35-ga1e44f0
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..7c66052
--- /dev/null
+++ b/final/lib/External/isl/Makefile.am
@@ -0,0 +1,365 @@
+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_codegen isl_test_int
+TESTS = isl_test codegen_test.sh pip_test.sh bound_test.sh isl_test_int
+
+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_id_to_ast_expr.c \
+	isl_id_to_pw_aff.c \
+	isl_ilp.c \
+	isl_ilp_private.h \
+	isl_input.c \
+	isl_int.h \
+	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_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_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_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_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_pw_aff.h \
+	include/isl/ilp.h \
+	include/isl/hash.h \
+	include/isl/hmap.h \
+	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/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/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
+
+EXTRA_DIST = \
+	LICENSE \
+	isl_config_post.h \
+	basis_reduction_templ.c \
+	isl_hmap_templ.c \
+	isl_list_templ.c \
+	isl_list_templ.h \
+	isl_map_lexopt_templ.c \
+	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_floor.c \
+	isl_multi_gist.c \
+	isl_multi_intersect.c \
+	print_templ.c \
+	isl_power_templ.c \
+	isl_pw_templ.c \
+	isl_union_templ.c \
+	isl.py \
+	doc/CodingStyle \
+	doc/SubmittingPatches \
+	doc/chicago.bst \
+	doc/chicago.sty \
+	doc/implementation.tex \
+	doc/isl.bib \
+	doc/mypod2latex \
+	doc/manual.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.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
diff --git a/final/lib/External/isl/Makefile.in b/final/lib/External/isl/Makefile.in
new file mode 100644
index 0000000..3c86994
--- /dev/null
+++ b/final/lib/External/isl/Makefile.in
@@ -0,0 +1,2144 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 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 = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+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_codegen$(EXEEXT) \
+	isl_test_int$(EXEEXT) $(am__EXEEXT_1)
+TESTS = isl_test$(EXEEXT) codegen_test.sh pip_test.sh bound_test.sh \
+	isl_test_int$(EXEEXT) $(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 = .
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/configure $(am__configure_deps) \
+	$(srcdir)/isl_config.h.in $(srcdir)/bound_test.sh.in \
+	$(srcdir)/codegen_test.sh.in $(srcdir)/pip_test.sh.in depcomp \
+	$(deprecated_HEADERS) $(am__pkginclude_HEADERS_DIST) \
+	test-driver AUTHORS ChangeLog README compile config.guess \
+	config.sub install-sh missing ltmain.sh
+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_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)
+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 = bound_test.sh codegen_test.sh pip_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_id_to_ast_expr.c \
+	isl_id_to_pw_aff.c isl_ilp.c isl_ilp_private.h isl_input.c \
+	isl_int.h 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_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_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_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_pw_aff.lo isl_ilp.lo \
+	isl_input.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_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_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
+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_pip_SOURCES) $(isl_polyhedron_detect_equalities_SOURCES) \
+	$(isl_polyhedron_minimize_SOURCES) \
+	$(isl_polyhedron_sample_SOURCES) $(isl_polytope_scan_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_pip_SOURCES) \
+	$(isl_polyhedron_detect_equalities_SOURCES) \
+	$(isl_polyhedron_minimize_SOURCES) \
+	$(isl_polyhedron_sample_SOURCES) $(isl_polytope_scan_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_pw_aff.h \
+	include/isl/ilp.h include/isl/hash.h include/isl/hmap.h \
+	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/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/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)
+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@
+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@
+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@
+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@
+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_id_to_ast_expr.c \
+	isl_id_to_pw_aff.c \
+	isl_ilp.c \
+	isl_ilp_private.h \
+	isl_input.c \
+	isl_int.h \
+	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_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_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_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_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_pw_aff.h \
+	include/isl/ilp.h \
+	include/isl/hash.h \
+	include/isl/hmap.h \
+	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/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/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
+
+EXTRA_DIST = \
+	LICENSE \
+	isl_config_post.h \
+	basis_reduction_templ.c \
+	isl_hmap_templ.c \
+	isl_list_templ.c \
+	isl_list_templ.h \
+	isl_map_lexopt_templ.c \
+	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_floor.c \
+	isl_multi_gist.c \
+	isl_multi_intersect.c \
+	print_templ.c \
+	isl_power_templ.c \
+	isl_pw_templ.c \
+	isl_union_templ.c \
+	isl.py \
+	doc/CodingStyle \
+	doc/SubmittingPatches \
+	doc/chicago.bst \
+	doc/chicago.sty \
+	doc/implementation.tex \
+	doc/isl.bib \
+	doc/mypod2latex \
+	doc/manual.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.py.top \
+	test_inputs
+
+pkgconfigdir = $(pkgconfig_libdir)
+pkgconfig_DATA = $(pkgconfig_libfile)
+all: 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
+.PRECIOUS: 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
+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 $@
+
+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_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_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)/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_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_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_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@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; \
+	else \
+	  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)
+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 shar distribution archives 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 distribution archives compressed with" \
+		       "legacy program 'compress' 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)/_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 \
+	  && ../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 $(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: 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)
+	-rm -f imath_wrap/$(DEPDIR)/$(am__dirstamp)
+	-rm -f imath_wrap/$(am__dirstamp)
+
+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-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-nodist_pkgincludeHEADERS uninstall-pkgconfigDATA \
+	uninstall-pkgincludeHEADERS
+
+.MAKE: $(am__recursive_targets) all 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-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-nodist_pkgincludeHEADERS uninstall-pkgconfigDATA \
+	uninstall-pkgincludeHEADERS
+
+
+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
+
+# 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..95dbd75
--- /dev/null
+++ b/final/lib/External/isl/aclocal.m4
@@ -0,0 +1,1169 @@
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 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-2013 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.14'
+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.14.1], [],
+      [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.14.1])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-2013 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],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 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-2013 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-2013 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-2013 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.  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 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-2013 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}" != 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-2013 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-2013 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-2013 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-2013 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-2013 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-2013 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-2013 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-2013 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-2013 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-2013 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-2013 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_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..6f13da0
--- /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..4ce2d78
--- /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.
+ */
+struct isl_mat *isl_basic_set_reduced_basis(struct 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..e0eeaa8
--- /dev/null
+++ b/final/lib/External/isl/bound.c
@@ -0,0 +1,291 @@
+#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 nvar;
+	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;
+	int 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));
+
+	nvar = isl_set_dim(dom, isl_dim_set);
+	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..e3fc037
--- /dev/null
+++ b/final/lib/External/isl/bound_test.sh.in
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+EXEEXT=@EXEEXT@
+
+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/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..b2227aa
--- /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);
+	argc = cg_options_parse(options, argc, argv, ISL_ARG_ALL);
+
+	ctx = isl_ctx_alloc_with_options(&options_args, options);
+
+	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..531136b
--- /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-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/isl/config.guess b/final/lib/External/isl/config.guess
new file mode 100755
index 0000000..1f5c50c
--- /dev/null
+++ b/final/lib/External/isl/config.guess
@@ -0,0 +1,1420 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-03-23'
+
+# 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.
+#
+# 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
+#
+# Please send patches with a ChangeLog entry 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-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."
+
+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=`(/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 ;;
+    *: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 ;;
+    *: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 ;;
+    *: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 '[A-Z]' '[a-z]'``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 ;;
+    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 ;;
+    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}-unknown-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 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 ;;
+    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 ;;
+    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 ;;
+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;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/isl/config.sub b/final/lib/External/isl/config.sub
new file mode 100755
index 0000000..bba4efb
--- /dev/null
+++ b/final/lib/External/isl/config.sub
@@ -0,0 +1,1799 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-09-11'
+
+# 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 with a ChangeLog entry 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;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 1992-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."
+
+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* | \
+  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 \
+	| be32 | be64 \
+	| bfin \
+	| c4x | c8051 | 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 \
+	| 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[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 | 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-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| c8051-* | 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-* \
+	| 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-* \
+	| 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
+		;;
+	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* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -bitrig* | -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* | -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* | -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*)
+		;;
+	-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..e058920
--- /dev/null
+++ b/final/lib/External/isl/configure
@@ -0,0 +1,21815 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for isl 0.15.
+#
+# 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='isl'
+PACKAGE_TARNAME='isl'
+PACKAGE_VERSION='0.15'
+PACKAGE_STRING='isl 0.15'
+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
+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
+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
+LIBTOOL
+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
+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_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
+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'
+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 isl 0.15 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/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.15:";;
+   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-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
+  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.15
+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
+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.15, 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.14'
+
+# 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}" != 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.15'
+
+
+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.  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=15:0:0
+
+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
+
+
+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"
+
+# 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*|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
+	    ;;
+	  powerpc64le-*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*)
+	    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-*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*)
+	    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
+
+
+
+
+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
+
+
+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"
+
+      if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; 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 "$_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.
+
+
+
+
+
+
+# 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
+  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-%%"`
+
+
+  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_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+    else
+      lt_prog_compiler_no_builtin_flag_CXX=
+    fi
+
+    if test "$GXX" = yes; 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 "$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
+
+
+
+
+
+
+
+      # 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
+        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 "$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.
+
+        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,'
+
+        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
+	    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 "$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
+
+        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_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_CXX='-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__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 "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_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 "${lt_cv_aix_libpath+set}" = 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 "$with_gnu_ld" = yes; 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
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    archive_expsym_cmds_CXX="\$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
+	  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~linknames='
+	  archive_expsym_cmds_CXX='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, 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 (1st line
+	    # is EXPORTS), use it as is; otherwise, prepend...
+	    archive_expsym_cmds_CXX='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
+	    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 "$lt_cv_ld_force_load" = "yes"; 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*) _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_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 "$lt_cv_apple_cc_single_mod" != "yes"; 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
+
+	;;
+
+      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 $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
+              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 $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              ld_shlibs_CXX=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; 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 "$GXX" = yes; then
+	      if test $with_gnu_ld = no; 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 "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; 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 "x$supports_anon_versioning" = xyes; 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
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	ld_shlibs_CXX=no
+	;;
+
+      openbsd*)
+	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__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; 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 "$GXX" = yes && test "$with_gnu_ld" = no; 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 "$GXX" = yes && test "$with_gnu_ld" = no; 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 $LDFLAGS $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 -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 $LDFLAGS $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 -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 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_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 "$ld_shlibs_CXX" = no && 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 $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 "$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 "$pre_test_object_deps_done" = no; 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=
+  ;;
+
+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
+      postdeps_CXX='-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
+      postdeps_CXX='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+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 "$GXX" = yes; 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 "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_CXX='-Bstatic'
+      fi
+      ;;
+
+    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'
+      ;;
+    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 "$host_cpu" = ia64; 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 "$host_cpu" != ia64; 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 which 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"
+   # 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 x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; 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 x"$lt_cv_prog_compiler_static_works_CXX" = xyes; 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 "$lt_cv_prog_compiler_c_o_CXX" = 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; }
+
+  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 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_CXX='$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_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | 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 "$ld_shlibs_CXX" = no && 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 "$enable_shared" = yes && test "$GCC" = yes; 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 "$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}'
+
+      ;;
+    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} $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_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
+
+  # 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_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+   test -n "$runpath_var_CXX" ||
+   test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct_CXX" != 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, CXX)" != no &&
+     test "$hardcode_minus_L_CXX" != no; 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 "$hardcode_action_CXX" = relink ||
+   test "$inherit_rpath_CXX" = 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
+
+
+
+
+
+
+
+  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_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:
+
+
+
+# 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$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"
+
+
+	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`
+	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
+
+
+	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
+
+
+	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
+
+echo '#define GIT_HEAD_ID "'$GIT_HEAD_ID'"' > gitversion.h
+
+
+ac_config_headers="$ac_config_headers isl_config.h"
+
+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"
+
+
+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 "${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.15, 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.15
+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"`'
+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"`'
+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_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 \
+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\\"\\\`\\\\\\""
+      ;;
+    *)
+      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 \
+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\\"\\\`\\\\\\""
+      ;;
+    *)
+      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'
+
+
+
+
+
+# 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" ;;
+    "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" ;;
+
+  *) 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 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="CXX "
+
+# ### 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
+
+# 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
+
+  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"
+
+
+    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 ;;
+
+  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..7362f79
--- /dev/null
+++ b/final/lib/External/isl/configure.ac
@@ -0,0 +1,267 @@
+AC_INIT([isl], [0.15], [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=15:0:0
+
+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__
+
+AC_PROG_LIBTOOL
+
+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(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
+
+AC_SUBST(CLANG_CXXFLAGS)
+AC_SUBST(CLANG_LDFLAGS)
+AC_SUBST(CLANG_LIBS)
+AX_SUBMODULE(clang,system|no,no)
+case "$with_clang" in
+system)
+	AC_PROG_GREP
+	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`
+	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_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_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"
+	;;
+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
+echo '#define GIT_HEAD_ID "'$GIT_HEAD_ID'"' > gitversion.h
+
+AH_BOTTOM([#include <isl_config_post.h>])
+AC_CONFIG_HEADERS(isl_config.h)
+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_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..4ebd5b3
--- /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-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.
+
+# 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..aa79a6c
--- /dev/null
+++ b/final/lib/External/isl/doc/Makefile.am
@@ -0,0 +1,17 @@
+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
+	(cd ..; echo "@GIT_HEAD_VERSION@") > version.tex
+	$(PDFLATEX) $<
+	bibtex 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..b5f56eb
--- /dev/null
+++ b/final/lib/External/isl/doc/Makefile.in
@@ -0,0 +1,473 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 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 = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+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
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+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_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)
+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)
+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@
+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@
+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@
+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@
+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@
+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
+.PRECIOUS: 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:
+
+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
+
+@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
+@GENERATE_DOC_TRUE@	(cd ..; echo "@GIT_HEAD_VERSION@") > version.tex
+@GENERATE_DOC_TRUE@	$(PDFLATEX) $<
+@GENERATE_DOC_TRUE@	bibtex 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/chicago.bst b/final/lib/External/isl/doc/chicago.bst
new file mode 100644
index 0000000..ba05833
--- /dev/null
+++ b/final/lib/External/isl/doc/chicago.bst
@@ -0,0 +1,1726 @@
+%%% ====================================================================
+%%%  @BibTeX-style-file{
+%%%     author          = "Glenn Paulley",
+%%%     version         = "4",
+%%%     date            = "28 August 1992",
+%%%     time            = "10:23:39 199",
+%%%     filename        = "chicago.bst",
+%%%     address         = "Data Structuring Group
+%%%                        Department of Computer Science
+%%%                        University of Waterloo
+%%%                        Waterloo, Ontario, Canada
+%%%                        N2L 3G1",
+%%%     telephone       = "(519) 885-1211",
+%%%     FAX             = "(519) 885-1208",
+%%%     checksum        = "26323 1654 5143 37417",
+%%%     email           = "gnpaulle@bluebox.uwaterloo.ca",
+%%%     codetable       = "ISO/ASCII",
+%%%     keywords        = "",
+%%%     supported       = "yes",
+%%%     abstract        = "A BibTeX bibliography style that follows the
+%%%                        `B' reference style of the 13th Edition of
+%%%                        the Chicago Manual of Style. A detailed
+%%%                        feature list is given below.",
+%%%     docstring       = "The checksum field above contains a CRC-16
+%%%                        checksum as the first value, followed by the
+%%%                        equivalent of the standard UNIX wc (word
+%%%                        count) utility output of lines, words, and
+%%%                        characters.  This is produced by Robert
+%%%                        Solovay's checksum utility.",
+%%%  }
+%%% ====================================================================
+%
+% "Chicago" BibTeX style, chicago.bst
+% ===================================
+%
+% BibTeX `chicago' style file for BibTeX version 0.99c, LaTeX version 2.09
+% Place it in a file called chicago.bst in the BibTeX search path.
+% You need to include chicago.sty as a \documentstyle option.
+% (Placing it in the same directory as the LaTeX document should also work.)
+% This "chicago" style is based on newapa.bst (American Psych. Assoc.)
+% found at ymir.claremont.edu.
+%
+%   Citation format: (author-last-name year)
+%             (author-last-name and author-last-name year)
+%             (author-last-name, author-last-name, and author-last-name year)
+%             (author-last-name et al. year)
+%             (author-last-name)
+%             author-last-name (year)
+%             (author-last-name and author-last-name)
+%             (author-last-name et al.)
+%             (year) or (year,year)
+%             year or year,year
+%
+%   Reference list ordering: alphabetical by author or whatever passes
+%    for author in the absence of one.
+%
+% This BibTeX style has support for abbreviated author lists and for
+%    year-only citations.  This is done by having the citations
+%    actually look like
+%
+%    \citeauthoryear{full-author-info}{abbrev-author-info}{year}
+%
+% The LaTeX style has to have the following (or similar)
+%
+%     \let\@internalcite\cite
+%     \def\fullcite{\def\citeauthoryear##1##2##3{##1, ##3}\@internalcite}
+%     \def\fullciteA{\def\citeauthoryear##1##2##3{##1}\@internalcite}
+%     \def\shortcite{\def\citeauthoryear##1##2##3{##2, ##3}\@internalcite}
+%     \def\shortciteA{\def\citeauthoryear##1##2##3{##2}\@internalcite}
+%     \def\citeyear{\def\citeauthoryear##1##2##3{##3}\@internalcite}
+%
+% These TeX macro definitions are found in chicago.sty. Additional
+% commands to manipulate different components of a citation can be defined
+% so that, for example, you can list author's names without parentheses
+% if using a citation as a noun or object in a sentence.
+%
+% This file was originally copied from newapa.bst at ymir.claremont.edu.
+%
+% Features of chicago.bst:
+% =======================
+%
+% - full names used in citations, but abbreviated citations are available
+%   (see above)
+% - if an entry has a "month", then the month and year are also printed
+%   as part of that bibitem.
+% - all conjunctions use "and" instead of "\&"
+% - major modification from Chicago Manual of Style (13th ed.) is that
+%   only the first author in a reference appears last name first-
+%   additional authors appear as J. Q. Public.
+% - pages are listed as "pp. xx-xx" in all entry types except
+%   article entries.
+% - book, inbook, and manual use "location: publisher" (or organization)
+%   for address and publisher. All other types list publishers separately.
+% - "pp." are used to identify page numbers for all entry types except
+%   articles.
+% - organization is used as a citation label if neither author nor editor
+%   is present (for manuals).
+% - "et al." is used for long author and editor lists, or when "others"
+%   is used.
+%
+% Modifications and bug fixes from newapa.bst:
+% ===========================================
+%
+%   - added month, year to bib entries if month is present
+%   - fixed bug with In proceedings, added necessary comma after title
+%   - all conjunctions changed to "and" from "\&"
+%   - fixed bug with author labels in my.full.label: "et al." now is
+%        generated when "others" is an author name
+%   - major modification from Chicago Manual of Style (13th ed.) is that
+%     only the first author in a reference appears last name first-
+%     additional authors appear as J. Q. Public.
+%   - pages are listed as "pp. xx-xx" in all entry types except
+%     article entries. Unnecessary (IMHO) "()" around page numbers
+%     were removed, and page numbers now don't end with a period.
+%   - created chicago.sty for use with this bibstyle (required).
+%   - fixed bugs in FUNCTION {format.vol.num.pages} for missing volume,
+%     number, and /or pages. Renamed to format.jour.vol.
+%   - fixed bug in formatting booktitles: additional period an error if
+%     book has a volume.
+%   - fixed bug: editors usually given redundant period before next clause
+%     (format.editors.dot) removed.
+%   - added label support for organizations, if both author and editor
+%     are missing (from alpha.bst). If organization is too long, then
+%     the key field is used for abbreviated citations.
+%   - In proceedings or books of several volumes, no comma was written
+%     between the "Volume x" and the page numbers (this was intentional
+%     in newapa.bst). Fixed.
+%   - Some journals may not have volumes/numbers, only month/year (eg.
+%     IEEE Computer). Fixed bug in article style that assumed volume/number
+%     was always present.
+%
+% Original documentation for newapa.sty:
+% =====================================
+%
+% This version was made by modifying the master file made by
+% Oren Patashnik (PATASHNIK@SCORE.STANFORD.EDU), and the 'named' BibTeX
+% style of Peter F. Patel-Schneider.
+%
+% Copyright (C) 1985, all rights reserved.
+% Copying of this file is authorized only if either
+% (1) you make absolutely no changes to your copy, including name, or
+% (2) if you do make changes, you name it something other than 'newapa.bst'.
+% There are undoubtably bugs in this style.  If you make bug fixes,
+% improvements, etc.  please let me know.  My e-mail address is:
+%    spencer@cgrg.ohio.state.edu or 71160.3141@compuserve.com
+%
+% This style was made from 'plain.bst', 'named.bst', and 'apalike.bst',
+% with lots of tweaking to make it look like APA style, along with tips
+% from Young Ryu and Brian Reiser's modifications of 'apalike.bst'.
+
+ENTRY
+  { address
+    author
+    booktitle
+    chapter
+    edition
+    editor
+    fjournal
+    howpublished
+    institution
+    journal
+    key
+    month
+    note
+    number
+    organization
+    pages
+    publisher
+    school
+    series
+    title
+    type
+    volume
+    year
+  }
+  {}
+  { label.year extra.label sort.year sort.label }
+
+INTEGERS { output.state before.all mid.sentence after.sentence after.block }
+
+FUNCTION {init.state.consts}
+{ #0 'before.all :=
+  #1 'mid.sentence :=
+  #2 'after.sentence :=
+  #3 'after.block :=
+}
+
+STRINGS { s t u }
+
+FUNCTION {output.nonnull}
+{ 's :=
+  output.state mid.sentence =
+    { ", " * write$ }
+    { output.state after.block =
+    { add.period$ write$
+      newline$
+      "\newblock " write$
+    }
+    { output.state before.all =
+        'write$
+        { add.period$ " " * write$ }
+      if$
+    }
+      if$
+      mid.sentence 'output.state :=
+    }
+  if$
+  s
+}
+
+% Use a colon to separate output. Used only for address/publisher
+% combination in book/inbook types, address/institution for manuals,
+% and organization:publisher for proceedings (inproceedings).
+%
+FUNCTION {output.nonnull.colon}
+{ 's :=
+  output.state mid.sentence =
+    { ": " * write$ }
+    { output.state after.block =
+    { add.period$ write$
+      newline$
+      "\newblock " write$
+    }
+    { output.state before.all =
+        'write$
+        { add.period$ " " * write$ }
+      if$
+    }
+      if$
+      mid.sentence 'output.state :=
+    }
+  if$
+  s
+}
+
+FUNCTION {output}
+{ duplicate$ empty$
+    'pop$
+    'output.nonnull
+  if$
+}
+
+FUNCTION {output.colon}
+{ duplicate$ empty$
+    'pop$
+    'output.nonnull.colon
+  if$
+}
+
+FUNCTION {output.check}
+{ 't :=
+  duplicate$ empty$
+    { pop$ "empty " t * " in " * cite$ * warning$ }
+    'output.nonnull
+  if$
+}
+
+FUNCTION {output.check.colon}
+{ 't :=
+  duplicate$ empty$
+    { pop$ "empty " t * " in " * cite$ * warning$ }
+    'output.nonnull.colon
+  if$
+}
+
+FUNCTION {output.year.check}
+{ year empty$
+     { "empty year in " cite$ * warning$ }
+     { write$
+        " (" year * extra.label *
+       month empty$
+          { ")" * }
+          { ", " * month * ")" * }
+       if$
+       mid.sentence 'output.state :=
+     }
+  if$
+}
+
+
+FUNCTION {fin.entry}
+{ add.period$
+  write$
+  newline$
+}
+
+FUNCTION {new.block}
+{ output.state before.all =
+    'skip$
+    { after.block 'output.state := }
+  if$
+}
+
+FUNCTION {new.sentence}
+{ output.state after.block =
+    'skip$
+    { output.state before.all =
+    'skip$
+    { after.sentence 'output.state := }
+      if$
+    }
+  if$
+}
+
+FUNCTION {not}
+{   { #0 }
+    { #1 }
+  if$
+}
+
+FUNCTION {and}
+{   'skip$
+    { pop$ #0 }
+  if$
+}
+
+FUNCTION {or}
+{   { pop$ #1 }
+    'skip$
+  if$
+}
+
+FUNCTION {new.block.checka}
+{ empty$
+    'skip$
+    'new.block
+  if$
+}
+
+FUNCTION {new.block.checkb}
+{ empty$
+  swap$ empty$
+  and
+    'skip$
+    'new.block
+  if$
+}
+
+FUNCTION {new.sentence.checka}
+{ empty$
+    'skip$
+    'new.sentence
+  if$
+}
+
+FUNCTION {new.sentence.checkb}
+{ empty$
+  swap$ empty$
+  and
+    'skip$
+    'new.sentence
+  if$
+}
+
+FUNCTION {field.or.null}
+{ duplicate$ empty$
+    { pop$ "" }
+    'skip$
+  if$
+}
+
+%
+% Emphasize the top string on the stack.
+%
+FUNCTION {emphasize}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "{\em " swap$ * "}" * }
+  if$
+}
+
+%
+% Emphasize the top string on the stack, but add a trailing space.
+%
+FUNCTION {emphasize.space}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "{\em " swap$ * "\/}" * }
+  if$
+}
+
+INTEGERS { nameptr namesleft numnames }
+%
+% Format bibliographical entries with the first author last name first,
+% and subsequent authors with initials followed by last name.
+% All names are formatted in this routine.
+%
+FUNCTION {format.names}
+{ 's :=
+  #1 'nameptr :=               % nameptr = 1;
+  s num.names$ 'numnames :=    % numnames = num.name$(s);
+  numnames 'namesleft :=
+    { namesleft #0 > }
+
+    { nameptr #1 =
+        {s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ 't := }
+        {s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't := }
+      if$
+      nameptr #1 >
+        { namesleft #1 >
+              { ", " * t * }
+              { numnames #2 >
+                  { "," * }
+                  'skip$
+                if$
+                t "others" =
+                    { " et~al." * }
+                    { " and " * t * } % from Chicago Manual of Style
+                  if$
+               }
+               if$
+             }
+            't
+        if$
+        s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ 't := 
+	"\protect \index {" * t * "|hyperemph}" *
+        nameptr #1 + 'nameptr :=          % nameptr += 1;
+        namesleft #1 - 'namesleft :=      % namesleft =- 1;
+    }
+  while$
+}
+
+FUNCTION {my.full.label}
+{ 's :=
+  #1 'nameptr :=               % nameptr = 1;
+  s num.names$ 'numnames :=    % numnames = num.name$(s);
+  numnames 'namesleft :=
+    { namesleft #0 > }
+
+    { s nameptr "{vv~}{ll}" format.name$ 't :=  % get the next name
+      nameptr #1 >
+        { namesleft #1 >
+              { ", " * t * }
+              { numnames #2 >
+                  { "," * }
+                  'skip$
+                if$
+                t "others" =
+                    { " et~al." * }
+                    { " and " * t * } % from Chicago Manual of Style
+                  if$
+               }
+               if$
+             }
+            't
+        if$
+        s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ 't := 
+	"\protect \index {" * t * "|bold}" *
+        nameptr #1 + 'nameptr :=          % nameptr += 1;
+        namesleft #1 - 'namesleft :=      % namesleft =- 1;
+    }
+  while$
+
+}
+
+FUNCTION {format.names.fml}
+%
+% Format names in "familiar" format, with first initial followed by
+% last name. Like format.names, ALL names are formatted.
+%
+{ 's :=
+  #1 'nameptr :=               % nameptr = 1;
+  s num.names$ 'numnames :=    % numnames = num.name$(s);
+  numnames 'namesleft :=
+    { namesleft #0 > }
+
+    { s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't :=
+
+      nameptr #1 >
+        { namesleft #1 >
+              { ", " * t * }
+               { numnames #2 >
+                    { "," * }
+                    'skip$
+                  if$
+                  t "others" =
+                        { " et~al." * }
+                        { " and " * t * }
+%                       { " \& " * t * }
+                      if$
+                }
+               if$
+             }
+            't
+        if$
+        nameptr #1 + 'nameptr :=          % nameptr += 1;
+        namesleft #1 - 'namesleft :=      % namesleft =- 1;
+    }
+  while$
+}
+
+FUNCTION {format.authors}
+{ author empty$
+    { "" }
+    { author format.names }
+  if$
+}
+
+FUNCTION {format.key}
+{ empty$
+    { key field.or.null }
+    { "" }
+  if$
+}
+
+%
+% Format editor names for use in the "in" types: inbook, incollection,
+% inproceedings: first initial, then last names. When editors are the
+% LABEL for an entry, then format.editor is used which lists editors
+% by last name first.
+%
+FUNCTION {format.editors.fml}
+{ editor empty$
+    { "" }
+    { editor format.names.fml
+      editor num.names$ #1 >
+    { " (Eds.)" * }
+    { " (Ed.)" * }
+      if$
+    }
+  if$
+}
+
+%
+% Format editor names for use in labels, last names first.
+%
+FUNCTION {format.editors}
+{ editor empty$
+    { "" }
+    { editor format.names
+      editor num.names$ #1 >
+    { " (Eds.)" * }
+    { " (Ed.)" * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.title}
+{ title empty$
+    { "" }
+    { title "t" change.case$ }
+  if$
+}
+
+% Note that the APA style requres case changes
+% in article titles. The following does not
+% change cases. If you perfer it, uncomment the
+% following and comment out the above.
+
+%FUNCTION {format.title}
+%{ title empty$
+%    { "" }
+%    { title }
+%  if$
+%}
+
+FUNCTION {n.dashify}
+{ 't :=
+  ""
+    { t empty$ not }
+    { t #1 #1 substring$ "-" =
+    { t #1 #2 substring$ "--" = not
+        { "--" *
+          t #2 global.max$ substring$ 't :=
+        }
+        {   { t #1 #1 substring$ "-" = }
+        { "-" *
+          t #2 global.max$ substring$ 't :=
+        }
+          while$
+        }
+      if$
+    }
+    { t #1 #1 substring$ *
+      t #2 global.max$ substring$ 't :=
+    }
+      if$
+    }
+  while$
+}
+
+FUNCTION {format.btitle}
+{ edition empty$
+  { title emphasize }
+  { title empty$
+    { title emphasize }
+    { volume empty$     % gnp - check for volume, then don't need period
+       { "{\em " title * "\/} (" * edition * " ed.)" * "." * }
+       { "{\em " title * "\/} (" * edition * " ed.)" * }
+      if$
+    }
+    if$
+  }
+  if$
+}
+
+FUNCTION {format.emphasize.booktitle}
+{ edition empty$
+  { booktitle emphasize }
+  { booktitle empty$
+    { booktitle emphasize }
+    { volume empty$    % gnp - extra period an error if book has a volume
+        { "{\em " booktitle * "\/} (" * edition * " ed.)" * "." *}
+        { "{\em " booktitle * "\/} (" * edition * " ed.)" * }
+      if$
+      }
+    if$
+    }
+  if$
+  }
+
+
+FUNCTION {tie.or.space.connect}
+{ duplicate$ text.length$ #3 <
+    { "~" }
+    { " " }
+  if$
+  swap$ * *
+}
+
+FUNCTION {either.or.check}
+{ empty$
+    'pop$
+    { "can't use both " swap$ * " fields in " * cite$ * warning$ }
+  if$
+}
+
+FUNCTION {format.bvolume}
+{ volume empty$
+    { "" }
+    { "Volume" volume tie.or.space.connect % gnp - changed to mixed case
+      series empty$
+        'skip$
+        { " of " * series emphasize * }
+      if$
+      "volume and number" number either.or.check
+    }
+  if$
+}
+
+FUNCTION {format.number.series}
+{ volume empty$
+    { number empty$
+    { series field.or.null }
+    { output.state mid.sentence =
+        { "Number" } % gnp - changed to mixed case always
+        { "Number" }
+      if$
+      number tie.or.space.connect
+      series empty$
+        { "there's a number but no series in " cite$ * warning$ }
+        { " in " * series * }
+      if$
+    }
+      if$
+    }
+    { "" }
+  if$
+}
+
+INTEGERS { multiresult }
+
+FUNCTION {multi.page.check}
+{ 't :=
+  #0 'multiresult :=
+    { multiresult not
+      t empty$ not
+      and
+    }
+    { t #1 #1 substring$
+      duplicate$ "-" =
+      swap$ duplicate$ "," =
+      swap$ "+" =
+      or or
+    { #1 'multiresult := }
+    { t #2 global.max$ substring$ 't := }
+      if$
+    }
+  while$
+  multiresult
+}
+
+FUNCTION {format.pages}
+{ pages empty$
+  { "" }
+  { pages multi.page.check
+	{ "pp.\ " pages n.dashify tie.or.space.connect } % gnp - removed ()
+	{ "pp.\ " pages tie.or.space.connect }
+    if$
+  }
+  if$
+}
+
+% By Young (and Spencer)
+% GNP - fixed bugs with missing volume, number, and/or pages
+%
+% Format journal, volume, number, pages for article types.
+%
+FUNCTION {format.jour.vol}
+{ fjournal empty$
+    { journal empty$
+	{ "no journal in " cite$ * warning$
+	  "" }
+	{ journal emphasize.space }
+	if$
+    } 
+    { fjournal emphasize.space }
+    if$
+  number empty$
+    { volume empty$
+       { "no number and no volume in " cite$ * warning$
+         "" * }
+       { "~{\em " * Volume * "}" * }
+      if$
+    }
+    { volume empty$
+      {"no volume for " cite$ * warning$
+       "~(" * number * ")" * }
+      { "~" *
+        volume emphasize.space
+        "(" * number * ")" * * }
+      if$
+    }
+  if$
+  pages empty$
+    {"page numbers missing in " cite$ * warning$
+     "" * } % gnp - place a null string on the stack for output
+    { duplicate$ empty$
+      { pop$ format.pages }
+      { ", " *  pages n.dashify * } % gnp - removed pp. for articles
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.chapter.pages}
+{ chapter empty$
+    'format.pages
+    { type empty$
+        { "Chapter" } % gnp - changed to mixed case
+        { type "t" change.case$ }
+      if$
+      chapter tie.or.space.connect
+      pages empty$
+        {"page numbers missing in " cite$ * warning$} % gnp - added check
+        { ", " * format.pages * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.in.ed.booktitle}
+{ booktitle empty$
+  { "" }
+  { editor empty$
+    { "In " format.emphasize.booktitle * }
+    { "In " format.editors.fml * ", " * format.emphasize.booktitle * }
+    if$
+  }
+  if$
+}
+
+FUNCTION {format.thesis.type}
+{ type empty$
+    'skip$
+    { pop$
+      type "t" change.case$
+    }
+  if$
+}
+
+FUNCTION {format.tr.number}
+{ type empty$
+    { "Technical Report" }
+    'type
+  if$
+  number empty$
+    { "t" change.case$ }
+    { number tie.or.space.connect }
+  if$
+}
+
+FUNCTION {format.article.crossref}
+{ "See"
+  "\citeN{" * crossref * "}" *
+}
+
+FUNCTION {format.crossref.editor}
+{ editor #1 "{vv~}{ll}" format.name$
+  editor num.names$ duplicate$
+  #2 >
+    { pop$ " et~al." * }
+    { #2 <
+    'skip$
+    { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" =
+        { " et~al." * }
+        { " and " * editor #2 "{vv~}{ll}" format.name$ * }
+      if$
+    }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.book.crossref}
+{ volume empty$
+    { "empty volume in " cite$ * "'s crossref of " * crossref * warning$
+      "In "
+    }
+    { "Volume" volume tie.or.space.connect % gnp - changed to mixed case
+      " of " *
+    }
+  if$
+  editor empty$
+  editor field.or.null author field.or.null =
+  or
+    { key empty$
+    { series empty$
+        { "need editor, key, or series for " cite$ * " to crossref " *
+          crossref * warning$
+          "" *
+        }
+        { "{\em " * series * "\/}" * }
+      if$
+    }
+    { key * }
+      if$
+    }
+    { format.crossref.editor * }
+  if$
+  " \citeN{" * crossref * "}" *
+}
+
+FUNCTION {format.incoll.inproc.crossref}
+{ "See"
+  " \citeN{" * crossref * "}" *
+}
+
+% format.lab.names:
+%
+% determines "short" names for the abbreviated author information.
+% "Long" labels are created in calc.label, using the routine my.full.label
+% to format author and editor fields.
+%
+% There are 4 cases for labels.   (n=3 in the example)
+% a) one author             Foo
+% b) one to n               Foo, Bar and Baz
+% c) use of "and others"    Foo, Bar et al.
+% d) more than n            Foo et al.
+%
+FUNCTION {format.lab.names}
+{ 's :=
+  s num.names$ 'numnames :=
+  numnames #2 >    % change number to number of others allowed before
+		   % forcing "et al".
+    { s #1 "{vv~}{ll}" format.name$ 
+      "\protect \index {" * 
+      s #1 "{vv~}{ll}{, jj}{, f.}" format.name$ *
+      "}" *
+	"\protect\chicagoetal/" * }
+    {
+      numnames #1 - 'namesleft :=
+      #2 'nameptr :=
+      s #1 "{vv~}{ll}" format.name$
+      "\protect \index {" * 
+      s #1 "{vv~}{ll}{, jj}{, f.}" format.name$ *
+      "}" *
+	{ namesleft #0 > }
+	{ nameptr numnames =
+	    { s nameptr "{ff }{vv }{ll}{ jj}" format.name$ "others" =
+		{ "\protect\chicagoetal/" * }
+		{ "\protect\chicagoand/" * s nameptr "{vv~}{ll}" format.name$ * 
+		  "\protect \index {" * 
+		  s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ *
+		  "}" *
+                }
+	      if$
+	    }
+	    { ", " * s nameptr "{vv~}{ll}" format.name$ * }
+	  if$
+	  nameptr #1 + 'nameptr :=
+	  namesleft #1 - 'namesleft :=
+	}
+      while$
+    }
+  if$
+}
+
+FUNCTION {author.key.label}
+{ author empty$
+    { key empty$
+          { "no key, author in " cite$ * warning$
+            cite$ #1 #3 substring$ }
+         'key
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {editor.key.label}
+{ editor empty$
+    { key empty$
+          { "no key, editor in " cite$ * warning$
+            cite$ #1 #3 substring$ }
+          'key
+        if$
+     }
+     { editor format.lab.names }
+  if$
+}
+
+FUNCTION {author.key.organization.label}
+%
+% added - gnp. Provide label formatting by organization if author is null.
+%
+{ author empty$
+    { organization empty$
+	{ key empty$
+	    { "no key, author or organization in " cite$ * warning$
+              cite$ #1 #3 substring$ }
+	    'key
+	  if$
+	}
+        { organization }
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {editor.key.organization.label}
+%
+% added - gnp. Provide label formatting by organization if editor is null.
+%
+{ editor empty$
+    { organization empty$
+	{ key empty$
+	    { "no key, editor or organization in " cite$ * warning$
+              cite$ #1 #3 substring$ }
+	    'key
+	  if$
+	}
+        { organization }
+      if$
+    }
+    { editor format.lab.names }
+  if$
+}
+
+FUNCTION {author.editor.key.label}
+{ author empty$
+    { editor empty$
+          { key empty$
+               { "no key, author, or editor in " cite$ * warning$
+                 cite$ #1 #3 substring$ }
+             'key
+           if$
+         }
+          { editor format.lab.names }
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {calc.label.orig}
+%
+% Changed - GNP. See also author.organization.sort, editor.organization.sort
+% Form label for BibTeX entry. The classification of which fields are used
+% for which type of entry (book, inbook, etc.) are taken from alpha.bst.
+% The change here from newapa is to also include organization as a
+% citation label if author or editor is missing.
+%
+{ type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.key.label
+    { type$ "proceedings" =
+	'editor.key.organization.label
+	{ type$ "manual" =
+	    'author.key.organization.label
+	    'author.key.label
+	  if$
+	}
+      if$
+    }
+  if$
+
+  author empty$  % generate the full label citation information.
+    { editor empty$
+        { organization empty$
+           { "no author, editor, or organization in " cite$ * warning$
+             "??" }
+           { organization }
+           if$
+        }
+        { editor my.full.label }
+        if$
+    }
+    { author.key.label }
+  if$
+
+% leave label on the stack, to be popped when required.
+
+  "}{" * swap$ *
+%  year field.or.null purify$ #-1 #4 substring$ *
+%
+% save the year for sort processing afterwards (adding a, b, c, etc.)
+%
+  year field.or.null purify$ #-1 #4 substring$
+  'label.year :=
+}
+
+FUNCTION {calc.label}
+%
+% Changed - GNP. See also author.organization.sort, editor.organization.sort
+% Form label for BibTeX entry. The classification of which fields are used
+% for which type of entry (book, inbook, etc.) are taken from alpha.bst.
+% The change here from newapa is to also include organization as a
+% citation label if author or editor is missing.
+%
+{ type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.key.label
+    { type$ "proceedings" =
+	'editor.key.organization.label
+	{ type$ "manual" =
+	    'author.key.organization.label
+	    'author.key.label
+	  if$
+	}
+      if$
+    }
+  if$
+
+  author empty$  % generate the full label citation information.
+    { editor empty$
+        { organization empty$
+           { "no author, editor, or organization in " cite$ * warning$
+             "??" }
+           { organization }
+           if$
+        }
+        { editor my.full.label }
+        if$
+    }
+    { author my.full.label }
+  if$
+
+% leave label on the stack, to be popped when required.
+
+  "}{" * swap$ * "}{" * title * "}{" *
+%  year field.or.null purify$ #-1 #4 substring$ *
+%
+% save the year for sort processing afterwards (adding a, b, c, etc.)
+%
+  year field.or.null purify$ #-1 #4 substring$
+  'label.year :=
+}
+
+FUNCTION {output.bibitem}
+{ newline$
+
+  "\bibitem[\protect\citeauthortitleyear{" write$
+  calc.label write$
+  sort.year write$
+  "}]{" write$
+
+  cite$ write$
+  "}" write$
+  newline$
+  ""
+  before.all 'output.state :=
+}
+
+FUNCTION {article}
+{ output.bibitem
+  format.authors
+  "author" output.check
+  author format.key output          % added
+  output.year.check                 % added
+  new.block
+  format.title
+  "title" output.check
+  new.block
+  crossref missing$
+    { format.jour.vol output
+    }
+    { format.article.crossref output.nonnull
+      format.pages output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {book}
+{ output.bibitem
+  author empty$
+    { format.editors
+	  "author and editor" output.check }
+    { format.authors
+	  output.nonnull
+      crossref missing$
+    	{ "author and editor" editor either.or.check }
+    	'skip$
+      if$
+    }
+  if$
+  output.year.check       % added
+  new.block
+  format.btitle
+  "title" output.check
+  crossref missing$
+    { format.bvolume output
+      new.block
+      format.number.series output
+      new.sentence
+      address output
+      publisher "publisher" output.check.colon
+    }
+    { new.block
+      format.book.crossref output.nonnull
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {booklet}
+{ output.bibitem
+  format.authors output
+  author format.key output          % added
+  output.year.check                 % added
+  new.block
+  format.title
+  "title" output.check
+  new.block
+  howpublished output
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inbook}
+{ output.bibitem
+  author empty$
+    { format.editors
+      "author and editor" output.check
+    }
+    { format.authors output.nonnull
+      crossref missing$
+    { "author and editor" editor either.or.check }
+    'skip$
+      if$
+    }
+  if$
+  output.year.check                 % added
+  new.block
+  format.btitle
+  "title" output.check
+  crossref missing$
+    { format.bvolume output
+      format.chapter.pages
+      "chapter and pages" output.check
+      new.block
+      format.number.series output
+      new.sentence
+      address output
+      publisher
+      "publisher" output.check.colon
+    }
+    { format.chapter.pages "chapter and pages" output.check
+      new.block
+      format.book.crossref output.nonnull
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {incollection}
+{ output.bibitem
+  format.authors
+  "author" output.check
+  author format.key output       % added
+  output.year.check              % added
+  new.block
+  format.title
+  "title" output.check
+  new.block
+  crossref missing$
+  { format.in.ed.booktitle
+    "booktitle" output.check
+    format.bvolume output
+    format.number.series output
+    format.chapter.pages output % gnp - was special.output.nonnull
+%                                 left out comma before page numbers
+    new.sentence
+    address output
+    publisher "publisher" output.check.colon
+  }
+  { format.incoll.inproc.crossref
+	output.nonnull
+    format.chapter.pages output
+  }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inproceedings}
+{ output.bibitem
+  format.authors
+  "author" output.check
+  author format.key output            % added
+  output.year.check                   % added
+  new.block
+  format.title
+  "title" output.check
+  new.block
+  crossref missing$
+    { format.in.ed.booktitle
+	  "booktitle" output.check
+      format.bvolume output
+      format.number.series output
+      address output
+      format.pages output
+      new.sentence
+      organization output
+      publisher output.colon
+      }
+    { format.incoll.inproc.crossref output.nonnull
+      format.pages output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {conference} { inproceedings }
+
+FUNCTION {manual}
+{ output.bibitem
+  author empty$
+    { editor empty$
+      { organization "organization" output.check
+        organization format.key output }  % if all else fails, use key
+      { format.editors "author and editor" output.check }
+      if$
+    }
+    { format.authors output.nonnull }
+    if$
+  output.year.check                 % added
+  new.block
+  format.btitle
+  "title" output.check
+  organization address new.block.checkb
+% Reversed the order of "address" and "organization", added the ":".
+  address output
+  organization "organization" output.check.colon
+%  address output
+%  ":" output
+%  organization output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {mastersthesis}
+{ output.bibitem
+  format.authors
+  "author" output.check
+  author format.key output          % added
+  output.year.check                 % added
+  new.block
+  format.title
+  "title" output.check
+  new.block
+  "Master's thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {misc}
+{ output.bibitem
+  format.authors output
+  author format.key output            % added
+  output.year.check                   % added
+  title howpublished new.block.checkb
+  format.title output
+  new.block
+  howpublished output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {phdthesis}
+{ output.bibitem
+  format.authors
+  "author" output.check
+  author format.key output            % added
+  output.year.check                   % added
+  new.block
+  format.btitle
+  "title" output.check
+  new.block
+  "Ph.\ D. thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {proceedings}
+{ output.bibitem
+  editor empty$
+    { organization output
+      organization format.key output }  % gnp - changed from author format.key
+    { format.editors output.nonnull }
+  if$
+% author format.key output             % gnp - removed (should be either
+%                                        editor or organization
+  output.year.check                    % added (newapa)
+  new.block
+  format.btitle
+  "title" output.check
+  format.bvolume output
+  format.number.series output
+  address output
+  new.sentence
+  organization output
+  publisher output.colon
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {techreport}
+{ output.bibitem
+  format.authors
+  "author" output.check
+  author format.key output             % added
+  output.year.check                    % added
+  new.block
+  format.title
+  "title" output.check
+  new.block
+  format.tr.number output.nonnull
+  institution
+  "institution" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {unpublished}
+{ output.bibitem
+  format.authors
+  "author" output.check
+  author format.key output              % added
+  output.year.check                      % added
+  new.block
+  format.title
+  "title" output.check
+  new.block
+  note "note" output.check
+  fin.entry
+}
+
+FUNCTION {default.type} { misc }
+
+MACRO {jan} {"January"}
+
+MACRO {feb} {"February"}
+
+MACRO {mar} {"March"}
+
+MACRO {apr} {"April"}
+
+MACRO {may} {"May"}
+
+MACRO {jun} {"June"}
+
+MACRO {jul} {"July"}
+
+MACRO {aug} {"August"}
+
+MACRO {sep} {"September"}
+
+MACRO {oct} {"October"}
+
+MACRO {nov} {"November"}
+
+MACRO {dec} {"December"}
+
+MACRO {acmcs} {"ACM Computing Surveys"}
+
+MACRO {acta} {"Acta Informatica"}
+
+MACRO {ai} {"Artificial Intelligence"}
+
+MACRO {cacm} {"Communications of the ACM"}
+
+MACRO {ibmjrd} {"IBM Journal of Research and Development"}
+
+MACRO {ibmsj} {"IBM Systems Journal"}
+
+MACRO {ieeese} {"IEEE Transactions on Software Engineering"}
+
+MACRO {ieeetc} {"IEEE Transactions on Computers"}
+
+MACRO {ieeetcad}
+ {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"}
+
+MACRO {ipl} {"Information Processing Letters"}
+
+MACRO {jacm} {"Journal of the ACM"}
+
+MACRO {jcss} {"Journal of Computer and System Sciences"}
+
+MACRO {scp} {"Science of Computer Programming"}
+
+MACRO {sicomp} {"SIAM Journal on Computing"}
+
+MACRO {tocs} {"ACM Transactions on Computer Systems"}
+
+MACRO {tods} {"ACM Transactions on Database Systems"}
+
+MACRO {tog} {"ACM Transactions on Graphics"}
+
+MACRO {toms} {"ACM Transactions on Mathematical Software"}
+
+MACRO {toois} {"ACM Transactions on Office Information Systems"}
+
+MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"}
+
+MACRO {tcs} {"Theoretical Computer Science"}
+
+READ
+
+FUNCTION {sortify}
+{ purify$
+  "l" change.case$
+}
+
+INTEGERS { len }
+
+FUNCTION {chop.word}
+{ 's :=
+  'len :=
+  s #1 len substring$ =
+    { s len #1 + global.max$ substring$ }
+    's
+  if$
+}
+
+
+
+FUNCTION {sort.format.names}
+{ 's :=
+  #1 'nameptr :=
+  ""
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { nameptr #2 =
+	{ year field.or.null purify$ #-1 #4 substring$ * }
+	'skip$
+      if$
+      nameptr #1 >
+          { "   " * }
+         'skip$
+      if$
+      s nameptr "{vv{ } }{ll{ }}{  f{ }}{  jj{ }}" format.name$ 't :=
+      nameptr numnames = t "others" = and
+          { " et~al" * }
+          { t sortify * }
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {sort.format.title}
+{ 't :=
+  "A " #2
+    "An " #3
+      "The " #4 t chop.word
+    chop.word
+  chop.word
+  sortify
+  #1 global.max$ substring$
+}
+
+FUNCTION {author.sort}
+{ author empty$
+    { key empty$
+         { "to sort, need author or key in " cite$ * warning$
+           "" }
+         { key sortify }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {editor.sort}
+{ editor empty$
+    { key empty$
+         { "to sort, need editor or key in " cite$ * warning$
+           ""
+         }
+         { key sortify }
+      if$
+    }
+    { editor sort.format.names }
+  if$
+}
+
+FUNCTION {author.editor.sort}
+{ author empty$
+    { "missing author in " cite$ * warning$
+      editor empty$
+         { key empty$
+             { "to sort, need author, editor, or key in " cite$ * warning$
+               ""
+             }
+             { key sortify }
+           if$
+         }
+         { editor sort.format.names }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {author.organization.sort}
+%
+% added - GNP. Stack author or organization for sorting (from alpha.bst).
+% Unlike alpha.bst, we need entire names, not abbreviations
+%
+{ author empty$
+    { organization empty$
+	{ key empty$
+	    { "to sort, need author, organization, or key in " cite$ * warning$
+	      ""
+	    }
+	    { key sortify }
+	  if$
+	}
+	{ organization sortify }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {editor.organization.sort}
+%
+% added - GNP. Stack editor or organization for sorting (from alpha.bst).
+% Unlike alpha.bst, we need entire names, not abbreviations
+%
+{ editor empty$
+    { organization empty$
+	{ key empty$
+	    { "to sort, need editor, organization, or key in " cite$ * warning$
+	      ""
+	    }
+	    { key sortify }
+	  if$
+	}
+	{ organization sortify }
+      if$
+    }
+    { editor sort.format.names }
+  if$
+}
+
+FUNCTION {presort}
+%
+% Presort creates the bibentry's label via a call to calc.label, and then
+% sorts the entries based on entry type. Chicago.bst adds support for
+% including organizations as the sort key; the following is stolen from
+% alpha.bst.
+%
+{ %calc.label sortify % recalculate bibitem label
+  %year field.or.null purify$ #-1 #4 substring$ * % add year
+  %duplicate$ warning$
+  %"    "
+  %*
+  type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.sort
+    { type$ "proceedings" =
+	'editor.organization.sort
+	{ type$ "manual" =
+	    'author.organization.sort
+	    'author.sort
+	  if$
+	}
+      if$
+    }
+  if$
+  #1 entry.max$ substring$        % added for newapa
+  'sort.label :=                  % added for newapa
+  sort.label                      % added for newapa
+  %*
+  "    "
+  *
+  title field.or.null
+  sort.format.title
+  *
+  #1 entry.max$ substring$
+  'sort.key$ :=
+}
+
+ITERATE {presort}
+
+SORT             % by label, year, author/editor, title
+
+STRINGS { last.label next.extra }
+
+INTEGERS { last.extra.num }
+
+FUNCTION {initialize.extra.label.stuff}
+{ #0 int.to.chr$ 'last.label :=
+  "" 'next.extra :=
+  #0 'last.extra.num :=
+}
+
+FUNCTION {forward.pass}
+%
+% Pass through all entries, comparing current entry to last one.
+% Need to concatenate year to the stack (done by calc.label) to determine
+% if two entries are the same (see presort)
+%
+{ last.label
+  calc.label.orig year field.or.null purify$ #-1 #4 substring$ * % add year
+  #1 entry.max$ substring$ =     % are they equal?
+     { last.extra.num #1 + 'last.extra.num :=
+       last.extra.num int.to.chr$ 'extra.label :=
+     }
+     { "a" chr.to.int$ 'last.extra.num :=
+       "" 'extra.label :=
+       calc.label.orig year field.or.null purify$ #-1 #4 substring$ * % add year
+       #1 entry.max$ substring$ 'last.label := % assign to last.label
+     }
+  if$
+}
+
+FUNCTION {reverse.pass}
+{ next.extra "b" =
+    { "a" 'extra.label := }
+     'skip$
+  if$
+  label.year extra.label * 'sort.year :=
+  extra.label 'next.extra :=
+}
+
+EXECUTE {initialize.extra.label.stuff}
+
+ITERATE {forward.pass}
+
+REVERSE {reverse.pass}
+
+FUNCTION {bib.sort.order}
+{ sort.label
+  "    "
+  *
+  year field.or.null sortify
+  *
+  "    "
+  *
+  title field.or.null
+  sort.format.title
+  *
+  #1 entry.max$ substring$
+  'sort.key$ :=
+}
+
+ITERATE {bib.sort.order}
+
+SORT             % by sort.label, year, title --- giving final bib. order.
+
+FUNCTION {begin.bib}
+
+{ preamble$ empty$
+    'skip$
+    { preamble$ write$ newline$ }
+  if$
+  "\begin{thebibliography}{}" write$ newline$
+}
+
+
+EXECUTE {begin.bib}
+
+EXECUTE {init.state.consts}
+
+ITERATE {call.type$}
+
+FUNCTION {end.bib}
+{ newline$
+  "\end{thebibliography}" write$ newline$
+}
+
+EXECUTE {end.bib}
+
diff --git a/final/lib/External/isl/doc/chicago.sty b/final/lib/External/isl/doc/chicago.sty
new file mode 100644
index 0000000..33588db
--- /dev/null
+++ b/final/lib/External/isl/doc/chicago.sty
@@ -0,0 +1,320 @@
+% -*- LaTeX -*-
+%%% ====================================================================
+%%%  @LaTeX-style-file{
+%%%     author          = "Glenn Paulley",
+%%%     version         = "4",
+%%%     date            = "31 August 1992",
+%%%     time            = "09:42:44 199",
+%%%     filename        = "chicago.sty",
+%%%     address         = "Data Structuring Group
+%%%                        Department of Computer Science
+%%%                        University of Waterloo
+%%%                        Waterloo, Ontario, Canada
+%%%                        N2L 3G1",
+%%%     telephone       = "(519) 885-1211",
+%%%     FAX             = "(519) 885-1208",
+%%%     checksum        = "44674 264 1050 10394",
+%%%     email           = "gnpaulle@bluebox.uwaterloo.ca",
+%%%     codetable       = "ISO/ASCII",
+%%%     keywords        = "",
+%%%     supported       = "yes",
+%%%     abstract        = "Contains the LaTeX style command definitions
+%%%                        for the Chicago BibTeX styles chicago.bst and
+%%%                        chicagoa.bst. For details, see below.",
+%%%     docstring       = "The checksum field above contains a CRC-16
+%%%                        checksum as the first value, followed by the
+%%%                        equivalent of the standard UNIX wc (word
+%%%                        count) utility output of lines, words, and
+%%%                        characters.  This is produced by Robert
+%%%                        Solovay's checksum utility.",
+%%%  }
+%%% ====================================================================
+%
+% chicago.sty: Style file for use with bibtex style chicago.bst, for
+% bibliographies formatted according to the 13th Edition of the Chicago
+% Manual of Style.
+%
+% 'newapa.bst' was made from 'plain.bst', 'named.bst', and 'apalike.bst',
+% with lots of tweaking to make it look like APA style, along with tips
+% from Young Ryu and Brian Reiser's modifications of 'apalike.bst'.
+% newapa.sty formed the basis of this style, chicago.sty. Author-date
+% references in newapa.bst formed the basis for chicago.bst. Chicagoa.bst
+% supports annotations.
+%
+% Version 4 (August, 1992):
+% - fixed chicago.bst and chicagoa.bst to handle long author lists in
+%   sorting
+% - fixed chicago.bst and chicagoa.bst so that missing page numbers in
+%   ``article'' entries are handled correctly
+% - modified chicago.sty to format entries with 2nd and subsequent lines
+%   indented.
+%
+%   Citation format: (author-last-name year)
+%             (author-last-name and author-last-name year)
+%             (author-last-name et al. year)
+%             (author-last-name)
+%             author-last-name
+%             author-last-name (year)
+%             (author-last-name and author-last-name)
+%             (author-last-name et al.)
+%             (year) or (year,year)
+%             year or year,year
+%
+%   Reference list ordering: alphabetical by author or whatever passes
+%    for author in the absence of one.
+%
+% This BibTeX style has support for abbreviated author lists and for
+%    year-only citations.  This is done by having the citations
+%    actually look like
+%
+%    \citeauthoryear{full-author-info}{abbrev-author-info}{year}
+%
+% The LaTeX style has to have the following (or similar)
+%
+%     \let\@internalcite\cite
+%     \def\fullcite{\def\citeauthoryear##1##2##3{##1, ##3}\@internalcite}
+%     \def\fullciteA{\def\citeauthoryear##1##2##3{##1}\@internalcite}
+%     \def\shortcite{\def\citeauthoryear##1##2##3{##2, ##3}\@internalcite}
+%     \def\shortciteA{\def\citeauthoryear##1##2##3{##2}\@internalcite}
+%     \def\citeyear{\def\citeauthoryear##1##2##3{##3}\@internalcite}
+%
+% -------------------------------------------------------------------------
+% This file implements citations for the ``chicago'' bibliography style.
+%  Place it in a file called chicago.sty in the TeX search path.
+%(Placing it in the same directory as the LaTeX document should also work.)
+%
+%    This file is a modification of the ``newapa'' LaTeX style,
+%    originally adapted by Steven Spencer from the ``apalike'' LaTeX style.
+%    It was originally modified by Stephen N. Spencer, with further
+%    modifications by Young U. Ryu.
+%
+% The ``chicago'' BibTeX bibliography style creates citations with labels:
+%       \citeauthoryear{author-info}{abbrev. author-info}{year}
+%
+% These labels are processed by the following LaTeX commands:
+%
+%  \cite{key}
+%    which produces citations with full author list and year.
+%    eg. (Brown 1978; Jarke, Turner, Stohl, et al. 1985)
+%  \citeNP{key}
+%    which produces citations with full author list and year, but without
+%    enclosing parentheses:
+%    eg. Brown 1978; Jarke, Turner and Stohl 1985
+%  \citeA{key}
+%    which produces citations with only the full author list.
+%    eg. (Brown; Jarke, Turner and Stohl)
+%  \citeANP{key}
+%    which produces citations with only the full author list, without
+%    parentheses eg. Brown; Jarke, Turner and Stohl
+%  \citeN{key}
+%    which produces citations with the full author list and year, but
+%    can be used as nouns in a sentence; no parentheses appear around
+%    the author names, but only around the year.
+%      eg. Shneiderman (1978) states that......
+%    \citeN should only be used for a single citation.
+%  \shortcite{key}
+%    which produces citations with abbreviated author list and year.
+%  \shortciteNP{key}
+%    which produces citations with abbreviated author list and year.
+%  \shortciteA{key}
+%    which produces only the abbreviated author list.
+%  \shortciteANP{key}
+%    which produces only the abbreviated author list.
+%  \shortciteN{key}
+%    which produces the abbreviated author list and year, with only the
+%    year in parentheses. Use with only one citation.
+%  \citeyear{key}
+%    which produces the year information only, within parentheses.
+%  \citeyearNP{key}
+%    which produces the year information only.
+%
+% Abbreviated author lists use the ``et al.'' construct.
+%
+% `NP' means `no parentheses'.
+%
+% This LaTeX style file must be used with the ``chicago'' or ``chicagoa''
+% (annotated chicago style) BibTeX styles.
+%
+\typeout{Using Chicago Manual of Style bibliography: 31 August 1992}
+%
+% -------------------------------------------------------------------------
+%
+% Citation macros.
+%
+\def\chicagoand/{ and }
+\def\chicagoetal/{ et~al.}
+%
+\let\@internalcite\cite
+%
+\def\cite{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{(##1\if@tempswa , ##2\fi)}%
+    \def\citeauthortitleyear##1##2##3##4{##1\ ##4}\@internalcite}
+\def\citeNP{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##1\ ##4}\@internalcite}
+\def\citetitleN{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2)\else{)}\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##3\ (##1; ##4}\@citedata}
+\def\citeN{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2)\else{)}\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##1\ (##4}\@citedata}
+\def\citeA{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{(##1\if@tempswa , ##2\fi)}%
+    \def\citeauthortitleyear##1##2##3##4{##1}\@internalcite}
+\def\citeANP{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##1}\@internalcite}
+%
+\def\shortcite{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{(##1\if@tempswa , ##2\fi)}%
+    \def\citeauthortitleyear##1##2##3##4{##2\ ##4}\@internalcite}
+\def\shortciteNP{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##2\ ##4}\@internalcite}
+\def\shortciteN{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2)\else{)}\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##2\ (##4}\@citedata}
+\def\shortciteA{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{(##1\if@tempswa , ##2\fi)}%
+    \def\citeauthortitleyear##1##2##3##4{##2}\@internalcite}
+\def\shortciteANP{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##2}\@internalcite}
+%
+\def\citeyear{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{(##1\if@tempswa , ##2\fi)}%
+    \def\citeauthortitleyear##1##2##3##4{##4}\@citedata}
+\def\citeyearNP{\def\@citeseppen{-1000}%
+    \def\@cite##1##2{##1\if@tempswa , ##2\fi}%
+    \def\citeauthortitleyear##1##2##3##4{##4}\@citedata}
+
+%
+% \@citedata and \@citedatax:
+%
+% Place commas in-between citations in the same \citeyear, \citeyearNP,
+% \citeN, or \shortciteN command.
+% Use something like \citeN{ref1,ref2,ref3} and \citeN{ref4} for a list.
+%
+\def\@citedata{%
+	\@ifnextchar [{\@tempswatrue\@citedatax}%
+				  {\@tempswafalse\@citedatax[]}%
+}
+
+\def\@citedatax[#1]#2{%
+\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi%
+  \def\@citea{}\@cite{\@for\@citeb:=#2\do%
+    {\@citea\def\@citea{), }\@ifundefined% by Young
+       {b@\@citeb}{{\bf ?}%
+       \@warning{Citation `\@citeb' on page \thepage \space undefined}}%
+{\csname b@\@citeb\endcsname}}}{#1}}%
+
+\@ifpackageloaded{hyperref}{%
+  \let\BRorg@citedatax\@citedatax 
+  \def\@citedatax[#1]#2{%
+    \BRorg@citedatax[#1]{#2}%
+    \Hy@backout{#2}%
+  }%
+}{}
+\@ifpackageloaded{hyperref}{%
+\def\hyperemph#1{{\em\hyperpage{#1}}}%
+\def\bold#1{{\bf\hyperpage{#1}}}%
+}{%
+\def\hyperemph#1{{\em #1}}%
+\def\bold#1{{\bf #1}}%
+}
+
+\def\BR@@lbibitem[#1]#2#3\par{%
+  \BRorg@bibitem[#1]{#2}#3\hfill\penalty100\hbox{}
+  \newblock
+  \backref\hfill[{\csname br@#2\endcsname}%
+  ]\parskip=-10pt\penalty-10000\hbox{}\nobreak\par
+}%
+\def\BR@@bibitem#1#2\par{%
+  \BRorg@bibitem{#1}#2
+  \newblock
+  \backref\penalty-100\hbox{}\nobreak\hfill[\hbox{\csname br@#2\endcsname}%
+  ]\par
+}
+\def\thepageorcolor{\thepage}
+\def\Hy@backout#1{%
+  \@bsphack
+  \ifx\@empty\@currentlabel
+    \protected@write\@auxout{}{%
+      \string\@writefile{brf}{%
+        \string\backcite{#1}{{\thepageorcolor}{(document)}{Doc-Start}}%
+      }%
+    }%
+  \else
+   \protected@write\@auxout{}{%
+     \string\@writefile{brf}{%
+       \string\backcite{#1}{{\thepageorcolor}{\@currentlabel}{\@currentHref}}%
+     }%
+   }%
+  \fi
+  \@esphack
+}
+
+% don't box citations, separate with ; and a space
+% also, make the penalty between citations negative: a good place to break.
+%
+\def\@citex[#1]#2{%
+\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi%
+  \def\@citea{}\@cite{\@for\@citeb:=#2\do%
+    {\@citea\def\@citea{; }\@ifundefined% by Young
+       {b@\@citeb}{{\bf ?}%
+       \@warning{Citation `\@citeb' on page \thepage \space undefined}}%
+{\csname b@\@citeb\endcsname}}}{#1}}%
+
+% (from apalike.sty)
+% No labels in the bibliography.
+%
+\def\@biblabel#1{}
+
+% (from apalike.sty)
+% Set length of hanging indentation for bibliography entries.
+%
+\newlength{\bibhang}
+\setlength{\bibhang}{2em}
+
+% Indent second and subsequent lines of bibliographic entries. Stolen
+% from openbib.sty: \newblock is set to {}.
+
+\newdimen\bibindent
+\bibindent=1.5em
+\@ifundefined{refname}%
+   {\@ifundefined{chapter}%
+     {\newcommand{\refname}{References}}%
+     {\newcommand{\refname}{Bibliography}}%
+   }%
+   {}%
+\@ifundefined{chapter}%
+ {\def\thebibliography#1{\section*{\refname\@mkboth
+   {\uppercase{\refname}}{\uppercase{\refname}}}
+   \addcontentsline{toc}{section}{References}
+   \list
+   {[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}
+   \leftmargin\labelwidth
+   \advance\leftmargin\labelsep
+   \advance\leftmargin\bibindent
+   \itemindent -\bibindent
+   \listparindent \itemindent
+   \parsep \z@
+   \usecounter{enumi}}
+   \def\newblock{}
+   \sloppy
+   \sfcode`\.=1000\relax}}
+ {\def\thebibliography#1{\chapter*{\refname\@mkboth
+   {\refname}{\refname}}
+   \addcontentsline{toc}{chapter}{References}
+   \list
+   {[\arabic{enumi}]}{\settowidth\labelwidth{[#1]}
+   \leftmargin\labelwidth
+   \advance\leftmargin\labelsep
+   \advance\leftmargin\bibindent
+   \itemindent -\bibindent
+   \listparindent \itemindent
+   \parsep \z@
+   \usecounter{enumi}}
+   \def\newblock{}
+   \sloppy
+   \sfcode`\.=1000\relax}}
diff --git a/final/lib/External/isl/doc/implementation.tex b/final/lib/External/isl/doc/implementation.tex
new file mode 100644
index 0000000..76d1acd
--- /dev/null
+++ b/final/lib/External/isl/doc/implementation.tex
@@ -0,0 +1,2036 @@
+\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 \shortcite{Feautrier88parametric}
+is used to solve many problems within the context of the polyhedral model.
+Here, we are mainly interested in dependence analysis \shortcite{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
+\shortcite{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 \shortciteN{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} \shortcite{Detlefs2005simplify}, which, in turn,
+was derived from the work of \shortciteN{Nelson1980phd}.
+In the original \shortcite{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, \shortciteN[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
+\shortcite{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 \shortciteN{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
+\shortcite{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 \shortciteN{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.
+
+\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''
+\shortcite{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 \shortciteN{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 \shortciteN{Galea2009personal}, who
+worked on a parametric integer programming implementation
+in {\tt PPL} \shortcite{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 \shortcite{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 \shortciteN{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}
+
+\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.
+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 \shortcite{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 \shortciteN{Seghir2006minimizing}.
+The remaining two come from \shortciteN{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
+\shortciteN{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
+\shortciteN{Bygde2010licentiate} and an analysis of the results
+by the approximate MPA method developed by \shortciteN{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 \shortciteN{Verdoolaege2009isl}, for now.
+More details will be added later.
+
+\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 \shortcite{Kelly1996closure},
+we can, in the general case, only compute an approximation
+of the transitive closure.
+Whereas \shortciteN{Kelly1996closure} compute underapproximations,
+we, like \shortciteN{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 \shortciteN{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 \shortciteN{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 \shortcite[Theorem~16.4]{Schrijver1986}.
+
+Note however that, as pointed out by \shortciteN{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 \shortciteN{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 \shortcite{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~\shortcite{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 \shortciteN[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 \shortciteN{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.,
+\shortciteN[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
+\shortciteN{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\shortciteN{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\shortciteN{Beletska2009} and its transitive closure}
+\label{f:COCOA:1}
+\end{figure}
+\begin{example}
+Consider the relation on the right of Figure~1 of
+\shortciteN{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^+$.
+\shortciteN{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$.
+\shortciteN{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.
+\shortciteN{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 \shortciteN{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
+\shortcite[Section 6.4]{Omega_lib}.
+
+The main tool is Equation~(2) of \shortciteN{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
+\shortciteN{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..cfe8081
--- /dev/null
+++ b/final/lib/External/isl/doc/isl.bib
@@ -0,0 +1,313 @@
+@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},
+}
+
+@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}
+}
+
+@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 =    {},
+}
+
+@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.},
+}
+
+@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},
+}
+
+@misc{barvinok-0.22,
+  author = {Sven Verdoolaege},
+  title = {{\texttt{barvinok}}, version 0.22},
+  howpublished = {Available from \url{http://freshmeat.net/projects/barvinok/}},
+  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",
+}
+
+@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",
+}
+
+@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={ },
+}
+
+@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}
+}
+
+@misc{DeSmet2010personal,
+    author = "De Smet, Sven",
+    title = "personal communication",
+    year = 2010,
+    month = apr,
+}
diff --git a/final/lib/External/isl/doc/manual.pdf b/final/lib/External/isl/doc/manual.pdf
new file mode 100644
index 0000000..1d61308
--- /dev/null
+++ b/final/lib/External/isl/doc/manual.pdf
Binary files differ
diff --git a/final/lib/External/isl/doc/manual.tex b/final/lib/External/isl/doc/manual.tex
new file mode 100644
index 0000000..91b3db0
--- /dev/null
+++ b/final/lib/External/isl/doc/manual.tex
@@ -0,0 +1,75 @@
+\documentclass{report}
+\usepackage[plainpages=false,pdfpagelabels,breaklinks,pagebackref]{hyperref}
+\usepackage{amsmath}
+\usepackage{amssymb}
+\usepackage{txfonts}
+\usepackage{chicago}
+\usepackage{aliascnt}
+\usepackage{tikz}
+\usepackage{calc}
+\usepackage[ruled]{algorithm2e}
+\usetikzlibrary{matrix,fit,backgrounds,decorations.pathmorphing,positioning}
+\usepackage{listings}
+
+\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}
+
+\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}
+
+\bibliography{isl}
+\bibliographystyle{chicago}
+
+\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/user.pod b/final/lib/External/isl/doc/user.pod
new file mode 100644
index 0000000..4492e80
--- /dev/null
+++ b/final/lib/External/isl/doc/user.pod
@@ -0,0 +1,10119 @@
+=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 is 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 * Objects of type C<isl_union_pw_multi_aff> can no longer contain
+two or more C<isl_pw_multi_aff> objects with the same domain space.
+
+=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
+
+=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://freshmeat.net/projects/isl/>.
+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 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);
+
+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);
+
+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,
+		__isl_give 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_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).
+
+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_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);
+	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">).
+
+	__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.
+If, furthermore, the same existentials, i.e., existentials
+with the same explicit representations, should appear in the
+same order in each of the disjuncts of a set or map, then the user should call
+either of the following functions.
+
+	__isl_give isl_set *isl_set_align_divs(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_align_divs(
+		__isl_take isl_map *map);
+
+Alternatively, the existentially quantified variables can be removed
+using the following functions, which compute an overapproximation.
+
+	__isl_give isl_basic_set *isl_basic_set_remove_divs(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_basic_map *isl_basic_map_remove_divs(
+		__isl_take isl_basic_map *bmap);
+	__isl_give isl_set *isl_set_remove_divs(
+		__isl_take isl_set *set);
+	__isl_give isl_map *isl_map_remove_divs(
+		__isl_take isl_map *map);
+
+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);
+
+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
+
+	#include <isl/set.h>
+	__isl_give isl_basic_set_list *isl_set_get_basic_set_list(
+		__isl_keep isl_set *set);
+
+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);
+	void 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);
+
+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) 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);
+
+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_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);
+	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>
+	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_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>.
+
+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 *ma,
+			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_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);
+	__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);
+
+Alternatively, a string representation can be obtained
+directly using the following functions, which always print
+in isl format.
+
+	#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_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_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_multi_aff_to_str(
+		__isl_keep isl_multi_aff *aff);
+	__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);
+
+=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_is_universe(
+		__isl_keep isl_basic_set *bset);
+	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 * 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 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);
+
+	#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);
+
+	#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.
+
+=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
+
+	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.
+
+	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.
+
+=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);
+
+Check whether the given expression is a constant.
+
+	#include <isl/aff.h>
+	isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff);
+	isl_bool isl_pw_aff_involves_nan(
+		__isl_keep isl_pw_aff *pa);
+
+	#include <isl/polynomial.h>
+	isl_bool isl_qpolynomial_fold_is_nan(
+		__isl_keep isl_qpolynomial_fold *fold);
+
+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_multi_aff_plain_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_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1,
+		__isl_keep isl_pw_aff *pa2);
+
+The function C<isl_pw_aff_plain_cmp> can be used to sort
+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_basic_set *isl_basic_set_params(
+		__isl_take isl_basic_set *bset);
+	__isl_give isl_set *isl_set_params(__isl_take isl_set *set);
+
+	#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_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 a set
+
+Create a relation with the given set as domain or range.
+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/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);
+
+=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.
+
+	__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_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_map *isl_map_lower_bound_si(
+		__isl_take isl_map *map,
+		enum isl_dim_type type, unsigned pos, int 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);
+	__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);
+
+	#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_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_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_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);
+
+	#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_map *
+	isl_map_drop_constraints_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);
+
+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_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.
+
+	__isl_give isl_basic_set *isl_basic_set_coefficients(
+		__isl_take isl_basic_set *bset);
+	__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.
+
+=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 Arithmethic Operations
+
+	#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);
+
+	#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);
+
+	#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);
+
+	#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);
+
+=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_le_basic_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_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_ge_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_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 Arithmethic Operations
+
+	#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);
+
+=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_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<1>.  The callbacks C<follows> and C<fn>
+should return C<-1> 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>) 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_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);
+
+They can be modified using the following function.
+
+	#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 store 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);
+	void 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.
+
+=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 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 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);
+
+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);
+
+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 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);
+
+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)">.
+
+	#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 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.
+
+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_after(
+		__isl_take isl_schedule_node *node,
+		__isl_take isl_union_set *filter);
+
+This function splits 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 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);
+
+=head2 Dependence Analysis
+
+C<isl> contains specialized functionality for performing
+array dataflow analysis.  That is, given a I<sink> access relation
+and a collection of possible I<source> access relations,
+C<isl> can compute relations that describe
+for each iteration of the sink access, which iteration
+of which of the source access relations was the last
+to access the same data element before the given iteration
+of the sink access.
+The resulting dependence relations map source iterations
+to the corresponding sink iterations.
+To compute standard flow dependences, the sink should be
+a read, while the sources should be writes.
+If any of the source accesses are marked as being I<may>
+accesses, then there will be a dependence from the last
+I<must> access B<and> from any I<may> access that follows
+this last I<must> access.
+In particular, if I<all> sources are I<may> accesses,
+then memory based dependence analysis is performed.
+If, on the other hand, all sources are I<must> accesses,
+then value based dependence analysis is performed.
+
+=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_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_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_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 user is free not to call one (or both) 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.
+
+The output of C<isl_union_access_info_compute_flow> can be examined
+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_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_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_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>.
+
+=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 sources can be added to the C<isl_access_info> 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 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
+
+B<The functionality described in this section is fairly new
+and may be subject to change.>
+
+	#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_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.
+
+An C<isl_schedule_constraints> object can be inspected
+using the following functions.
+
+	#include <isl/schedule.h>
+	__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_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);
+
+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_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_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_algorithm(
+		isl_ctx *ctx, int val);
+	int isl_options_get_schedule_algorithm(
+		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_maximize_band_depth
+
+If this option is set, we do not split bands at the point
+where we detect splitting is necessary. Instead, we
+backtrack and split bands as early as possible. This
+reduces the number of splits and maximizes the width of
+the bands. Wider bands give more possibilities for tiling.
+Note that if the C<schedule_serialize_sccs> options is set,
+then bands will be split as early as possible, even if there is no need.
+The C<schedule_maximize_band_depth> option therefore has no effect in this case.
+
+=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_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 graphs have a common non-trivial
+divisor.
+The constant term is then placed in a separate band and the linear
+part is reduced.
+
+=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_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);
+
+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_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_node_foreach_ast_op_type> calls C<fn> 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);
+
+More advanced printing can be performed using the following functions.
+
+	#include <isl/ast.h>
+	__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_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>.
+C<isl_ast_op_type_print_macro> prints out the macro
+corresponding to a specific C<isl_ast_op_type>.
+C<isl_ast_node_print_macros> scans the C<isl_ast_node>
+for expressions where these macros would be used and prints
+out the required macro definitions.
+Essentially, C<isl_ast_node_print_macros> calls
+C<isl_ast_node_foreach_ast_op_type> with C<isl_ast_op_type_print_macro>
+as function 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_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 options 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_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.
+The use of the C<isolate> option 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>.
+The 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_codegen>
+
+Given a schedule, 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.
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..30b63e6
--- /dev/null
+++ b/final/lib/External/isl/imath/gmp_compat.c
@@ -0,0 +1,862 @@
+/*
+  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>
+
+#ifdef  NDEBUG
+#define CHECK(res) (res)
+#else
+#define CHECK(res) assert(((res) == MP_OK) && "expected MP_OK")
+#endif
+
+/*************************************************************************
+ *
+ * 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 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 n = 0, d = 0 */
+  int n_is_zero = mp_int_compare_zero(n) == 0;
+  int d_is_zero = mp_int_compare_zero(d) == 0;
+  if (n_is_zero && d_is_zero)
+    return 1;
+
+  /* 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;
+  int num_used_bytes;
+  size_t num_words, num_missing_bytes;
+  unsigned char* dst;
+  unsigned char* src;
+
+  /* We do not have a complete implementation. Assert to ensure our
+   * restrictions are in place, We do not support big endian output, but do not
+   * check that native endian is little endian. */
+  assert(nails  == 0 && "Do not support non-full words");
+  assert((endian == 0 || endian == -1) && "Do not support big endian");
+
+  /* The gmp API requires that order must be -1 or 1.
+     Not sure how gmp behaves when order is not 1 or -1, so force all non-one
+     values to -1 for now. */
+  if (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);
+  }
+
+  /* Initialize dst and src pointers */
+  dst = (unsigned char *)rop;
+  src = (unsigned char *)MP_DIGITS(op);
+
+  /* Most significant word first */
+  if (order == 1) {
+    size_t words_written = 0;
+    src += (num_words-1) * size;
+
+    /* Handle write of first word specially */
+    for (i = 0; i < size - num_missing_bytes; i++)
+      dst[i] = src[i];
+    for (; i < size; i++)
+      dst[i] = 0;
+    dst += size;
+    src -= size;
+    words_written++;
+
+    for (; words_written < num_words; words_written++) {
+      for (i = 0; i < size; i++)
+        dst[i] = src[i];
+      dst += size;
+      src -= size;
+    }
+  }
+  /* Least significant word first */
+  else {
+    size_t words_written = 0;
+    for (; words_written < num_words - 1; words_written++) {
+      for (i = 0; i < size; i++)
+        dst[i] = src[i];
+      dst += size;
+      src += size;
+    }
+
+    /* Handle write of last word specially */
+    for (i = 0; i < size - num_missing_bytes; i++)
+      dst[i] = src[i];
+
+    for (; i < size; i++)
+      dst[i] = 0;
+  }
+
+  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;
+  const char *src;
+  char *dst;
+  int i;
+  if (count == 0 || op == NULL)
+    return;
+
+  /* We do not have a complete implementation. Assert to ensure our
+   * restrictions are in place, We do not support big endian output, but do not
+   * check that native endian is little endian. */
+  assert(nails  == 0 && "Do not support non-full words");
+  assert((endian == 0 || endian == -1) && "Do not support big 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 char *) op;
+  dst = (char *)MP_DIGITS(tmp);
+
+  /* Most significant word is first */
+  if (order == 1) {
+    size_t word;
+    dst += (count - 1) * size;
+    for (word = 0; word < count; word++) {
+      for (i = 0; i < size; i++)
+        dst[i] = src[i];
+      dst -= size;
+      src += size;
+    }
+  }
+  /* Least significant word is first */
+  else {
+    size_t word;
+    for (word = 0; word < count; word++) {
+      for (i = 0; i < size; i++)
+        dst[i] = src[i];
+      dst += size;
+      src += size;
+    }
+  }
+  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..7a767dc
--- /dev/null
+++ b/final/lib/External/isl/imath/imath.c
@@ -0,0 +1,3256 @@
+/*
+  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 = abs(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 = abs(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 = (sz == MP_NEG) ? -(mp_small)uv : (mp_small)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 = (mp_usmall) (v < 0) ? -v : 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 = (1 << 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 < (mp_digit) (1 << (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;
+}
+
+#if 0
+/*
+  The s_udiv function produces incorrect results. For example, with test
+     div:11141460315522012760862883825:48318382095:0,230584300062375935
+   commenting out the function for now and using s_udiv_knuth instead.
+   STATIC mp_result s_udiv(mp_int a, mp_int b);
+*/
+/* Precondition:  a >= b and b > 0
+   Postcondition: a' = a / b, b' = a % b
+ */
+STATIC mp_result s_udiv(mp_int a, mp_int b)
+{
+  mpz_t q, r, t;
+  mp_size ua, ub, qpos = 0;
+  mp_digit *da, btop;
+  mp_result res = MP_OK;
+  int k, skip = 0;
+
+  /* Force signs to positive */
+  MP_SIGN(a) = MP_ZPOS;
+  MP_SIGN(b) = MP_ZPOS;
+
+  /* Normalize, per Knuth */
+  k = s_norm(a, b);
+
+  ua = MP_USED(a); ub = MP_USED(b); btop = b->digits[ub - 1];
+  if ((res = mp_int_init_size(&q, ua)) != MP_OK) return res;
+  if ((res = mp_int_init_size(&t, ua + 1)) != MP_OK) goto CLEANUP;
+
+  da = MP_DIGITS(a);
+  r.digits = da + ua - 1;  /* The contents of r are shared with a */
+  r.used   = 1;
+  r.sign   = MP_ZPOS;
+  r.alloc  = MP_ALLOC(a);
+  ZERO(t.digits, t.alloc);
+
+  /* Solve for quotient digits, store in q.digits in reverse order */
+  while (r.digits >= da) {
+    assert(qpos <= q.alloc);
+
+    if (s_ucmp(b, &r) > 0) {
+      r.digits -= 1;
+      r.used += 1;
+
+      if (++skip > 1 && qpos > 0)
+	q.digits[qpos++] = 0;
+
+      CLAMP(&r);
+    }
+    else {
+      mp_word  pfx = r.digits[r.used - 1];
+      mp_word  qdigit;
+
+      if (r.used > 1 && pfx < btop) {
+	pfx <<= MP_DIGIT_BIT / 2;
+	pfx <<= MP_DIGIT_BIT / 2;
+	pfx |= r.digits[r.used - 2];
+      }
+
+      qdigit = pfx / btop;
+      if (qdigit > MP_DIGIT_MAX) {
+	qdigit = MP_DIGIT_MAX;
+      }
+
+      s_dbmul(MP_DIGITS(b), (mp_digit) qdigit, t.digits, ub);
+      t.used = ub + 1; CLAMP(&t);
+      while (s_ucmp(&t, &r) > 0) {
+	--qdigit;
+	(void) mp_int_sub(&t, b, &t); /* cannot fail */
+      }
+
+      s_usub(r.digits, t.digits, r.digits, r.used, t.used);
+      CLAMP(&r);
+
+      q.digits[qpos++] = (mp_digit) qdigit;
+      ZERO(t.digits, t.used);
+      skip = 0;
+    }
+  }
+
+  /* Put quotient digits in the correct order, and discard extra zeroes */
+  q.used = qpos;
+  REV(mp_digit, q.digits, qpos);
+  CLAMP(&q);
+
+  /* Denormalize the remainder */
+  CLAMP(a);
+  if (k != 0)
+    s_qdiv(a, k);
+
+  mp_int_copy(a, b);  /* ok:  0 <= r < b */
+  mp_int_copy(&q, a); /* ok:  q <= a     */
+
+  mp_int_clear(&t);
+ CLEANUP:
+  mp_int_clear(&q);
+  return res;
+}
+#endif
+
+/* 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..f68e50d
--- /dev/null
+++ b/final/lib/External/isl/imath_wrap/wrap.h
@@ -0,0 +1,172 @@
+#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_q_ui	isl_impz_fdiv_q_ui
+#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..45c274d
--- /dev/null
+++ b/final/lib/External/isl/include/isl/aff.h
@@ -0,0 +1,913 @@
+#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);
+
+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_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff);
+__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff);
+__isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff);
+__isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff,
+	__isl_take isl_val *mod);
+
+__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_aff *isl_aff_add(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+__isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1,
+	__isl_take isl_aff *aff2);
+
+__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_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_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_le_basic_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_aff *isl_aff_read_from_str(isl_ctx *ctx, const char *str);
+__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);
+__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_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);
+int 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_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_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_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_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_add(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_give isl_pw_aff *isl_pw_aff_sub(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2);
+__isl_give isl_pw_aff *isl_pw_aff_neg(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff);
+__isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa,
+	__isl_take isl_val *mod);
+__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);
+
+__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_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_give isl_pw_aff *isl_pw_aff_scale_val(__isl_take isl_pw_aff *pa,
+	__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_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_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);
+
+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_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_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_pw_aff *isl_pw_aff_read_from_str(isl_ctx *ctx, const char *str);
+__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_NEG(aff)
+ISL_DECLARE_MULTI_DIMS(aff)
+ISL_DECLARE_MULTI_WITH_DOMAIN(aff)
+
+__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_product(
+	__isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2);
+
+__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_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_le_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 *aff);
+__isl_give isl_printer *isl_printer_print_multi_aff(__isl_take isl_printer *p,
+	__isl_keep isl_multi_aff *maff);
+
+__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_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma);
+__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_plain_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_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_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_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_flat_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_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_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_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_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 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_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_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_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_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_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_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_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_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_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);
+
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_identity(
+	__isl_take isl_space *space);
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff(
+	__isl_take isl_multi_aff *ma);
+__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_equal(__isl_keep isl_multi_pw_aff *mpa1,
+	__isl_keep isl_multi_pw_aff *mpa2);
+
+__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_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_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_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_give isl_multi_pw_aff *isl_multi_pw_aff_read_from_str(isl_ctx *ctx,
+	const char *str);
+__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_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_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 *ma, 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_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_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_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_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_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);
+
+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_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_pw_aff(
+	__isl_take isl_union_pw_aff *upa);
+__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_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_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);
+
+__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_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_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_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..12daf94
--- /dev/null
+++ b/final/lib/External/isl/include/isl/aff_type.h
@@ -0,0 +1,46 @@
+#ifndef ISL_AFF_TYPE_H
+#define ISL_AFF_TYPE_H
+
+#include <isl/list.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_aff;
+typedef struct isl_aff isl_aff;
+
+ISL_DECLARE_LIST(aff)
+
+struct isl_pw_aff;
+typedef struct isl_pw_aff isl_pw_aff;
+
+ISL_DECLARE_LIST(pw_aff)
+
+struct isl_union_pw_aff;
+typedef struct isl_union_pw_aff isl_union_pw_aff;
+
+ISL_DECLARE_LIST_TYPE(union_pw_aff)
+
+struct isl_multi_aff;
+typedef struct isl_multi_aff isl_multi_aff;
+
+struct isl_pw_multi_aff;
+typedef struct isl_pw_multi_aff isl_pw_multi_aff;
+
+struct 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_multi_pw_aff;
+typedef struct isl_multi_pw_aff isl_multi_pw_aff;
+
+struct 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..e091797
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ast.h
@@ -0,0 +1,173 @@
+#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_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_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 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_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_print_macro(
+	enum isl_ast_op_type type, __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);
+
+#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..0971a04
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ast_build.h
@@ -0,0 +1,116 @@
+#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_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_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_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_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_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);
+
+__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);
+__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..f18149e
--- /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_ast_expr;
+typedef struct isl_ast_expr isl_ast_expr;
+
+struct 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..d3b563a
--- /dev/null
+++ b/final/lib/External/isl/include/isl/constraint.h
@@ -0,0 +1,150 @@
+/*
+ * 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);
+
+int 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 isl_basic_set_has_defining_equality(
+	struct isl_basic_set *bset, enum isl_dim_type type, int pos,
+	struct isl_constraint **constraint);
+int 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);
+struct isl_basic_set *isl_basic_set_from_constraint(
+	struct 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);
+
+__isl_give isl_basic_set *isl_basic_set_drop_constraint(
+	__isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint);
+
+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..6cd26a1
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ctx.h
@@ -0,0 +1,254 @@
+/*
+ * 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_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;
+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..cbab1f9
--- /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);
+int 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..e9f7701
--- /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
+
+int 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);
+int 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..84bb88a
--- /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);
+
+int 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..0b98566
--- /dev/null
+++ b/final/lib/External/isl/include/isl/flow.h
@@ -0,0 +1,120 @@
+#ifndef ISL_FLOW_H
+#define ISL_FLOW_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>
+
+#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_union_access_info;
+typedef struct isl_union_access_info isl_union_access_info;
+struct isl_union_flow;
+typedef struct isl_union_flow isl_union_flow;
+
+__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_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_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_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);
+
+isl_ctx *isl_union_access_info_get_ctx(
+	__isl_keep isl_union_access_info *access);
+
+__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_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_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_null isl_union_flow *isl_union_flow_free(__isl_take 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..eceee48
--- /dev/null
+++ b/final/lib/External/isl/include/isl/hmap.h
@@ -0,0 +1,58 @@
+#include <isl/ctx.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_KEY ISL_CAT(isl_,ISL_KEY_BASE)
+#define ISL_VAL ISL_CAT(isl_,ISL_VAL_BASE)
+#define ISL_xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define ISL_FN(TYPE,NAME) ISL_xFN(TYPE,NAME)
+#define ISL_xHMAP(KEY,VAL_BASE) KEY ## _to_ ## VAL_BASE
+#define ISL_yHMAP(KEY,VAL_BASE) ISL_xHMAP(KEY,VAL_BASE)
+#define ISL_HMAP ISL_yHMAP(ISL_KEY,ISL_VAL_BASE)
+#define ISL_HMAP_BASE ISL_yHMAP(ISL_KEY_BASE,ISL_VAL_BASE)
+
+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_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_BASE)(
+	__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/id.h b/final/lib/External/isl/include/isl/id.h
new file mode 100644
index 0000000..093dd44
--- /dev/null
+++ b/final/lib/External/isl/include/isl/id.h
@@ -0,0 +1,40 @@
+#ifndef ISL_ID_H
+#define ISL_ID_H
+
+#include <isl/ctx.h>
+#include <isl/list.h>
+#include <isl/printer.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,
+	__isl_give void (*free_user)(void *user));
+
+__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..958360c
--- /dev/null
+++ b/final/lib/External/isl/include/isl/id_to_ast_expr.h
@@ -0,0 +1,13 @@
+#ifndef ISL_ID_TO_AST_EXPR_H
+#define ISL_ID_TO_AST_EXPR_H
+
+#include <isl/id.h>
+#include <isl/ast_type.h>
+
+#define ISL_KEY_BASE	id
+#define ISL_VAL_BASE	ast_expr
+#include <isl/hmap.h>
+#undef ISL_KEY_BASE
+#undef ISL_VAL_BASE
+
+#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..e54fefb
--- /dev/null
+++ b/final/lib/External/isl/include/isl/id_to_pw_aff.h
@@ -0,0 +1,13 @@
+#ifndef ISL_ID_TO_PW_AFF_H
+#define ISL_ID_TO_PW_AFF_H
+
+#include <isl/id.h>
+#include <isl/aff_type.h>
+
+#define ISL_KEY_BASE	id
+#define ISL_VAL_BASE	pw_aff
+#include <isl/hmap.h>
+#undef ISL_KEY_BASE
+#undef ISL_VAL_BASE
+
+#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..c177014
--- /dev/null
+++ b/final/lib/External/isl/include/isl/ilp.h
@@ -0,0 +1,33 @@
+/*
+ * 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/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_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);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
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..616d8dc
--- /dev/null
+++ b/final/lib/External/isl/include/isl/list.h
@@ -0,0 +1,76 @@
+/*
+ * 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.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_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..0e7219c
--- /dev/null
+++ b/final/lib/External/isl/include/isl/map.h
@@ -0,0 +1,668 @@
+/*
+ * 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
+
+/* General notes:
+ *
+ * All structures are reference counted to allow reuse without duplication.
+ * A *_copy operation will increase the reference count, while a *_free
+ * operation will decrease the reference count and only actually release
+ * the structures when the reference count drops to zero.
+ *
+ * Functions that return an isa structure will in general _destroy_
+ * all argument isa structures (the obvious execption begin the _copy
+ * functions).  A pointer passed to such a function may therefore
+ * never be used after the function call.  If you want to keep a
+ * reference to the old structure(s), use the appropriate _copy function.
+ */
+
+unsigned isl_basic_map_n_in(const struct isl_basic_map *bmap);
+unsigned isl_basic_map_n_out(const struct isl_basic_map *bmap);
+unsigned isl_basic_map_n_param(const struct isl_basic_map *bmap);
+unsigned isl_basic_map_n_div(const struct isl_basic_map *bmap);
+unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap);
+unsigned isl_basic_map_dim(__isl_keep isl_basic_map *bmap,
+				enum isl_dim_type type);
+
+unsigned isl_map_n_in(const struct isl_map *map);
+unsigned isl_map_n_out(const struct isl_map *map);
+unsigned isl_map_n_param(const struct 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);
+
+int 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_give isl_basic_map *isl_map_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_give isl_basic_map *isl_basic_map_from_basic_set(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim);
+__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 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);
+
+struct isl_basic_map *isl_basic_map_sum(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2);
+struct isl_basic_map *isl_basic_map_neg(struct isl_basic_map *bmap);
+
+struct isl_map *isl_map_sum(struct isl_map *map1, struct isl_map *map2);
+struct isl_map *isl_map_neg(struct 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);
+
+struct isl_basic_map *isl_map_copy_basic_map(struct isl_map *map);
+__isl_give isl_map *isl_map_drop_basic_map(__isl_take isl_map *map,
+						__isl_keep isl_basic_map *bmap);
+
+__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);
+
+int isl_basic_map_image_is_bounded(__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);
+struct isl_map *isl_map_union_disjoint(
+			struct isl_map *map1, struct 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_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_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_give isl_map *isl_map_from_set(__isl_take isl_set *set,
+	__isl_take isl_space *dim);
+__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);
+int isl_map_is_translation(__isl_keep isl_map *map);
+int 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_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_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_map *isl_map_drop_constraints_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_set_lifting(__isl_take isl_set *set);
+
+__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_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..7df8ee3
--- /dev/null
+++ b/final/lib/External/isl/include/isl/map_to_basic_set.h
@@ -0,0 +1,13 @@
+#ifndef ISL_MAP_TO_BASIC_SET_H
+#define ISL_MAP_TO_BASIC_SET_H
+
+#include <isl/set_type.h>
+#include <isl/map_type.h>
+
+#define ISL_KEY_BASE	map
+#define ISL_VAL_BASE	basic_set
+#include <isl/hmap.h>
+#undef ISL_KEY_BASE
+#undef ISL_VAL_BASE
+
+#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..7a43ccb
--- /dev/null
+++ b/final/lib/External/isl/include/isl/mat.h
@@ -0,0 +1,111 @@
+/*
+ * 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);
+struct isl_mat *isl_mat_dup(struct 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);
+struct isl_mat *isl_mat_cow(struct 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);
+
+struct isl_mat *isl_mat_swap_cols(struct isl_mat *mat, unsigned i, unsigned j);
+struct isl_mat *isl_mat_swap_rows(struct isl_mat *mat, unsigned i, unsigned j);
+
+struct isl_vec *isl_mat_vec_product(struct isl_mat *mat, struct isl_vec *vec);
+struct isl_vec *isl_vec_mat_product(struct isl_vec *vec, struct isl_mat *mat);
+__isl_give isl_vec *isl_mat_vec_inverse_product(__isl_take isl_mat *mat,
+						__isl_take isl_vec *vec);
+struct isl_mat *isl_mat_aff_direct_sum(struct isl_mat *left,
+					struct isl_mat *right);
+__isl_give isl_mat *isl_mat_diagonal(__isl_take isl_mat *mat1,
+	__isl_take isl_mat *mat2);
+struct isl_mat *isl_mat_left_hermite(struct isl_mat *M,
+	int neg, struct isl_mat **U, struct isl_mat **Q);
+struct isl_mat *isl_mat_lin_to_aff(struct isl_mat *mat);
+struct isl_mat *isl_mat_inverse_product(struct isl_mat *left,
+	struct isl_mat *right);
+__isl_give isl_mat *isl_mat_product(__isl_take isl_mat *left,
+	__isl_take isl_mat *right);
+struct isl_mat *isl_mat_transpose(struct 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);
+
+struct isl_mat *isl_mat_drop_cols(struct isl_mat *mat,
+				unsigned col, unsigned n);
+struct isl_mat *isl_mat_drop_rows(struct 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);
+
+struct isl_mat *isl_mat_unimodular_complete(struct 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);
+
+int 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/multi.h b/final/lib/External/isl/include/isl/multi.h
new file mode 100644
index 0000000..8d598f7
--- /dev/null
+++ b/final/lib/External/isl/include/isl/multi.h
@@ -0,0 +1,142 @@
+#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);				\
+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_give isl_multi_##BASE *isl_multi_##BASE##_flat_range_product(	\
+	__isl_take isl_multi_##BASE *multi1,				\
+	__isl_take isl_multi_##BASE *multi2);				\
+__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_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_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_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..930e1c4
--- /dev/null
+++ b/final/lib/External/isl/include/isl/options.h
@@ -0,0 +1,50 @@
+/*
+ * 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_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..ae295d3
--- /dev/null
+++ b/final/lib/External/isl/include/isl/point.h
@@ -0,0 +1,43 @@
+#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_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);
+void 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);
+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..23fb239
--- /dev/null
+++ b/final/lib/External/isl/include/isl/polynomial.h
@@ -0,0 +1,669 @@
+#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);
+
+int isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp,
+	__isl_keep isl_basic_set *bset,
+	int (*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_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);
+int 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_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_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_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);
+
+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 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_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_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);
+int 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_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);
+
+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_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 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_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_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_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..f5b2f43
--- /dev/null
+++ b/final/lib/External/isl/include/isl/printer.h
@@ -0,0 +1,78 @@
+#ifndef ISL_PRINTER_H
+#define ISL_PRINTER_H
+
+#include <stdio.h>
+#include <isl/ctx.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct isl_printer;
+typedef struct isl_printer isl_printer;
+
+__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_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/schedule.h b/final/lib/External/isl/include/isl/schedule.h
new file mode 100644
index 0000000..7a03789
--- /dev/null
+++ b/final/lib/External/isl/include/isl/schedule.h
@@ -0,0 +1,150 @@
+#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_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_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_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_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_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_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_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);
+
+void isl_schedule_constraints_dump(__isl_keep isl_schedule_constraints *sc);
+
+__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_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_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_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_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_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_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);
+
+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..d0dbba9
--- /dev/null
+++ b/final/lib/External/isl/include/isl/schedule_node.h
@@ -0,0 +1,223 @@
+#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_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_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_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_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);
+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);
+
+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_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);
+__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_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);
+
+#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..b1e63d6
--- /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_schedule_node;
+typedef struct isl_schedule_node isl_schedule_node;
+
+struct 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..7307722
--- /dev/null
+++ b/final/lib/External/isl/include/isl/set.h
@@ -0,0 +1,498 @@
+/*
+ * 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(const struct 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_basic_set *isl_basic_set_list_product(
+	__isl_take struct isl_basic_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_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);
+
+__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);
+
+int 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_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);
+int 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_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_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_give isl_basic_set *isl_set_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);
+struct isl_basic_set *isl_set_bounded_simple_hull(struct isl_set *set);
+__isl_give isl_set *isl_set_recession_cone(__isl_take isl_set *set);
+
+struct isl_set *isl_set_union_disjoint(
+			struct isl_set *set1, struct 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_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);
+struct isl_set *isl_set_eliminate_dims(struct 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_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);
+int 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);
+int isl_set_is_box(__isl_keep isl_set *set);
+int 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);
+struct isl_set *isl_basic_set_compute_divs(struct isl_basic_set *bset);
+__isl_give isl_set *isl_set_compute_divs(__isl_take isl_set *set);
+__isl_give isl_set *isl_set_align_divs(__isl_take isl_set *set);
+
+struct isl_basic_set *isl_set_copy_basic_set(struct isl_set *set);
+struct isl_set *isl_set_drop_basic_set(struct isl_set *set,
+						struct isl_basic_set *bset);
+
+__isl_give isl_val *isl_set_plain_get_val_if_fixed(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos);
+int 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_dim_is_unique(struct isl_set *set, unsigned dim);
+
+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_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_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 *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_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..fdcbff1
--- /dev/null
+++ b/final/lib/External/isl/include/isl/space.h
@@ -0,0 +1,174 @@
+/*
+ * 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);
+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_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 *dim, enum isl_dim_type type,
+		unsigned n);
+__isl_give isl_space *isl_space_move_dims(__isl_take isl_space *dim,
+	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 *dim);
+__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_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim,
+		unsigned first, unsigned n);
+__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 *dim);
+__isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim);
+__isl_give isl_space *isl_space_range(__isl_take isl_space *dim);
+__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_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 *dim);
+__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_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_tuple_is_equal(__isl_keep isl_space *space1,
+	enum isl_dim_type type1, __isl_keep isl_space *space2,
+	enum isl_dim_type type2);
+int isl_space_match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
+	__isl_keep isl_space *dim2, enum isl_dim_type dim2_type);
+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);
+int isl_space_compatible(__isl_keep isl_space *dim1,
+	__isl_keep isl_space *dim2);
+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..603ae25
--- /dev/null
+++ b/final/lib/External/isl/include/isl/stream.h
@@ -0,0 +1,96 @@
+/*
+ * 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_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..2dac338
--- /dev/null
+++ b/final/lib/External/isl/include/isl/union_map.h
@@ -0,0 +1,268 @@
+#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_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);
+__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);
+__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_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_give isl_union_map *isl_union_map_product(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2);
+__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_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_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_range(
+	__isl_take isl_union_map *umap);
+__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_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_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_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_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_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);
+
+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_give int isl_union_map_contains(__isl_keep isl_union_map *umap,
+	__isl_keep isl_space *dim);
+__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_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_give isl_union_set *isl_union_map_wrap(__isl_take isl_union_map *umap);
+__isl_give isl_union_map *isl_union_set_unwrap(__isl_take isl_union_set *uset);
+
+__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_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..3d818fe
--- /dev/null
+++ b/final/lib/External/isl/include/isl/union_set.h
@@ -0,0 +1,158 @@
+#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_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_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_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);
+
+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 int isl_union_set_contains(__isl_keep isl_union_set *uset,
+	__isl_keep isl_space *dim);
+__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_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_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..167244f
--- /dev/null
+++ b/final/lib/External/isl/include/isl/val.h
@@ -0,0 +1,121 @@
+#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_val;
+typedef struct isl_val isl_val;
+
+ISL_DECLARE_LIST(val)
+
+struct 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_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);
+__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);
+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_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_inv(__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_2exp(__isl_take isl_val *v);
+__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_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);
+
+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);
+
+int isl_val_cmp_si(__isl_keep isl_val *v, long i);
+
+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);
+
+isl_bool isl_val_is_divisible_by(__isl_keep isl_val *v1,
+	__isl_keep isl_val *v2);
+
+__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..e73278c
--- /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);
+
+struct isl_vec *isl_vec_ceil(struct 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..a10b4f3
--- /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);
+void 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..377bb86
--- /dev/null
+++ b/final/lib/External/isl/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-11-20.07; # 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-writable 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/isl/interface/all.h b/final/lib/External/isl/interface/all.h
new file mode 100644
index 0000000..46634e2
--- /dev/null
+++ b/final/lib/External/isl/interface/all.h
@@ -0,0 +1,4 @@
+#include <isl/set.h>
+#include <isl/map.h>
+#include <isl/union_set.h>
+#include <isl/union_map.h>
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..6d4ae49
--- /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 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..d1d293f
--- /dev/null
+++ b/final/lib/External/isl/isl_aff.c
@@ -0,0 +1,8684 @@
+/*
+ * 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;
+}
+
+/* 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 reodering.
+ * 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);
+	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)
+{
+	if (!aff || !model)
+		goto error;
+
+	if (!isl_space_match(aff->ls->dim, isl_dim_param,
+			     model, isl_dim_param)) {
+		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;
+}
+
+/* Does "pa" involve any NaNs?
+ */
+isl_bool isl_pw_aff_involves_nan(__isl_keep isl_pw_aff *pa)
+{
+	int i;
+
+	if (!pa)
+		return isl_bool_error;
+	if (pa->n == 0)
+		return isl_bool_false;
+
+	for (i = 0; i < pa->n; ++i) {
+		isl_bool is_nan = isl_aff_is_nan(pa->p[i].aff);
+		if (is_nan < 0 || is_nan)
+			return is_nan;
+	}
+
+	return isl_bool_false;
+}
+
+/* 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.
+ */
+int isl_aff_get_denominator(__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 denominator of NaN", return -1);
+	isl_int_set(*v, aff->v->el[0]);
+	return 0;
+}
+
+/* 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;
+}
+
+/* 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]);
+}
+
+/* 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.
+ *
+ * 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 i, j;
+	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);
+	if (new_n_div < old_n_div)
+		isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+			"not an expansion", goto error);
+
+	aff->v = isl_vec_extend(aff->v, aff->v->size + new_n_div - old_n_div);
+	if (!aff->v)
+		goto error;
+
+	offset = 1 + isl_local_space_offset(aff->ls, isl_dim_div);
+	j = old_n_div - 1;
+	for (i = new_n_div - 1; i >= 0; --i) {
+		if (j >= 0 && exp[j] == i) {
+			if (i != j)
+				isl_int_swap(aff->v->el[offset + i],
+					     aff->v->el[offset + j]);
+			j--;
+		} else
+			isl_int_set_si(aff->v->el[offset + i], 0);
+	}
+
+	aff->ls = isl_local_space_replace_divs(aff->ls, isl_mat_copy(div));
+	if (!aff->ls)
+		goto error;
+	isl_mat_free(div);
+	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 negative.
+ */
+__isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff)
+{
+	aff = isl_aff_neg(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 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 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);
+}
+
+__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);
+}
+
+#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>
+
+#undef UNION
+#define UNION isl_union_pw_aff
+#undef PART
+#define PART isl_pw_aff
+#undef PARTS
+#define PARTS pw_aff
+
+#define NO_EVAL
+
+#include <isl_union_templ.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))
+{
+	if (!pwaff1 || !pwaff2)
+		goto error;
+	if (isl_space_match(pwaff1->dim, isl_dim_param,
+			  pwaff2->dim, isl_dim_param))
+		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))
+{
+	if (!pa1 || !pa2)
+		goto error;
+	if (isl_space_match(pa1->dim, isl_dim_param, pa2->dim, isl_dim_param))
+		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 better (according to cmp)
+ * 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_opt(__isl_take isl_pw_aff *pwaff1,
+	__isl_take isl_pw_aff *pwaff2,
+	__isl_give isl_basic_set *(*cmp)(__isl_take isl_aff *aff1,
+					__isl_take isl_aff *aff2))
+{
+	int i, j, n;
+	isl_pw_aff *res;
+	isl_ctx *ctx;
+	isl_set *set;
+
+	if (!pwaff1 || !pwaff2)
+		goto error;
+
+	ctx = isl_space_get_ctx(pwaff1->dim);
+	if (!isl_space_is_equal(pwaff1->dim, pwaff2->dim))
+		isl_die(ctx, isl_error_invalid,
+			"arguments should live in same space", goto error);
+
+	if (isl_pw_aff_is_empty(pwaff1)) {
+		isl_pw_aff_free(pwaff1);
+		return pwaff2;
+	}
+
+	if (isl_pw_aff_is_empty(pwaff2)) {
+		isl_pw_aff_free(pwaff2);
+		return pwaff1;
+	}
+
+	n = 2 * (pwaff1->n + 1) * (pwaff2->n + 1);
+	res = isl_pw_aff_alloc_size(isl_space_copy(pwaff1->dim), n);
+
+	for (i = 0; i < pwaff1->n; ++i) {
+		set = isl_set_copy(pwaff1->p[i].set);
+		for (j = 0; j < pwaff2->n; ++j) {
+			struct isl_set *common;
+			isl_set *better;
+
+			common = isl_set_intersect(
+					isl_set_copy(pwaff1->p[i].set),
+					isl_set_copy(pwaff2->p[j].set));
+			better = isl_set_from_basic_set(cmp(
+					isl_aff_copy(pwaff2->p[j].aff),
+					isl_aff_copy(pwaff1->p[i].aff)));
+			better = isl_set_intersect(common, better);
+			if (isl_set_plain_is_empty(better)) {
+				isl_set_free(better);
+				continue;
+			}
+			set = isl_set_subtract(set, isl_set_copy(better));
+
+			res = isl_pw_aff_add_piece(res, better,
+						isl_aff_copy(pwaff2->p[j].aff));
+		}
+		res = isl_pw_aff_add_piece(res, set,
+						isl_aff_copy(pwaff1->p[i].aff));
+	}
+
+	for (j = 0; j < pwaff2->n; ++j) {
+		set = isl_set_copy(pwaff2->p[j].set);
+		for (i = 0; i < pwaff1->n; ++i)
+			set = isl_set_subtract(set,
+					isl_set_copy(pwaff1->p[i].set));
+		res = isl_pw_aff_add_piece(res, set,
+						isl_aff_copy(pwaff2->p[j].aff));
+	}
+
+	isl_pw_aff_free(pwaff1);
+	isl_pw_aff_free(pwaff2);
+
+	return res;
+error:
+	isl_pw_aff_free(pwaff1);
+	isl_pw_aff_free(pwaff2);
+	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 pw_aff_union_opt(pwaff1, pwaff2, &isl_aff_ge_basic_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 pw_aff_union_opt(pwaff1, pwaff2, &isl_aff_le_basic_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;
+		int 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.
+ */
+__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;
+
+	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);
+	}
+
+	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;
+}
+
+/* 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;
+}
+
+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);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_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_min);
+}
+
+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);
+}
+
+__isl_give isl_pw_aff *isl_pw_aff_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_max);
+}
+
+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"?
+ */
+int isl_aff_matching_params(__isl_keep isl_aff *aff,
+	__isl_keep isl_space *space)
+{
+	isl_space *aff_space;
+	int match;
+
+	if (!aff || !space)
+		return -1;
+
+	aff_space = isl_aff_get_domain_space(aff);
+
+	match = isl_space_match(space, isl_dim_param, aff_space, isl_dim_param);
+
+	isl_space_free(aff_space);
+	return match;
+}
+
+/* Check that the domain space of "aff" matches "space".
+ *
+ * Return 0 on success and -1 on error.
+ */
+int isl_aff_check_match_domain_space(__isl_keep isl_aff *aff,
+	__isl_keep isl_space *space)
+{
+	isl_space *aff_space;
+	int match;
+
+	if (!aff || !space)
+		return -1;
+
+	aff_space = isl_aff_get_domain_space(aff);
+
+	match = isl_space_match(space, isl_dim_param, aff_space, isl_dim_param);
+	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 0;
+error:
+	isl_space_free(aff_space);
+	return -1;
+}
+
+#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_floor.c>
+#include <isl_multi_gist.c>
+
+#undef NO_DOMAIN
+
+/* 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
+ * 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)
+{
+	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 = isl_map_lex_ge(space);
+	map = isl_map_intersect_range(map, isl_map_wrap(ge));
+
+	return isl_map_domain(map);
+}
+
+#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>
+
+#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
+
+#define NO_EVAL
+
+#include <isl_union_templ.c>
+
+/* Given a function "cmp" that returns the set of elements where
+ * "ma1" is "better" than "ma2", return the intersection of this
+ * set with "dom1" and "dom2".
+ */
+static __isl_give isl_set *shared_and_better(__isl_keep isl_set *dom1,
+	__isl_keep isl_set *dom2, __isl_keep isl_multi_aff *ma1,
+	__isl_keep isl_multi_aff *ma2,
+	__isl_give isl_set *(*cmp)(__isl_take isl_multi_aff *ma1,
+				    __isl_take isl_multi_aff *ma2))
+{
+	isl_set *common;
+	isl_set *better;
+	int is_empty;
+
+	common = isl_set_intersect(isl_set_copy(dom1), isl_set_copy(dom2));
+	is_empty = isl_set_plain_is_empty(common);
+	if (is_empty >= 0 && is_empty)
+		return common;
+	if (is_empty < 0)
+		return isl_set_free(common);
+	better = cmp(isl_multi_aff_copy(ma1), isl_multi_aff_copy(ma2));
+	better = isl_set_intersect(common, better);
+
+	return better;
+}
+
+/* Given a function "cmp" that returns the set of elements where
+ * "ma1" is "better" than "ma2", return a piecewise multi affine
+ * expression defined on the union of the definition domains
+ * of "pma1" and "pma2" that maps to the "best" of "pma1" and
+ * "pma2" on each cell.  If only one of the two input functions
+ * is defined on a given cell, then it is considered the best.
+ */
+static __isl_give isl_pw_multi_aff *pw_multi_aff_union_opt(
+	__isl_take isl_pw_multi_aff *pma1,
+	__isl_take isl_pw_multi_aff *pma2,
+	__isl_give isl_set *(*cmp)(__isl_take isl_multi_aff *ma1,
+				    __isl_take isl_multi_aff *ma2))
+{
+	int i, j, n;
+	isl_pw_multi_aff *res = NULL;
+	isl_ctx *ctx;
+	isl_set *set = NULL;
+
+	if (!pma1 || !pma2)
+		goto error;
+
+	ctx = isl_space_get_ctx(pma1->dim);
+	if (!isl_space_is_equal(pma1->dim, pma2->dim))
+		isl_die(ctx, isl_error_invalid,
+			"arguments should live in the same space", goto error);
+
+	if (isl_pw_multi_aff_is_empty(pma1)) {
+		isl_pw_multi_aff_free(pma1);
+		return pma2;
+	}
+
+	if (isl_pw_multi_aff_is_empty(pma2)) {
+		isl_pw_multi_aff_free(pma2);
+		return pma1;
+	}
+
+	n = 2 * (pma1->n + 1) * (pma2->n + 1);
+	res = isl_pw_multi_aff_alloc_size(isl_space_copy(pma1->dim), n);
+
+	for (i = 0; i < pma1->n; ++i) {
+		set = isl_set_copy(pma1->p[i].set);
+		for (j = 0; j < pma2->n; ++j) {
+			isl_set *better;
+			int is_empty;
+
+			better = shared_and_better(pma2->p[j].set,
+					pma1->p[i].set, pma2->p[j].maff,
+					pma1->p[i].maff, cmp);
+			is_empty = isl_set_plain_is_empty(better);
+			if (is_empty < 0 || is_empty) {
+				isl_set_free(better);
+				if (is_empty < 0)
+					goto error;
+				continue;
+			}
+			set = isl_set_subtract(set, isl_set_copy(better));
+
+			res = isl_pw_multi_aff_add_piece(res, better,
+					isl_multi_aff_copy(pma2->p[j].maff));
+		}
+		res = isl_pw_multi_aff_add_piece(res, set,
+					isl_multi_aff_copy(pma1->p[i].maff));
+	}
+
+	for (j = 0; j < pma2->n; ++j) {
+		set = isl_set_copy(pma2->p[j].set);
+		for (i = 0; i < pma1->n; ++i)
+			set = isl_set_subtract(set,
+					isl_set_copy(pma1->p[i].set));
+		res = isl_pw_multi_aff_add_piece(res, set,
+					isl_multi_aff_copy(pma2->p[j].maff));
+	}
+
+	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);
+	isl_set_free(set);
+	return isl_pw_multi_aff_free(res);
+}
+
+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 pw_multi_aff_union_opt(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 pw_multi_aff_union_opt(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.
+ */
+__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_multi_aff *maff;
+		isl_basic_map *bmap;
+		isl_map *map_i;
+
+		maff = isl_multi_aff_copy(pma->p[i].maff);
+		bmap = isl_basic_map_from_multi_aff(maff);
+		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;
+}
+
+/* Given a basic map with a single output dimension that is defined
+ * in terms of the parameters and input dimensions using an equality,
+ * extract an isl_aff that expresses the output dimension in terms
+ * of the parameters and input dimensions.
+ * Note that this expression may involve integer divisions defined
+ * in terms of parameters and input 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_take isl_basic_map *bmap)
+{
+	int eq;
+	unsigned offset;
+	unsigned n_div;
+	isl_local_space *ls;
+	isl_aff *aff;
+
+	if (!bmap)
+		return NULL;
+	if (isl_basic_map_dim(bmap, isl_dim_out) != 1)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"basic map should have a single output dimension",
+			goto error);
+	eq = isl_basic_map_output_defining_equality(bmap, 0);
+	if (eq >= bmap->n_eq)
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"unable to find suitable equality", goto error);
+	ls = isl_basic_map_get_local_space(bmap);
+	aff = isl_aff_alloc(isl_local_space_domain(ls));
+	if (!aff)
+		goto error;
+	offset = isl_basic_map_offset(bmap, isl_dim_out);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	if (isl_int_is_neg(bmap->eq[eq][offset])) {
+		isl_seq_cpy(aff->v->el + 1, bmap->eq[eq], offset);
+		isl_seq_cpy(aff->v->el + 1 + offset, bmap->eq[eq] + offset + 1,
+			    n_div);
+	} else {
+		isl_seq_neg(aff->v->el + 1, bmap->eq[eq], offset);
+		isl_seq_neg(aff->v->el + 1 + offset, bmap->eq[eq] + offset + 1,
+			    n_div);
+	}
+	isl_int_abs(aff->v->el[0], bmap->eq[eq][offset]);
+	isl_basic_map_free(bmap);
+
+	aff = isl_aff_remove_unused_divs(aff);
+	return aff;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* 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_basic_map *bmap_i;
+		isl_aff *aff;
+
+		bmap_i = isl_basic_map_copy(bmap);
+		bmap_i = isl_basic_map_project_out(bmap_i, isl_dim_out,
+							i + 1, n_out - (1 + i));
+		bmap_i = isl_basic_map_project_out(bmap_i, isl_dim_out, 0, i);
+		aff = extract_isl_aff_from_basic_map(bmap_i);
+		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.
+ */
+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;
+
+	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;
+	int is_set;
+
+	is_set = isl_map_is_set(map);
+
+	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;
+}
+
+/* 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 fro "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;
+	int is_set;
+
+	is_set = isl_map_is_set(map);
+
+	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;
+}
+
+/* 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, we check if any of the output dimensions is "strided".
+ * That is, we check if can be written as
+ *
+ *	x = m a + f(..)
+ *
+ * with m greater than 1, a some combination of existentiall quantified
+ * variables and f and 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.
+ */
+__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map)
+{
+	int i, j;
+	int sv;
+	isl_basic_map *hull;
+	unsigned n_out;
+	unsigned o_out;
+	unsigned n_div;
+	unsigned o_div;
+	isl_int gcd;
+
+	if (!map)
+		return NULL;
+
+	hull = isl_map_affine_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)
+		hull = isl_basic_map_free(hull);
+	if (!hull)
+		goto error;
+
+	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);
+error:
+	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".
+ */
+__isl_give isl_aff *isl_aff_align_divs(__isl_take isl_aff *dst,
+	__isl_keep isl_aff *src)
+{
+	isl_ctx *ctx;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_mat *div;
+
+	if (!src || !dst)
+		return isl_aff_free(dst);
+
+	ctx = isl_aff_get_ctx(src);
+	if (!isl_space_is_equal(src->ls->dim, dst->ls->dim))
+		isl_die(ctx, isl_error_invalid,
+			"spaces don't match", goto error);
+
+	if (src->ls->div->n_row == 0)
+		return dst;
+
+	exp1 = isl_alloc_array(ctx, int, src->ls->div->n_row);
+	exp2 = isl_alloc_array(ctx, int, dst->ls->div->n_row);
+	if (!exp1 || (dst->ls->div->n_row && !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)(void **entry, 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(void **entry, void *user)
+{
+	struct isl_union_pw_multi_aff_bin_data *data = user;
+	isl_pw_multi_aff *pma = *entry;
+
+	data->pma = pma;
+	if (isl_hash_table_foreach(data->upma2->space->ctx, &data->upma2->table,
+				   data->fn, data) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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)(void **entry, 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(isl_space_copy(upma1->space),
+				       upma1->table.n);
+	if (isl_hash_table_foreach(upma1->space->ctx, &upma1->table,
+				   &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 *entry have the same domain space, then compute
+ * their flat range product and the result to data->res.
+ */
+static isl_stat flat_range_product_entry(void **entry, void *user)
+{
+	struct isl_union_pw_multi_aff_bin_data *data = user;
+	isl_pw_multi_aff *pma2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in,
+				 pma2->dim, isl_dim_in))
+		return isl_stat_ok;
+
+	pma2 = isl_pw_multi_aff_flat_range_product(
+					isl_pw_multi_aff_copy(data->pma),
+					isl_pw_multi_aff_copy(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)
+{
+	if (!pma || !pa)
+		goto error;
+	if (isl_space_match(pma->dim, isl_dim_param, pa->dim, isl_dim_param))
+		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"?
+ */
+int isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space)
+{
+	isl_space *pa_space;
+	int match;
+
+	if (!pa || !space)
+		return -1;
+
+	pa_space = isl_pw_aff_get_space(pa);
+
+	match = isl_space_match(space, isl_dim_param, pa_space, isl_dim_param);
+
+	isl_space_free(pa_space);
+	return match;
+}
+
+/* Check that the domain space of "pa" matches "space".
+ *
+ * Return 0 on success and -1 on error.
+ */
+int isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space)
+{
+	isl_space *pa_space;
+	int match;
+
+	if (!pa || !space)
+		return -1;
+
+	pa_space = isl_pw_aff_get_space(pa);
+
+	match = isl_space_match(space, isl_dim_param, pa_space, isl_dim_param);
+	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 0;
+error:
+	isl_space_free(pa_space);
+	return -1;
+}
+
+#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_gist.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;
+
+	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);
+	if (!isl_space_match(pma->dim, isl_dim_param,
+					mv->space, isl_dim_param)) {
+		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;
+}
+
+/* Internal data structure for isl_union_pw_multi_aff_scale_multi_val.
+ * mv contains the mv argument.
+ * res collects the results.
+ */
+struct isl_union_pw_multi_aff_scale_multi_val_data {
+	isl_multi_val *mv;
+	isl_union_pw_multi_aff *res;
+};
+
+/* 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 add the result
+ * to data->res.
+ */
+static isl_stat union_pw_multi_aff_scale_multi_val_entry(void **entry,
+	void *user)
+{
+	struct isl_union_pw_multi_aff_scale_multi_val_data *data = user;
+	isl_pw_multi_aff *pma = *entry;
+
+	if (!pma)
+		return isl_stat_error;
+	if (!isl_space_tuple_is_equal(pma->dim, isl_dim_out,
+				    data->mv->space, isl_dim_set))
+		return isl_stat_ok;
+
+	pma = isl_pw_multi_aff_copy(pma);
+	pma = isl_pw_multi_aff_scale_multi_val(pma,
+						isl_multi_val_copy(data->mv));
+	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;
+}
+
+/* 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)
+{
+	struct isl_union_pw_multi_aff_scale_multi_val_data data;
+
+	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;
+
+	data.mv = mv;
+	data.res = isl_union_pw_multi_aff_alloc(isl_space_copy(upma->space),
+						upma->table.n);
+	if (isl_hash_table_foreach(upma->space->ctx, &upma->table,
+		       &union_pw_multi_aff_scale_multi_val_entry, &data) < 0)
+		goto error;
+
+	isl_multi_val_free(mv);
+	isl_union_pw_multi_aff_free(upma);
+	return data.res;
+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.
+ */
+int isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1, __isl_keep isl_pw_aff *pa2)
+{
+	int equal;
+	isl_map *map1, *map2;
+
+	if (!pa1 || !pa2)
+		return -1;
+
+	equal = isl_pw_aff_plain_is_equal(pa1, pa2);
+	if (equal < 0 || equal)
+		return equal;
+
+	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;
+
+	if (!mpa1 || !mpa2)
+		return isl_bool_error;
+
+	if (!isl_space_match(mpa1->space, isl_dim_param,
+			     mpa2->space, isl_dim_param)) {
+		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;
+}
+
+/* Coalesce the elements of "mpa".
+ *
+ * Note that such coalescing does not change the meaning of "mpa"
+ * so there is no need to cow.  We do need to be careful not to
+ * destroy any other copies of "mpa" in case of failure.
+ */
+__isl_give isl_multi_pw_aff *isl_multi_pw_aff_coalesce(
+	__isl_take isl_multi_pw_aff *mpa)
+{
+	int i;
+
+	if (!mpa)
+		return NULL;
+
+	for (i = 0; i < mpa->n; ++i) {
+		isl_pw_aff *pa = isl_pw_aff_copy(mpa->p[i]);
+		pa = isl_pw_aff_coalesce(pa);
+		if (!pa)
+			return isl_multi_pw_aff_free(mpa);
+		isl_pw_aff_free(mpa->p[i]);
+		mpa->p[i] = pa;
+	}
+
+	return mpa;
+}
+
+/* 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)
+{
+	if (!mpa || !ma)
+		goto error;
+	if (isl_space_match(mpa->space, isl_dim_param,
+			    ma->space, isl_dim_param))
+		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)
+{
+	if (!mpa || !pma)
+		goto error;
+	if (isl_space_match(mpa->space, isl_dim_param, pma->dim, isl_dim_param))
+		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)
+{
+	if (!aff || !mpa)
+		goto error;
+	if (isl_space_match(aff->ls->dim, isl_dim_param,
+				mpa->space, isl_dim_param))
+		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)
+{
+	if (!pa || !mpa)
+		goto error;
+	if (isl_space_match(pa->dim, isl_dim_param, mpa->space, isl_dim_param))
+		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_take isl_multi_pw_aff *mpa1, __isl_take 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_take isl_multi_pw_aff *mpa1, __isl_take 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_take isl_multi_pw_aff *mpa1, __isl_take 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(void **entry, void *user)
+{
+	struct isl_union_pw_multi_aff_bin_data *data = user;
+	isl_pw_multi_aff *pma2 = *entry;
+
+	if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in,
+				 pma2->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	pma2 = isl_pw_multi_aff_pullback_pw_multi_aff(
+					isl_pw_multi_aff_copy(data->pma),
+					isl_pw_multi_aff_copy(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".
+ *
+ * Return 0 on success and -1 on error.
+ *
+ * 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 int isl_union_pw_aff_check_match_domain_space(
+	__isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space)
+{
+	isl_space *upa_space;
+	int match;
+
+	if (!upa || !space)
+		return -1;
+
+	match = isl_space_is_set(space);
+	if (match < 0)
+		return -1;
+	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_match(space, isl_dim_param, upa_space, isl_dim_param);
+	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 0;
+error:
+	isl_space_free(upa_space);
+	return -1;
+}
+
+/* Do the parameters of "upa" match those of "space"?
+ */
+static int isl_union_pw_aff_matching_params(__isl_keep isl_union_pw_aff *upa,
+	__isl_keep isl_space *space)
+{
+	isl_space *upa_space;
+	int match;
+
+	if (!upa || !space)
+		return -1;
+
+	upa_space = isl_union_pw_aff_get_space(upa);
+
+	match = isl_space_match(space, isl_dim_param, upa_space, isl_dim_param);
+
+	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 };
+	int 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;
+}
+
+/* Replace the entry of isl_union_pw_aff to which "entry" points
+ * by its floor.
+ */
+static isl_stat floor_entry(void **entry, void *user)
+{
+	isl_pw_aff **pa = (isl_pw_aff **) entry;
+
+	*pa = isl_pw_aff_floor(*pa);
+	if (!*pa)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* Given f, return floor(f).
+ */
+__isl_give isl_union_pw_aff *isl_union_pw_aff_floor(
+	__isl_take isl_union_pw_aff *upa)
+{
+	isl_ctx *ctx;
+
+	upa = isl_union_pw_aff_cow(upa);
+	if (!upa)
+		return NULL;
+
+	ctx = isl_union_pw_aff_get_ctx(upa);
+	if (isl_hash_table_foreach(ctx, &upa->table, &floor_entry, NULL) < 0)
+		upa = isl_union_pw_aff_free(upa);
+
+	return upa;
+}
+
+/* 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(void **entry, void *user)
+{
+	struct isl_union_pw_aff_pullback_upma_data *data = user;
+	isl_pw_multi_aff *pma = *entry;
+	isl_pw_aff *pa;
+
+	if (!isl_space_tuple_is_equal(data->pa->dim, isl_dim_in,
+				 pma->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	pma = isl_pw_multi_aff_copy(pma);
+	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(void **entry, void *user)
+{
+	struct isl_union_pw_aff_pullback_upma_data *data = user;
+	isl_ctx *ctx;
+	isl_pw_aff *pa = *entry;
+
+	data->pa = pa;
+	ctx = isl_union_pw_multi_aff_get_ctx(data->upma);
+	if (isl_hash_table_foreach(ctx, &data->upma->table,
+				   &pa_pb_pma, data) < 0)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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_ctx *ctx;
+	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;
+
+	ctx = isl_union_pw_aff_get_ctx(upa);
+	data.upma = upma;
+	space = isl_union_pw_aff_get_space(upa);
+	data.res = isl_union_pw_aff_alloc(space, upa->table.n);
+	if (isl_hash_table_foreach(ctx, &upa->table, &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_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)
+{
+	if (!domain || !mv)
+		goto error;
+	if (isl_space_match(domain->dim, isl_dim_param,
+			    mv->space, isl_dim_param))
+		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)
+{
+	if (!domain || !ma)
+		goto error;
+	if (isl_space_match(domain->dim, isl_dim_param,
+			    ma->space, isl_dim_param))
+		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;
+
+	space = isl_multi_union_pw_aff_get_space(mupa);
+
+	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);
+	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_space *space_mpa = NULL;
+	isl_multi_pw_aff *mpa;
+
+	if (!mupa || !space)
+		goto error;
+
+	space_mpa = isl_multi_union_pw_aff_get_space(mupa);
+	if (!isl_space_match(space_mpa, isl_dim_param, space, isl_dim_param)) {
+		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..2214942
--- /dev/null
+++ b/final/lib/External/isl/isl_aff_private.h
@@ -0,0 +1,175 @@
+#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);
+
+__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);
+
+int isl_aff_matching_params(__isl_keep isl_aff *aff,
+	__isl_keep isl_space *space);
+int 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_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_substitute(isl_int *p, int pos, isl_int *subs,
+	int p_len, int subs_len, isl_int v);
+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);
+
+int isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space);
+int isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa,
+	__isl_keep isl_space *space);
+
+#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..e7bde3f
--- /dev/null
+++ b/final/lib/External/isl/isl_affine_hull.c
@@ -0,0 +1,1424 @@
+/*
+ * 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>
+
+struct isl_basic_map *isl_basic_map_implicit_equalities(
+						struct 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 (struct isl_basic_set *)
+		isl_basic_map_implicit_equalities((struct isl_basic_map*)bset);
+}
+
+struct isl_map *isl_map_implicit_equalities(struct isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return map;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_implicit_equalities(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* 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;
+}
+
+struct isl_basic_set *isl_basic_set_recession_cone(struct 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;
+}
+
+__isl_give isl_set *isl_set_recession_cone(__isl_take isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0)
+		return set;
+
+	set = isl_set_remove_divs(set);
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_recession_cone(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+
+	return set;
+error:
+	isl_set_free(set);
+	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;
+}
+
+/* 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;
+	unsigned dim;
+
+	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;
+
+	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,
+			"index out of bounds", 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)
+{
+	unsigned dim;
+
+	if (!bmap)
+		return NULL;
+	if (n == 0)
+		return bmap;
+
+	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,
+			"index out of bounds", 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 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)
+{
+	int i;
+	unsigned dim;
+
+	if (!map)
+		return NULL;
+	if (n == 0)
+		return map;
+
+	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] = isl_basic_map_drop_constraints_involving_dims(
+						    map->p[i], type, first, n);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	return map;
+}
+
+/* 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);
+}
+
+/* Construct an initial underapproximatino 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.
+ */
+struct isl_basic_map *isl_basic_map_detect_equalities(
+						struct 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 (isl_basic_set *)
+		isl_basic_map_detect_equalities((isl_basic_map *)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 (isl_set *)isl_map_detect_equalities((isl_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;
+}
+
+/* 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.
+ */
+struct isl_basic_map *isl_basic_map_affine_hull(struct 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 (struct isl_basic_set *)
+		isl_basic_map_affine_hull((struct isl_basic_map *)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(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 (struct isl_basic_set *)
+		isl_map_affine_hull((struct isl_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..d85dcce
--- /dev/null
+++ b/final/lib/External/isl/isl_arg.c
@@ -0,0 +1,1309 @@
+/*
+ * 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;
+		*(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;
+		*(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..0ac01f9
--- /dev/null
+++ b/final/lib/External/isl/isl_ast.c
@@ -0,0 +1,2212 @@
+/*
+ * 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_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_id *id;
+
+	if (!expr || !id2expr)
+		goto error;
+
+	switch (expr->type) {
+	case isl_ast_expr_int:
+		break;
+	case isl_ast_expr_id:
+		if (!isl_id_to_ast_expr_has(id2expr, expr->u.id))
+			break;
+		id = isl_id_copy(expr->u.id);
+		isl_ast_expr_free(expr);
+		expr = isl_id_to_ast_expr_get(id2expr, id);
+		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);
+}
+
+/* Textual C representation of the various operators.
+ */
+static char *op_str[] = {
+	[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_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;
+}
+
+/* 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.
+ * If "left" is set, then "expr" is the left-most operand.
+ */
+static __isl_give isl_printer *print_sub_expr(__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 = isl_printer_print_ast_expr(p, expr);
+	if (need_parens)
+		p = isl_printer_print_str(p, ")");
+	return p;
+}
+
+/* Print a min or max reduction "expr".
+ */
+static __isl_give isl_printer *print_min_max(__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, op_str[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 = isl_printer_print_ast_expr(p, expr->u.op.args[i]);
+		p = isl_printer_print_str(p, ")");
+	}
+
+	return p;
+}
+
+/* Print a function call "expr".
+ *
+ * The first argument represents the function to be called.
+ */
+static __isl_give isl_printer *print_call(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	int i = 0;
+
+	p = isl_printer_print_ast_expr(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 = isl_printer_print_ast_expr(p, expr->u.op.args[i]);
+	}
+	p = isl_printer_print_str(p, ")");
+
+	return p;
+}
+
+/* Print an array access "expr".
+ *
+ * The first argument represents the array being accessed.
+ */
+static __isl_give isl_printer *print_access(__isl_take isl_printer *p,
+	__isl_keep isl_ast_expr *expr)
+{
+	int i = 0;
+
+	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 = isl_printer_print_ast_expr(p, expr->u.op.args[i]);
+		p = isl_printer_print_str(p, "]");
+	}
+
+	return p;
+}
+
+/* Print "expr" to "p".
+ *
+ * If we are printing in isl format, then we also print an indication
+ * of the size of the expression (if it was computed).
+ */
+__isl_give isl_printer *isl_printer_print_ast_expr(__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(p, expr);
+			break;
+		}
+		if (expr->u.op.op == isl_ast_op_access) {
+			p = print_access(p, expr);
+			break;
+		}
+		if (expr->u.op.n_arg == 1) {
+			p = isl_printer_print_str(p, op_str[expr->u.op.op]);
+			p = print_sub_expr(p, expr->u.op.op,
+						expr->u.op.args[0], 0);
+			break;
+		}
+		if (expr->u.op.op == isl_ast_op_fdiv_q) {
+			p = isl_printer_print_str(p, "floord(");
+			p = isl_printer_print_ast_expr(p, expr->u.op.args[0]);
+			p = isl_printer_print_str(p, ", ");
+			p = isl_printer_print_ast_expr(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(p, expr);
+			break;
+		}
+		if (expr->u.op.op == isl_ast_op_cond ||
+		    expr->u.op.op == isl_ast_op_select) {
+			p = isl_printer_print_ast_expr(p, expr->u.op.args[0]);
+			p = isl_printer_print_str(p, " ? ");
+			p = isl_printer_print_ast_expr(p, expr->u.op.args[1]);
+			p = isl_printer_print_str(p, " : ");
+			p = isl_printer_print_ast_expr(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",
+				goto error);
+		p = print_sub_expr(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, op_str[expr->u.op.op]);
+		if (expr->u.op.op != isl_ast_op_member)
+			p = isl_printer_print_str(p, " ");
+		p = print_sub_expr(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;
+error:
+	isl_printer_free(p);
+	return NULL;
+}
+
+/* Print "node" to "p" in "isl format".
+ */
+static __isl_give isl_printer *print_ast_node_isl(__isl_take isl_printer *p,
+	__isl_keep isl_ast_node *node)
+{
+	p = isl_printer_print_str(p, "(");
+	switch (node->type) {
+	case isl_ast_node_for:
+		if (node->u.f.degenerate) {
+			p = isl_printer_print_ast_expr(p, node->u.f.init);
+		} else {
+			p = isl_printer_print_str(p, "init: ");
+			p = isl_printer_print_ast_expr(p, node->u.f.init);
+			p = isl_printer_print_str(p, ", ");
+			p = isl_printer_print_str(p, "cond: ");
+			p = isl_printer_print_ast_expr(p, node->u.f.cond);
+			p = isl_printer_print_str(p, ", ");
+			p = isl_printer_print_str(p, "inc: ");
+			p = isl_printer_print_ast_expr(p, node->u.f.inc);
+		}
+		if (node->u.f.body) {
+			p = isl_printer_print_str(p, ", ");
+			p = isl_printer_print_str(p, "body: ");
+			p = isl_printer_print_ast_node(p, node->u.f.body);
+		}
+		break;
+	case isl_ast_node_mark:
+		p = isl_printer_print_str(p, "mark: ");
+		p = isl_printer_print_id(p, node->u.m.mark);
+		p = isl_printer_print_str(p, "node: ");
+		p = isl_printer_print_ast_node(p, node->u.m.node);
+	case isl_ast_node_user:
+		p = isl_printer_print_ast_expr(p, node->u.e.expr);
+		break;
+	case isl_ast_node_if:
+		p = isl_printer_print_str(p, "guard: ");
+		p = isl_printer_print_ast_expr(p, node->u.i.guard);
+		if (node->u.i.then) {
+			p = isl_printer_print_str(p, ", ");
+			p = isl_printer_print_str(p, "then: ");
+			p = isl_printer_print_ast_node(p, node->u.i.then);
+		}
+		if (node->u.i.else_node) {
+			p = isl_printer_print_str(p, ", ");
+			p = isl_printer_print_str(p, "else: ");
+			p = isl_printer_print_ast_node(p, node->u.i.else_node);
+		}
+		break;
+	case isl_ast_node_block:
+		p = isl_printer_print_ast_node_list(p, node->u.b.children);
+		break;
+	case isl_ast_node_error:
+		break;
+	}
+	p = isl_printer_print_str(p, ")");
+	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);
+
+/* Print the body "node" of a for or if node.
+ * If "else_node" is set, then it is printed as well.
+ *
+ * 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.
+ *
+ * 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)
+{
+	if (!node)
+		return isl_printer_free(p);
+
+	if (!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);
+		} else {
+			p = isl_printer_print_str(p, " else");
+			p = print_body_c(p, else_node, NULL, options);
+		}
+	} 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);
+	} 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.
+ */
+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)
+{
+	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);
+
+	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);
+		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);
+	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;
+}
+
+/* Print a macro definition for the operator "type".
+ */
+__isl_give isl_printer *isl_ast_op_type_print_macro(
+	enum isl_ast_op_type type, __isl_take isl_printer *p)
+{
+	switch (type) {
+	case isl_ast_op_min:
+		p = isl_printer_start_line(p);
+		p = isl_printer_print_str(p,
+			"#define min(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 max(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 floord(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 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);
+
+	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;
+}
+
+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 "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;
+}
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..febc7d4
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_build.c
@@ -0,0 +1,2571 @@
+/*
+ * 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.
+ */
+__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;
+
+	bounds = isl_basic_set_preimage_multi_aff(bounds,
+					isl_multi_aff_copy(build->values));
+	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 {
+		isl_basic_set *generated, *pending;
+
+		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 = isl_basic_set_copy(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));
+		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;
+}
+
+/* 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->pending 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_pending(
+	__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->pending = isl_set_intersect(build->pending, set);
+	build->pending = isl_set_coalesce(build->pending);
+
+	if (!build->pending)
+		return isl_ast_build_free(build);
+
+	return build;
+error:
+	isl_ast_build_free(build);
+	isl_set_free(set);
+	return NULL;
+}
+
+/* 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?
+ */
+int isl_ast_build_has_stride(__isl_keep isl_ast_build *build, int pos)
+{
+	isl_val *v;
+	int has_stride;
+
+	if (!build)
+		return -1;
+
+	v = isl_vec_get_element_val(build->strides, pos);
+	if (!v)
+		return -1;
+	has_stride = !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));
+}
+
+/* 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_space *space, *space2;
+	isl_union_set *options;
+	int n, n2;
+	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;
+
+	options = isl_schedule_node_band_get_ast_build_options(build->node);
+
+	space = isl_multi_aff_get_space(build->internal2input);
+	space = isl_space_range(space);
+	space2 = isl_set_get_space(build->domain);
+	if (isl_space_is_wrapping(space2))
+		space2 = isl_space_range(isl_space_unwrap(space2));
+	n2 = isl_space_dim(space2, isl_dim_set);
+	n = isl_space_dim(space, isl_dim_set);
+	if (n < n2)
+		isl_die(isl_ast_build_get_ctx(build), isl_error_internal,
+			"total input space dimension cannot be smaller "
+			"than dimension of innermost band",
+			space = isl_space_free(space));
+	space = isl_space_drop_dims(space, isl_dim_set, n - n2, n2);
+	space = isl_space_map_from_domain_and_range(space, space2);
+	space = isl_space_wrap(space);
+	space = isl_space_set_tuple_name(space, isl_dim_set, "isolate");
+	isolated = isl_union_set_extract_set(options, space);
+	isl_union_set_free(options);
+
+	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..29eb53f
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_build_expr.c
@@ -0,0 +1,1956 @@
+/*
+ * 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>
+
+/* Compute the "opposite" of the (numerator of the) argument of a div
+ * with denonimator "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(data->div, 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_basic_set_get_ctx(bset);
+		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.
+ *
+ * "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;
+
+		domain = isl_set_subtract(domain, set);
+		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);
+}
+
+struct isl_from_pw_aff_data {
+	isl_ast_build *build;
+	int n;
+	isl_ast_expr **next;
+	isl_set *dom;
+};
+
+/* This function is called during the construction of an isl_ast_expr
+ * that evaluates an isl_pw_aff.
+ * Adjust data->next to take into account this piece.
+ *
+ * data->n is the number of pairs of set and aff to go.
+ * data->dom is the domain of the entire isl_pw_aff.
+ *
+ * If this is the last pair, then data->next is set to evaluate aff
+ * and the domain is ignored.
+ * Otherwise, data->next is set to a select operation that selects
+ * an isl_ast_expr corresponding to "aff" on "set" and to an expression
+ * that will be filled in by later calls otherwise.
+ *
+ * In both cases, the constraints of "set" are added to the generated
+ * constraints of the build such that they can be exploited to simplify
+ * the AST expression constructed from "aff".
+ */
+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_ctx *ctx;
+	isl_ast_build *build;
+
+	ctx = isl_set_get_ctx(set);
+	data->n--;
+	if (data->n == 0) {
+		build = isl_ast_build_copy(data->build);
+		build = isl_ast_build_restrict_generated(build, set);
+		*data->next = isl_ast_expr_from_aff(aff, build);
+		isl_ast_build_free(build);
+		if (!*data->next)
+			return isl_stat_error;
+	} else {
+		isl_ast_expr *ternary, *arg;
+		isl_set *gist;
+
+		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 = isl_ast_expr_from_aff(aff, build);
+		isl_ast_build_free(build);
+		ternary = isl_ast_expr_set_op_arg(ternary, 1, arg);
+		if (!ternary)
+			return isl_stat_error;
+
+		*data->next = ternary;
+		data->next = &ternary->u.op.args[2];
+	}
+
+	return isl_stat_ok;
+}
+
+/* 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;
+	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;
+
+	data.build = build;
+	data.n = isl_pw_aff_n_piece(pa);
+	data.next = &res;
+	data.dom = isl_pw_aff_domain(isl_pw_aff_copy(pa));
+
+	if (isl_pw_aff_foreach_piece(pa, &ast_expr_from_pw_aff, &data) < 0)
+		res = isl_ast_expr_free(res);
+	else if (!res)
+		isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,
+			"cannot handle void expression", res = NULL);
+
+	isl_pw_aff_free(pa);
+	isl_set_free(data.dom);
+	return res;
+}
+
+/* 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..59eec25
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_build_private.h
@@ -0,0 +1,325 @@
+#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_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 isl_ast_build *isl_ast_build_restrict_pending(
+	__isl_take isl_ast_build *build, __isl_take isl_set *set);
+__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_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);
+
+int 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..3c69805
--- /dev/null
+++ b/final/lib/External/isl/isl_ast_codegen.c
@@ -0,0 +1,5596 @@
+/*
+ * 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 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.
+ * 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, we generate a call expression for the single executed
+ * domain element and put a guard around it based on the (simplified)
+ * domain of "executed".
+ *
+ * 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.
+ * We therefore turn all pending constraints into guards
+ * (after simplifying them with respect to the already generated
+ * constraints) and add them to both the generated constraints
+ * and the guard of the constructed graft.  This guard will ensure
+ * that the constraints are effectively generated.
+ *
+ * If the user has set an at_each_domain callback, it is called
+ * on the constructed call expression node.
+ */
+static isl_stat generate_domain(__isl_take isl_map *executed, void *user)
+{
+	struct isl_generate_domain_data *data = user;
+	isl_ast_build *build;
+	isl_ast_graft *graft;
+	isl_ast_graft_list *list;
+	isl_set *guard, *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;
+	}
+
+	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);
+	}
+	guard = isl_map_domain(isl_map_copy(map));
+	guard = isl_set_compute_divs(guard);
+	guard = isl_set_intersect(guard,
+				    isl_ast_build_get_pending(data->build));
+	guard = isl_set_coalesce(guard);
+	guard = isl_ast_build_specialize(data->build, guard);
+	guard = isl_set_gist(guard, isl_ast_build_get_generated(data->build));
+
+	build = isl_ast_build_copy(data->build);
+	build = isl_ast_build_replace_pending_by_guard(build,
+							isl_set_copy(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;
+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 (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);
+
+	if (!node->u.f.iterator || !node->u.f.init ||
+	    !node->u.f.cond || !node->u.f.inc)
+		return isl_ast_graft_free(graft);
+
+	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);
+	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 (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 (!degenerate)
+		bounds = isl_ast_build_compute_gist_basic_set(build, bounds);
+	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;
+}
+
+/* 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.
+ */
+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_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);
+
+	if (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.
+ *
+ * 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.
+ * 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_ast_graft_list *list, *res;
+
+	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));
+	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));
+
+	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, domain, build, 0);
+	res = isl_ast_graft_list_concat(res, list);
+
+	isl_union_map_free(executed);
+	isl_ast_build_free(build);
+
+	return res;
+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.
+ */
+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_ast_graft_list *list;
+	int empty;
+	unsigned n1, n2;
+
+	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);
+
+	empty = isl_union_map_is_empty(executed);
+	if (empty < 0)
+		goto error;
+	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);
+	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..a34a0d5
--- /dev/null
+++ b/final/lib/External/isl/isl_bernstein.c
@@ -0,0 +1,555 @@
+/*
+ * 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 int 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 0;
+error:
+	isl_cell_free(cell);
+	return -1;
+}
+
+/* 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);
+	isl_vertices_foreach_disjoint_cell(vertices,
+		&bernstein_coefficients_cell, data);
+	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.
+ */
+int 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 0;
+error:
+	isl_basic_set_free(bset);
+	isl_qpolynomial_free(poly);
+	return -1;
+}
diff --git a/final/lib/External/isl/isl_bernstein.h b/final/lib/External/isl/isl_bernstein.h
new file mode 100644
index 0000000..7694b04
--- /dev/null
+++ b/final/lib/External/isl/isl_bernstein.h
@@ -0,0 +1,4 @@
+#include <isl_bound.h>
+
+int 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..d9f80db
--- /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 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 = block.data;
+	block.data = isl_realloc_array(ctx, block.data, isl_int, new_n);
+	if (!block.data) {
+		free(p);
+		return isl_blk_error();
+	}
+
+	for (i = block.size; i < new_n; ++i)
+		isl_int_init(block.data[i]);
+	block.size = new_n;
+
+	return block;
+}
+
+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);
+}
+
+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..0774d9a
--- /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 int 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 int 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;
+	int 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 -1;
+}
+
+static int 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;
+	int 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..9b0e47f
--- /dev/null
+++ b/final/lib/External/isl/isl_coalesce.c
@@ -0,0 +1,2684 @@
+/*
+ * 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 "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_vec_private.h>
+#include <isl_aff_private.h>
+
+#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 inequalties 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;
+		}
+		if (eq[2 * k] == STATUS_SEPARATE ||
+		    eq[2 * k + 1] == STATUS_SEPARATE)
+			break;
+	}
+
+	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;
+}
+
+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;
+};
+
+/* 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 schedule for the basic map
+ * to be simplified 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;
+
+	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;
+
+	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);
+			info[i].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);
+	ISL_F_SET(fused, ISL_BASIC_MAP_FINAL);
+	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);
+
+	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;
+	}
+
+	info[i].simplify |= info[j].simplify;
+	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 int 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 -1;
+		if (stat != STATUS_VALID)
+			return 0;
+		stat = status_in(bmap->eq[k], tab);
+		if (stat < 0)
+			return -1;
+		if (stat != STATUS_VALID)
+			return 0;
+	}
+
+	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 -1;
+		if (stat != STATUS_VALID)
+			return 0;
+	}
+	return 1;
+}
+
+/* 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".
+ * If so, 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);
+	int r;
+	int super;
+
+	if (isl_tab_extend_cons(info[i].tab, 1 + info[j].bmap->n_ineq) < 0)
+		return isl_change_error;
+
+	for (k = 0; k < info[i].bmap->n_ineq; ++k)
+		if (info[i].ineq[k] == STATUS_ADJ_INEQ)
+			break;
+	if (k >= info[i].bmap->n_ineq)
+		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;
+	}
+
+	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;
+}
+
+/* Basic map "i" has an inequality "k" that is adjacent to some equality
+ * of basic map "j".  All the other inequalities are valid for "j".
+ * Check if basic map "j" forms an extension of basic map "i".
+ *
+ * In particular, we relax constraint "k", compute the corresponding
+ * facet and check whether it is included in the other basic map.
+ * If so, we know that relaxing the constraint extends the basic
+ * map with exactly the other basic map (we already know that this
+ * other basic map is included in the extension, because there
+ * were no "cut" inequalities in "i") and we can replace the
+ * two basic maps by this extension.
+ * 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 this extension in the position that is the smallest of i and j.
+ *        ____			  _____
+ *       /    || 		 /     |
+ *      /     ||  		/      |
+ *      \     ||   	=>	\      |
+ *       \    ||		 \     |
+ *        \___||		  \____|
+ */
+static enum isl_change is_adj_eq_extension(int i, int j, int k,
+	struct isl_coalesce_info *info)
+{
+	int change = isl_change_none;
+	int super;
+	struct isl_tab_undo *snap, *snap2;
+	unsigned n_eq = info[i].bmap->n_eq;
+
+	if (isl_tab_is_equality(info[i].tab, n_eq + k))
+		return isl_change_none;
+
+	snap = isl_tab_snap(info[i].tab);
+	if (isl_tab_relax(info[i].tab, n_eq + k) < 0)
+		return isl_change_error;
+	snap2 = isl_tab_snap(info[i].tab);
+	if (isl_tab_select_facet(info[i].tab, n_eq + k) < 0)
+		return isl_change_error;
+	super = contains(&info[j], info[i].tab);
+	if (super < 0)
+		return isl_change_error;
+	if (super) {
+		int l;
+		unsigned total;
+
+		if (isl_tab_rollback(info[i].tab, snap2) < 0)
+			return isl_change_error;
+		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;
+			}
+		isl_int_add_ui(info[i].bmap->ineq[k][0],
+				info[i].bmap->ineq[k][0], 1);
+		ISL_F_SET(info[i].bmap, ISL_BASIC_MAP_FINAL);
+		drop(&info[j]);
+		if (j < i)
+			exchange(&info[i], &info[j]);
+		change = isl_change_fuse;
+	} else
+		if (isl_tab_rollback(info[i].tab, snap) < 0)
+			return isl_change_error;
+
+	return change;
+}
+
+/* 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 void 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);
+}
+
+/* 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 void 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;
+	ctx = isl_mat_get_ctx(mat);
+	wraps->bound = isl_options_get_coalesce_bounded_wrapping(ctx);
+	if (!wraps->bound)
+		return;
+	isl_int_init(wraps->max);
+	isl_int_set_si(wraps->max, 0);
+	wraps_update_max(wraps, &info[i]);
+	wraps_update_max(wraps, &info[j]);
+}
+
+/* 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 int 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 -1;
+		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 -1;
+			if (!added)
+				goto unbounded;
+			++w;
+		}
+	}
+
+	wraps->mat->n_row = w;
+	return 0;
+unbounded:
+	wraps->mat->n_row = 0;
+	return 0;
+}
+
+/* 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 int 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 -1;
+	if (isl_tab_detect_redundant(info->tab) < 0)
+		return -1;
+
+	isl_seq_neg(bound, info->bmap->ineq[k], 1 + total);
+
+	n = wraps->mat->n_row;
+	if (add_wraps(wraps, info, bound, set) < 0)
+		return -1;
+
+	if (isl_tab_rollback(info->tab, snap) < 0)
+		return -1;
+	if (check_wraps(wraps->mat, n, info->tab) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* 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);
+	wraps_init(&wraps, mat, info, i, j);
+	bound = isl_vec_alloc(ctx, 1 + total);
+	if (!set_i || !set_j || !wraps.mat || !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 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.
+ *
+ * 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.
+ * 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.
+ *
+ * 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 wrap_in_facets(int i, int j, int *cuts, 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;
+	int k, w;
+	struct isl_tab_undo *snap;
+
+	if (isl_tab_extend_cons(info[j].tab, 1) < 0)
+		goto 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);
+	wraps_init(&wraps, mat, info, i, j);
+	if (!set_i || !wraps.mat)
+		goto error;
+
+	snap = isl_tab_snap(info[j].tab);
+
+	wraps.mat->n_row = 0;
+
+	for (k = 0; k < n; ++k) {
+		w = wraps.mat->n_row++;
+		isl_seq_cpy(wraps.mat->row[w],
+			    info[i].bmap->ineq[cuts[k]], 1 + total);
+		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)
+			goto error;
+		if (isl_tab_detect_redundant(info[j].tab) < 0)
+			goto 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)
+			goto error;
+
+		if (isl_tab_rollback(info[j].tab, snap) < 0)
+			goto error;
+
+		if (!wraps.mat->n_row)
+			break;
+	}
+
+	if (k == n)
+		change = fuse(i, j, info, wraps.mat, 0, 1);
+
+	wraps_free(&wraps);
+	isl_set_free(set_i);
+
+	return change;
+error:
+	wraps_free(&wraps);
+	isl_set_free(set_i);
+	return isl_change_error;
+}
+
+/* Given two basic sets i and j such that i has no cut equalities,
+ * check if relaxing all the cut inequalities 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)
+{
+	enum isl_change change = isl_change_none;
+	int k, m;
+	int n;
+	int *cuts = NULL;
+	isl_ctx *ctx;
+
+	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].ineq, info[i].bmap->n_ineq, STATUS_CUT);
+	if (n == 0)
+		return isl_change_none;
+
+	ctx = isl_basic_map_get_ctx(info[i].bmap);
+	cuts = isl_alloc_array(ctx, int, n);
+	if (!cuts)
+		return isl_change_error;
+
+	for (k = 0, m = 0; m < n; ++k) {
+		enum isl_ineq_type type;
+
+		if (info[i].ineq[k] != STATUS_CUT)
+			continue;
+
+		isl_int_add_ui(info[i].bmap->ineq[k][0],
+				info[i].bmap->ineq[k][0], 1);
+		type = isl_tab_ineq_type(info[j].tab, info[i].bmap->ineq[k]);
+		isl_int_sub_ui(info[i].bmap->ineq[k][0],
+				info[i].bmap->ineq[k][0], 1);
+		if (type == isl_ineq_error)
+			goto error;
+		if (type != isl_ineq_redundant)
+			break;
+		cuts[m] = k;
+		++m;
+	}
+
+	if (m == n)
+		change = wrap_in_facets(i, j, cuts, n, info);
+
+	free(cuts);
+
+	return change;
+error:
+	free(cuts);
+	return isl_change_error;
+}
+
+/* Check if either i or j has only cut inequalities 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;
+
+	if (!any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT))
+		change = can_wrap_in_set(i, j, info);
+	if (change != isl_change_none)
+		return change;
+
+	if (!any(info[j].eq, 2 * info[j].bmap->n_eq, STATUS_CUT))
+		change = can_wrap_in_set(j, i, info);
+	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.
+ * We call the basic map that has the inequality "i" and the basic
+ * map that has the equality "j".
+ * If "i" has any "cut" (in)equality, then relaxing the inequality
+ * by one would not result in a basic map that contains the other
+ * basic map.  However, it may still be possible to wrap in the other
+ * basic map.
+ */
+static enum isl_change check_adj_eq(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+	int k;
+	int any_cut;
+
+	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 (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_CUT))
+		return isl_change_none;
+	any_cut = any(info[i].ineq, info[i].bmap->n_ineq, STATUS_CUT);
+	if (count(info[i].ineq, info[i].bmap->n_ineq, STATUS_ADJ_EQ) != 1 ||
+	    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;
+
+	for (k = 0; k < info[i].bmap->n_ineq; ++k)
+		if (info[i].ineq[k] == STATUS_ADJ_EQ)
+			break;
+
+	if (!any_cut) {
+		change = is_adj_eq_extension(i, j, k, info);
+		if (change != isl_change_none)
+			return change;
+	}
+
+	change = can_wrap_in_facet(i, j, k, info, any_cut);
+
+	return change;
+}
+
+/* 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;
+
+	for (k = 0; k < 2 * info[i].bmap->n_eq ; ++k)
+		if (info[i].eq[k] == STATUS_ADJ_EQ)
+			break;
+
+	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);
+	wraps_init(&wraps, mat, info, i, j);
+	bound = isl_vec_alloc(ctx, 1 + total);
+	if (!set_i || !set_j || !wraps.mat || !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;
+}
+
+/* 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.
+ *
+ * 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(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	enum isl_change change = isl_change_none;
+
+	info[i].eq = info[i].ineq = NULL;
+	info[j].eq = info[j].ineq = NULL;
+
+	info[i].eq = eq_status_in(info[i].bmap, 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;
+	if (any(info[i].eq, 2 * info[i].bmap->n_eq, STATUS_SEPARATE))
+		goto done;
+
+	info[j].eq = eq_status_in(info[j].bmap, 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[j].eq, 2 * info[j].bmap->n_eq, STATUS_SEPARATE))
+		goto done;
+
+	info[i].ineq = ineq_status_in(info[i].bmap, info[i].tab, 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;
+
+	info[j].ineq = ineq_status_in(info[j].bmap, info[j].tab, 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;
+
+	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:
+	free(info[i].eq);
+	free(info[j].eq);
+	free(info[i].ineq);
+	free(info[j].ineq);
+	return change;
+error:
+	free(info[i].eq);
+	free(info[j].eq);
+	free(info[i].ineq);
+	free(info[j].ineq);
+	return isl_change_error;
+}
+
+/* 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 int 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 -1;
+
+	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 -1;
+
+	return 0;
+}
+
+/* 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 one is equal to the other plus a constant.
+ *
+ * In particular, for each pair of integer divisions, if both are known,
+ * have identical coefficients (apart from the constant term) and
+ * if the difference between the constant terms (taking into account
+ * the denominator) is an integer, then move the difference outside.
+ * That is, if 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(x) + c_1 + n * d)/d) - n = floor((f(x) + c_2)/d) - n
+ */
+static int harmonize_divs(struct isl_coalesce_info *info1,
+	struct isl_coalesce_info *info2)
+{
+	int i;
+	int total;
+
+	if (!info1->bmap || !info2->bmap)
+		return -1;
+
+	if (info1->bmap->n_div != info2->bmap->n_div)
+		return 0;
+	if (info1->bmap->n_div == 0)
+		return 0;
+
+	total = isl_basic_map_total_dim(info1->bmap);
+	for (i = 0; i < info1->bmap->n_div; ++i) {
+		isl_int d;
+		int r = 0;
+
+		if (isl_int_is_zero(info1->bmap->div[i][0]) ||
+		    isl_int_is_zero(info2->bmap->div[i][0]))
+			continue;
+		if (isl_int_ne(info1->bmap->div[i][0], info2->bmap->div[i][0]))
+			continue;
+		if (isl_int_eq(info1->bmap->div[i][1], info2->bmap->div[i][1]))
+			continue;
+		if (!isl_seq_eq(info1->bmap->div[i] + 2,
+				info2->bmap->div[i] + 2, total))
+			continue;
+		isl_int_init(d);
+		isl_int_sub(d, info2->bmap->div[i][1], info1->bmap->div[i][1]);
+		if (isl_int_is_divisible_by(d, info1->bmap->div[i][0])) {
+			isl_int_divexact(d, d, info1->bmap->div[i][0]);
+			r = shift_div(info1, i, d);
+		}
+		isl_int_clear(d);
+		if (r < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* 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 int same_divs(__isl_keep isl_basic_map *bmap1,
+	__isl_keep isl_basic_map *bmap2)
+{
+	int i;
+	int known;
+	int total;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+	if (bmap1->n_div != bmap2->n_div)
+		return 0;
+
+	if (bmap1->n_div == 0)
+		return 1;
+
+	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;
+}
+
+/* Does "bmap" contain the basic map represented by the tableau "tab"
+ * after expanding the divs of "bmap" to match those of "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 "tab".
+ */
+static int contains_with_expanded_divs(__isl_keep isl_basic_map *bmap,
+	struct isl_tab *tab, __isl_keep isl_mat *div, int *exp)
+{
+	int superset = 0;
+	int *eq_i = NULL;
+	int *ineq_i = NULL;
+
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_set_expand_divs(bmap, isl_mat_copy(div), exp);
+
+	if (!bmap)
+		goto error;
+
+	eq_i = eq_status_in(bmap, tab);
+	if (bmap->n_eq && !eq_i)
+		goto error;
+	if (any(eq_i, 2 * bmap->n_eq, STATUS_ERROR))
+		goto error;
+	if (any(eq_i, 2 * bmap->n_eq, STATUS_SEPARATE))
+		goto done;
+
+	ineq_i = ineq_status_in(bmap, NULL, tab);
+	if (bmap->n_ineq && !ineq_i)
+		goto error;
+	if (any(ineq_i, bmap->n_ineq, STATUS_ERROR))
+		goto error;
+	if (any(ineq_i, bmap->n_ineq, STATUS_SEPARATE))
+		goto done;
+
+	if (all(eq_i, 2 * bmap->n_eq, STATUS_VALID) &&
+	    all(ineq_i, bmap->n_ineq, STATUS_VALID))
+		superset = 1;
+
+done:
+	isl_basic_map_free(bmap);
+	free(eq_i);
+	free(ineq_i);
+	return superset;
+error:
+	isl_basic_map_free(bmap);
+	free(eq_i);
+	free(ineq_i);
+	return -1;
+}
+
+/* Does "bmap_i" contain 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 "bmap_j".  If so, we pass control over to
+ * contains_with_expanded_divs.
+ */
+static int contains_after_aligning_divs(__isl_keep isl_basic_map *bmap_i,
+	struct isl_coalesce_info *info_j)
+{
+	int known;
+	isl_mat *div_i, *div_j, *div;
+	int *exp1 = NULL;
+	int *exp2 = NULL;
+	isl_ctx *ctx;
+	int subset;
+
+	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)
+		subset = contains_with_expanded_divs(bmap_i,
+							info_j->tab, div, exp1);
+	else
+		subset = 0;
+
+	isl_mat_free(div);
+
+	isl_mat_free(div_i);
+	isl_mat_free(div_j);
+
+	free(exp2);
+	free(exp1);
+
+	return subset;
+error:
+	isl_mat_free(div_i);
+	isl_mat_free(div_j);
+	free(exp1);
+	free(exp2);
+	return -1;
+}
+
+/* Check if the basic map "j" is a subset of basic map "i",
+ * if "i" has fewer divs that "j".
+ * If so, remove basic map "j".
+ *
+ * If the two basic maps have the same number of divs, then
+ * they must necessarily be different.  Otherwise, we would have
+ * called coalesce_local_pair.  We therefore don't try anything
+ * in this case.
+ */
+static int coalesced_subset(int i, int j, struct isl_coalesce_info *info)
+{
+	int superset;
+
+	if (info[i].bmap->n_div >= info[j].bmap->n_div)
+		return 0;
+
+	superset = contains_after_aligning_divs(info[i].bmap, &info[j]);
+	if (superset < 0)
+		return -1;
+	if (superset)
+		drop(&info[j]);
+
+	return superset;
+}
+
+/* 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".
+ *
+ * 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 int coalesced_subset_with_equalities(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	isl_basic_map *hull_i, *hull_j, *bmap_i;
+	int equal, empty, subset;
+
+	if (info[j].bmap->n_eq == 0)
+		return 0;
+	if (info[i].bmap->n_div == 0)
+		return 0;
+
+	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);
+		return equal < 0 || empty < 0 ? -1 : 0;
+	}
+
+	bmap_i = isl_basic_map_copy(info[i].bmap);
+	bmap_i = isl_basic_map_intersect(bmap_i, hull_j);
+	if (!bmap_i)
+		return -1;
+
+	if (bmap_i->n_div > info[j].bmap->n_div) {
+		isl_basic_map_free(bmap_i);
+		return 0;
+	}
+
+	subset = contains_after_aligning_divs(bmap_i, &info[j]);
+
+	isl_basic_map_free(bmap_i);
+
+	if (subset < 0)
+		return -1;
+	if (subset)
+		drop(&info[j]);
+
+	return subset;
+}
+
+/* Check if one of the basic maps is a subset of the other and, if so,
+ * drop the subset.
+ * 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 check_coalesce_subset(int i, int j,
+	struct isl_coalesce_info *info)
+{
+	int changed;
+
+	changed = coalesced_subset(i, j, info);
+	if (changed < 0 || changed)
+		return changed < 0 ? isl_change_error : isl_change_drop_second;
+
+	changed = coalesced_subset(j, i, info);
+	if (changed < 0 || changed)
+		return changed < 0 ? isl_change_error : isl_change_drop_first;
+
+	changed = coalesced_subset_with_equalities(i, j, info);
+	if (changed < 0 || changed)
+		return changed < 0 ? isl_change_error : isl_change_drop_second;
+
+	changed = coalesced_subset_with_equalities(j, i, info);
+	if (changed < 0 || changed)
+		return changed < 0 ? isl_change_error : isl_change_drop_first;
+
+	return isl_change_none;
+}
+
+/* Does "bmap" involve any divs that themselves refer to divs?
+ */
+static int 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 1;
+
+	return 0;
+}
+
+/* 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_seq_eq(bmap_i->div[i], bmap_j->div[j], 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 "tab" corresponding to the elements in "list"
+ * that are not set to NaN.
+ * "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".
+ */
+static int add_sub_vars(struct isl_tab *tab, __isl_keep isl_aff_list *list,
+	int dim)
+{
+	int i, n;
+
+	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 -1;
+
+		if (!is_nan && isl_tab_insert_var(tab, dim + i) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* 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".
+ */
+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 corresponding to the elements in "list"
+ * that are not set to NaN.  The value of the added variable
+ * 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".
+ * Additionally, add the div constraints that have been added info->bmap
+ * after the tableau was constructed to info->tab.  These constraints
+ * start at position "n_ineq" in info->bmap.
+ * The constraints need to be added to the tableau before
+ * the equalities assigning the purely affine expression
+ * because the position needs to match that in info->bmap.
+ * They are frozen because the corresponding added equality is a consequence
+ * of the two div constraints and the other equalities, meaning that
+ * the div constraints would otherwise get marked as redundant,
+ * while they are only redundant with respect to the extra equalities
+ * added to the tableau, which do not appear explicitly in the basic map.
+ */
+static int add_subs(struct isl_coalesce_info *info,
+	__isl_keep isl_aff_list *list, int dim, int n_ineq)
+{
+	int i, extra_var, extra_con;
+	int n;
+	unsigned n_eq = info->bmap->n_eq;
+
+	if (!list)
+		return -1;
+
+	n = isl_aff_list_n_aff(list);
+	extra_var = n - (info->tab->n_var - dim);
+	extra_con = info->bmap->n_ineq - n_ineq;
+
+	if (isl_tab_extend_vars(info->tab, extra_var) < 0)
+		return -1;
+	if (isl_tab_extend_cons(info->tab, extra_con + 2 * extra_var) < 0)
+		return -1;
+	if (add_sub_vars(info->tab, list, dim) < 0)
+		return -1;
+
+	for (i = n_ineq; i < info->bmap->n_ineq; ++i) {
+		if (isl_tab_add_ineq(info->tab, info->bmap->ineq[i]) < 0)
+			return -1;
+		if (isl_tab_freeze_constraint(info->tab, n_eq + i) < 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".
+ * Adding extra integer divisions to "j" through isl_basic_map_align_divs
+ * also adds the corresponding div constraints.  These need to be added
+ * to the corresponding tableau as well in add_subs to maintain consistency.
+ *
+ * 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;
+	int n_ineq;
+
+	bmap_j = isl_basic_map_copy(info[j].bmap);
+	n_ineq = info[j].bmap->n_ineq;
+	info[j].bmap = isl_basic_map_align_divs(info[j].bmap, info[i].bmap);
+	if (!info[j].bmap)
+		goto error;
+
+	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, n_ineq) < 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)
+{
+	int 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)
+{
+	int 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 = check_coalesce_subset(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.
+ */
+struct isl_map *isl_map_coalesce(struct 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 (struct isl_set *)isl_map_coalesce((struct isl_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..58830f3
--- /dev/null
+++ b/final/lib/External/isl/isl_config.h.in
@@ -0,0 +1,200 @@
+/* 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 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 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 the sub-directory in which 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
+
+/* 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
+
+#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..9411fd1
--- /dev/null
+++ b/final/lib/External/isl/isl_constraint.c
@@ -0,0 +1,1451 @@
+/*
+ * 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>
+
+#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((struct isl_basic_map *)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((isl_basic_map *)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 (struct isl_basic_set *)
+		isl_basic_map_add_constraint((struct isl_basic_map *)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(struct 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;
+}
+
+/* Drop any constraint from "bset" that is identical to "constraint".
+ * In particular, this means that the local spaces of "bset" and
+ * "constraint" need to be the same.
+ *
+ * We manually set ISL_BASIC_SET_FINAL instead of calling
+ * isl_basic_set_finalize because this function is called by CLooG,
+ * which does not expect any variables to disappear.
+ */
+__isl_give isl_basic_set *isl_basic_set_drop_constraint(
+	__isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint)
+{
+	int i;
+	unsigned n;
+	isl_int **row;
+	unsigned total;
+	isl_local_space *ls1;
+	int equal;
+	int equality;
+
+	if (!bset || !constraint)
+		goto error;
+
+	ls1 = isl_basic_set_get_local_space(bset);
+	equal = isl_local_space_is_equal(ls1, constraint->ls);
+	isl_local_space_free(ls1);
+	if (equal < 0)
+		goto error;
+	if (!equal) {
+		isl_constraint_free(constraint);
+		return bset;
+	}
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+
+	equality = isl_constraint_is_equality(constraint);
+	if (equality) {
+		n = bset->n_eq;
+		row = bset->eq;
+	} else {
+		n = bset->n_ineq;
+		row = bset->ineq;
+	}
+
+	total = isl_constraint_dim(constraint, isl_dim_all);
+	for (i = 0; i < n; ++i) {
+		if (!isl_seq_eq(row[i], constraint->v->el, 1 + total))
+			continue;
+		if (equality && isl_basic_set_drop_equality(bset, i) < 0)
+			goto error;
+		if (!equality && isl_basic_set_drop_inequality(bset, i) < 0)
+			goto error;
+		break;
+	}
+			
+	isl_constraint_free(constraint);
+	ISL_F_SET(bset, ISL_BASIC_SET_FINAL);
+	return bset;
+error:
+	isl_constraint_free(constraint);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+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) {
+		if (isl_local_space_is_div_constraint(constraint->ls,
+							constraint->v->el, i))
+			return 1;
+	}
+
+	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;
+}
+
+struct isl_basic_set *isl_basic_set_from_constraint(
+	struct 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 (isl_basic_set *)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.
+ */
+int 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 -1;
+	offset = basic_map_offset(bmap, type);
+	total = isl_basic_map_total_dim(bmap);
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), return -1);
+	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 1;
+	}
+	return 0;
+}
+
+/* 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.
+ */
+int 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((isl_basic_map *)bset,
+						    type, pos, c);
+}
+
+int 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 -1;
+	offset = basic_set_offset(bset, type);
+	total = isl_basic_set_total_dim(bset);
+	isl_assert(bset->ctx, pos < isl_basic_set_dim(bset, type), return -1);
+	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 1;
+		}
+	}
+	*lower = NULL;
+	*upper = NULL;
+	isl_int_clear(m);
+	return 0;
+}
+
+/* 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..5cef017
--- /dev/null
+++ b/final/lib/External/isl/isl_constraint_private.h
@@ -0,0 +1,32 @@
+#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_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..b5ca0d9
--- /dev/null
+++ b/final/lib/External/isl/isl_convex_hull.c
@@ -0,0 +1,2845 @@
+/*
+ * 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>
+
+static struct isl_basic_set *uset_convex_hull_wrap_bounded(struct isl_set *set);
+
+/* Return 1 if constraint c is redundant with respect to the constraints
+ * in bmap.  If c is a lower [upper] bound in some variable and bmap
+ * does not have a lower [upper] bound in that variable, then c cannot
+ * be redundant and we do not need solve any lp.
+ */
+int isl_basic_map_constraint_is_redundant(struct isl_basic_map **bmap,
+	isl_int *c, isl_int *opt_n, isl_int *opt_d)
+{
+	enum isl_lp_result res;
+	unsigned total;
+	int i, j;
+
+	if (!bmap)
+		return -1;
+
+	total = isl_basic_map_total_dim(*bmap);
+	for (i = 0; i < total; ++i) {
+		int sign;
+		if (isl_int_is_zero(c[1+i]))
+			continue;
+		sign = isl_int_sgn(c[1+i]);
+		for (j = 0; j < (*bmap)->n_ineq; ++j)
+			if (sign == isl_int_sgn((*bmap)->ineq[j][1+i]))
+				break;
+		if (j == (*bmap)->n_ineq)
+			break;
+	}
+	if (i < total)
+		return 0;
+
+	res = isl_basic_map_solve_lp(*bmap, 0, c, (*bmap)->ctx->one,
+					opt_n, opt_d, NULL);
+	if (res == isl_lp_unbounded)
+		return 0;
+	if (res == isl_lp_error)
+		return -1;
+	if (res == isl_lp_empty) {
+		*bmap = isl_basic_map_set_to_empty(*bmap);
+		return 0;
+	}
+	return !isl_int_is_neg(*opt_n);
+}
+
+int isl_basic_set_constraint_is_redundant(struct isl_basic_set **bset,
+	isl_int *c, isl_int *opt_n, isl_int *opt_d)
+{
+	return isl_basic_map_constraint_is_redundant(
+			(struct isl_basic_map **)bset, c, opt_n, opt_d);
+}
+
+/* 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.
+ *
+ * Alternatively, we could have intersected the basic map with the
+ * corresponding equality and the 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;
+
+	tab = isl_tab_from_basic_map(bmap, 0);
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		goto error;
+	if (isl_tab_detect_redundant(tab) < 0)
+		goto error;
+	bmap = isl_basic_map_update_from_tab(bmap, tab);
+	isl_tab_free(tab);
+	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 (struct isl_basic_set *)
+		isl_basic_map_remove_redundancies((struct isl_basic_map *)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(struct 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;
+}
+
+__isl_give isl_basic_map *isl_basic_map_set_rational(
+	__isl_take isl_basic_set *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_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);
+}
+
+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 struct isl_set *isl_set_add_basic_set_equality(struct 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 struct isl_basic_set *wrap_constraints(struct 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 struct isl_basic_set *compute_facet(struct 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 struct isl_basic_set *extend(struct isl_basic_set *hull,
+	struct 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 struct isl_basic_set *convex_hull_1d(struct 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 struct isl_basic_set *convex_hull_0d(struct 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 struct isl_basic_set *convex_hull_pair_elim(struct isl_basic_set *bset1,
+	struct 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?
+ */
+int isl_basic_set_is_bounded(__isl_keep isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+	int bounded;
+
+	if (!bset)
+		return -1;
+	if (isl_basic_set_plain_is_empty(bset))
+		return 1;
+
+	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?
+ */
+int 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);
+	int 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((isl_basic_set *)bmap);
+	isl_basic_map_free(bmap);
+
+	return bounded;
+}
+
+/* Is the set bounded for each value of the parameters?
+ */
+int isl_set_is_bounded(__isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return -1;
+
+	for (i = 0; i < set->n; ++i) {
+		int bounded = isl_basic_set_is_bounded(set->p[i]);
+		if (!bounded || bounded < 0)
+			return bounded;
+	}
+	return 1;
+}
+
+/* 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 struct isl_basic_set *induced_lineality_space(
+	struct isl_basic_set *bset1, struct 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 struct isl_basic_set *uset_convex_hull(struct 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 struct isl_basic_set *modulo_lineality(struct isl_set *set,
+	struct 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 struct isl_basic_set *valid_direction_lp(
+	struct isl_basic_set *bset1, struct 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 struct isl_vec *valid_direction(
+	struct isl_basic_set *bset1, struct 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 struct isl_basic_set *homogeneous_map(struct isl_basic_set *bset,
+	struct 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 struct isl_basic_set *convex_hull_pair_pointed(
+	struct isl_basic_set *bset1, struct 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 struct isl_basic_set *uset_convex_hull_wrap(struct isl_set *set);
+static struct isl_basic_set *modulo_affine_hull(
+	struct isl_set *set, struct 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 struct isl_basic_set *convex_hull_pair(struct isl_basic_set *bset1,
+	struct 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_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 currently do not allow the basic set to have any divs.
+ * We basically just drop the constants and turn every inequality
+ * into an equality.
+ */
+struct isl_basic_set *isl_basic_set_lineality_space(struct isl_basic_set *bset)
+{
+	int i, k;
+	struct isl_basic_set *lin = NULL;
+	unsigned dim;
+
+	if (!bset)
+		goto error;
+	isl_assert(bset->ctx, bset->n_div == 0, goto error);
+	dim = isl_basic_set_total_dim(bset);
+
+	lin = isl_basic_set_alloc_space(isl_basic_set_get_space(bset), 0, dim, 0);
+	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
+ * "underlying" set "set".
+ */
+static struct isl_basic_set *uset_combined_lineality_space(struct isl_set *set)
+{
+	int i;
+	struct isl_set *lin = NULL;
+
+	if (!set)
+		return NULL;
+	if (set->n == 0) {
+		isl_space *dim = isl_set_get_space(set);
+		isl_set_free(set);
+		return isl_basic_set_empty(dim);
+	}
+
+	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 struct isl_basic_set *uset_convex_hull_unbounded(struct isl_set *set)
+{
+	struct isl_basic_set *convex_hull = NULL;
+
+	convex_hull = isl_set_copy_basic_set(set);
+	set = isl_set_drop_basic_set(set, convex_hull);
+	if (!set)
+		goto error;
+	while (set->n > 0) {
+		struct isl_basic_set *t;
+		t = isl_set_copy_basic_set(set);
+		if (!t)
+			goto error;
+		set = isl_set_drop_basic_set(set, t);
+		if (!set)
+			goto error;
+		convex_hull = convex_hull_pair(convex_hull, t);
+		if (set->n == 0)
+			break;
+		t = isl_basic_set_lineality_space(isl_basic_set_copy(convex_hull));
+		if (!t)
+			goto error;
+		if (isl_basic_set_is_universe(t)) {
+			isl_basic_set_free(convex_hull);
+			convex_hull = t;
+			break;
+		}
+		if (t->n_eq < isl_basic_set_total_dim(t)) {
+			set = isl_set_add_basic_set(set, convex_hull);
+			return modulo_lineality(set, t);
+		}
+		isl_basic_set_free(t);
+	}
+	isl_set_free(set);
+	return convex_hull;
+error:
+	isl_set_free(set);
+	isl_basic_set_free(convex_hull);
+	return NULL;
+}
+
+/* Compute an initial hull for wrapping containing a single initial
+ * facet.
+ * This function assumes that the given set is bounded.
+ */
+static struct isl_basic_set *initial_hull(struct isl_basic_set *hull,
+	struct 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 struct isl_basic_set *common_constraints(struct isl_basic_set *hull,
+	struct 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 struct isl_basic_set *proto_hull(struct 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 struct isl_basic_set *uset_convex_hull_wrap(struct 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 struct isl_basic_set *uset_convex_hull(struct isl_set *set)
+{
+	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)
+		goto error;
+	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);
+
+	if (isl_set_is_bounded(set) &&
+	    set->ctx->opt->convex == ISL_CONVEX_HULL_WRAP)
+		return uset_convex_hull_wrap(set);
+
+	lin = uset_combined_lineality_space(isl_set_copy(set));
+	if (!lin)
+		goto error;
+	if (isl_basic_set_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 struct isl_basic_set *uset_convex_hull_wrap_bounded(struct 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 struct isl_basic_set *modulo_affine_hull(
+	struct isl_set *set, struct 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_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.
+ */
+struct isl_basic_map *isl_map_convex_hull(struct 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(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 (struct isl_basic_set *)
+		isl_map_convex_hull((struct isl_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 (isl_basic_set *)isl_map_polyhedral_hull((isl_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,
+				struct 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(struct 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, struct 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;
+}
+
+/* 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.
+ * 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 and if so directly update
+ * the inequality accordingly.
+ */
+static struct isl_basic_set *add_bound(struct isl_basic_set *hull,
+	struct sh_data *data, struct 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);
+
+	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, neg;
+		isl_int *ineq_j;
+		entry = isl_hash_table_find(hull->ctx, data->p[j].table,
+						c_hash, has_ineq, &v, 0);
+		if (entry) {
+			ineq_j = entry->data;
+			neg = isl_seq_is_neg(ineq_j + 1,
+					     hull->ineq[k] + 1, v.len);
+			if (neg)
+				isl_int_neg(ineq_j[0], ineq_j[0]);
+			if (isl_int_gt(ineq_j[0], hull->ineq[k][0]))
+				isl_int_set(hull->ineq[k][0], ineq_j[0]);
+			if (neg)
+				isl_int_neg(ineq_j[0], ineq_j[0]);
+			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 struct isl_basic_set *add_bounds(struct isl_basic_set *bset,
+	struct sh_data *data, struct 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.
+ * Translation is only allowed if "shift" is set.
+ */
+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;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return replace_map_by_empty_basic_map(map);
+	if (map->n == 1) {
+		hull = isl_basic_map_copy(map->p[0]);
+		isl_map_free(map);
+		return hull;
+	}
+
+	map = isl_map_detect_equalities(map);
+	affine_hull = isl_map_affine_hull(isl_map_copy(map));
+	map = isl_map_align_divs(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)
+		return NULL;
+	ISL_F_SET(hull, ISL_BASIC_MAP_NO_IMPLICIT);
+	ISL_F_SET(hull, ISL_BASIC_MAP_ALL_EQUALITIES);
+
+	hull = isl_basic_map_finalize(hull);
+
+	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 (struct isl_basic_set *)
+		isl_map_simple_hull((struct isl_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);
+}
+
+/* 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_set_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.
+ */
+struct isl_basic_set *isl_set_bounded_simple_hull(struct 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);
+	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..9588034
--- /dev/null
+++ b/final/lib/External/isl/isl_ctx.c
@@ -0,0 +1,334 @@
+/*
+ * 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))
+
+/* 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..102b8e8
--- /dev/null
+++ b/final/lib/External/isl/isl_dim_map.c
@@ -0,0 +1,233 @@
+/*
+ * 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, unsigned dst_stride,
+	unsigned src_pos, unsigned 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;
+
+	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..0f988c3
--- /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>
+
+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, unsigned dst_stride,
+	unsigned src_pos, unsigned 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..44cf8f0
--- /dev/null
+++ b/final/lib/External/isl/isl_equalities.c
@@ -0,0 +1,782 @@
+/*
+ * 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.
+ */
+struct isl_mat *isl_mat_parameter_compression(
+			struct isl_mat *B, struct 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);
+}
+
+/* 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].
+ * 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
+ *
+ *		H1 x1' - c = 0   or   x1' = H1^{-1} c = c'
+ *
+ * If any of the c' is non-integer, then the original set has no
+ * integer solutions (since the x' are a unimodular transformation
+ * of the x) and a zero-column matrix is returned.
+ * Otherwise, the transformation is given by
+ *
+ *		x = U1 H1^{-1} c + U2 x2'
+ *
+ * The inverse transformation is simply
+ *
+ *		x2' = Q2 x
+ */
+__isl_give isl_mat *isl_mat_variable_compression(__isl_take isl_mat *B,
+	__isl_give isl_mat **T2)
+{
+	int i;
+	struct isl_mat *H = NULL, *C = NULL, *H1, *U = NULL, *U1, *U2, *TC;
+	unsigned dim;
+
+	if (T2)
+		*T2 = NULL;
+	if (!B)
+		goto error;
+
+	dim = B->n_col - 1;
+	H = isl_mat_sub_alloc(B, 0, B->n_row, 1, dim);
+	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_lin_to_aff(*T2);
+		if (!*T2)
+			goto error;
+	}
+	C = isl_mat_alloc(B->ctx, 1+B->n_row, 1);
+	if (!C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	isl_mat_sub_neg(C->ctx, C->row+1, B->row, B->n_row, 0, 0, 1);
+	H1 = isl_mat_sub_alloc(H, 0, H->n_row, 0, H->n_row);
+	H1 = isl_mat_lin_to_aff(H1);
+	TC = isl_mat_inverse_product(H1, C);
+	if (!TC)
+		goto error;
+	isl_mat_free(H);
+	if (!isl_int_is_one(TC->row[0][0])) {
+		for (i = 0; i < B->n_row; ++i) {
+			if (!isl_int_is_divisible_by(TC->row[1+i][0], TC->row[0][0])) {
+				struct isl_ctx *ctx = B->ctx;
+				isl_mat_free(B);
+				isl_mat_free(TC);
+				isl_mat_free(U);
+				if (T2) {
+					isl_mat_free(*T2);
+					*T2 = NULL;
+				}
+				return isl_mat_alloc(ctx, 1 + dim, 0);
+			}
+			isl_seq_scale_down(TC->row[1+i], TC->row[1+i], TC->row[0][0], 1);
+		}
+		isl_int_set_si(TC->row[0][0], 1);
+	}
+	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);
+	TC = isl_mat_product(U1, TC);
+	TC = isl_mat_aff_direct_sum(TC, U2);
+
+	isl_mat_free(B);
+
+	return TC;
+error:
+	isl_mat_free(B);
+	isl_mat_free(H);
+	isl_mat_free(U);
+	if (T2) {
+		isl_mat_free(*T2);
+		*T2 = NULL;
+	}
+	return NULL;
+}
+
+/* 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 bset;
+
+	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;
+		}
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	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 bset;
+	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.
+ */
+int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
+	int pos, isl_int *modulo, isl_int *residue)
+{
+	struct isl_ctx *ctx;
+	struct isl_mat *H = NULL, *U = NULL, *C, *H1, *U1;
+	unsigned total;
+	unsigned nparam;
+
+	if (!bset || !modulo || !residue)
+		return -1;
+
+	if (isl_basic_set_plain_dim_is_fixed(bset, pos, residue)) {
+		isl_int_set_si(*modulo, 0);
+		return 0;
+	}
+
+	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 -1;
+
+	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 0;
+	}
+
+	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 -1;
+	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 0;
+	}
+	isl_int_divexact(*residue, C->row[1][0], C->row[0][0]);
+	isl_int_fdiv_r(*residue, *residue, *modulo);
+	isl_mat_free(C);
+	return 0;
+error:
+	isl_mat_free(H);
+	isl_mat_free(U);
+	return -1;
+}
+
+/* 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.
+ */
+int isl_set_dim_residue_class(struct isl_set *set,
+	int pos, isl_int *modulo, isl_int *residue)
+{
+	isl_int m;
+	isl_int r;
+	int i;
+
+	if (!set || !modulo || !residue)
+		return -1;
+
+	if (set->n == 0) {
+		isl_int_set_si(*modulo, 0);
+		isl_int_set_si(*residue, 0);
+		return 0;
+	}
+
+	if (isl_basic_set_dim_residue_class(set->p[0], pos, modulo, residue)<0)
+		return -1;
+
+	if (set->n == 1)
+		return 0;
+
+	if (isl_int_is_one(*modulo))
+		return 0;
+
+	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 0;
+error:
+	isl_int_clear(m);
+	isl_int_clear(r);
+	return -1;
+}
+
+/* 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..0206cd1
--- /dev/null
+++ b/final/lib/External/isl/isl_equalities.h
@@ -0,0 +1,33 @@
+/*
+ * 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_variable_compression(__isl_take isl_mat *B,
+	__isl_give isl_mat **T2);
+struct isl_mat *isl_mat_parameter_compression(
+			struct isl_mat *B, struct 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..4687b9c
--- /dev/null
+++ b/final/lib/External/isl/isl_factorization.h
@@ -0,0 +1,29 @@
+#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
diff --git a/final/lib/External/isl/isl_farkas.c b/final/lib/External/isl/isl_farkas.c
new file mode 100644
index 0000000..dddb49a
--- /dev/null
+++ b/final/lib/External/isl/isl_farkas.c
@@ -0,0 +1,403 @@
+/*
+ * 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);
+	isl_basic_set_simplify(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;
+}
+
+/* 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..5034c28
--- /dev/null
+++ b/final/lib/External/isl/isl_flow.c
@@ -0,0 +1,2430 @@
+/*
+ * 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>
+
+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;
+};
+
+/* 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
+ * 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.
+ *
+ * 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_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;
+}
+
+/* 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.
+ */
+static int access_sort_cmp(const void *p1, const void *p2, void *user)
+{
+	isl_access_info *acc = user;
+	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 % 2)
+		return -1;
+
+	level2 = acc->level_before(i2->data, i1->data);
+	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;
+}
+
+/* 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)
+{
+	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, acc) < 0)
+		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)
+{
+	if (isl_space_match(left, isl_dim_param, right, isl_dim_param))
+		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);
+}
+
+/* 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.
+ */
+static int 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 0;
+
+	for (k = j - 1; k >= 0; --k) {
+		int plevel, plevel2;
+		plevel = acc->level_before(acc->source[k].data, acc->sink.data);
+		if (!can_precede_at_level(plevel, sink_level))
+			continue;
+
+		plevel2 = acc->level_before(acc->source[j].data,
+						acc->source[k].data);
+
+		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 0;
+}
+
+/* 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 the all iteration 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);
+
+		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;
+}
+
+/* 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);
+		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;
+}
+
+/* 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, we also consider the may accesses.
+ * 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_alloc_array(ctx, struct isl_map *, acc->n_must);
+	may_rel = isl_alloc_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 (!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;
+
+			intermediate_sources(acc, must_rel, j, level);
+
+			T = last_source(acc, maydo, j, level, &rest);
+			may_rel[j] = isl_map_union_disjoint(may_rel[j], T);
+			maydo = rest;
+
+			intermediate_sources(acc, may_rel, j, level);
+
+			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 (!can_precede_at_level(plevel, level))
+				continue;
+
+			intermediate_sources(acc, must_rel, j, level);
+			intermediate_sources(acc, may_rel, j, level);
+		}
+
+		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 (!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:
+	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.  After the computation is finished, these extra dimensions are
+ * projected out again.
+ */
+__isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc)
+{
+	int j;
+	struct isl_flow *res = NULL;
+
+	if (!acc)
+		return NULL;
+
+	acc->domain_map = isl_map_domain_map(isl_map_copy(acc->sink.map));
+	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);
+	}
+	if (!res)
+		goto error;
+
+	for (j = 0; j < res->n_source; ++j) {
+		res->dep[j].map = isl_map_apply_range(res->dep[j].map,
+					isl_map_copy(acc->domain_map));
+		if (!res->dep[j].map)
+			goto error;
+	}
+	if (!res->must_no_source || !res->may_no_source)
+		goto error;
+
+	isl_access_info_free(acc);
+	return res;
+error:
+	isl_access_info_free(acc);
+	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;
+}
+
+/* This structure represents the input for a dependence analysis computation.
+ *
+ * "sink" represents the sink accesses.
+ * "must_source" represents the definite source accesses.
+ * "may_source" represents the possible source accesses.
+ *
+ * "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 *sink;
+	isl_union_map *must_source;
+	isl_union_map *may_source;
+
+	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)
+{
+	if (!access)
+		return NULL;
+
+	isl_union_map_free(access->sink);
+	isl_union_map_free(access->must_source);
+	isl_union_map_free(access->may_source);
+	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)
+{
+	return access ? isl_union_map_get_ctx(access->sink) : NULL;
+}
+
+/* Create a new isl_union_access_info with the given sink accesses and
+ * and no source accesses or schedule information.
+ *
+ * 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.
+ */
+__isl_give isl_union_access_info *isl_union_access_info_from_sink(
+	__isl_take isl_union_map *sink)
+{
+	isl_ctx *ctx;
+	isl_space *space;
+	isl_union_map *empty;
+	isl_union_access_info *access;
+
+	if (!sink)
+		return NULL;
+	ctx = isl_union_map_get_ctx(sink);
+	access = isl_alloc_type(ctx, isl_union_access_info);
+	if (!access)
+		goto error;
+
+	space = isl_union_map_get_space(sink);
+	empty = isl_union_map_empty(isl_space_copy(space));
+	access->sink = sink;
+	access->must_source = isl_union_map_copy(empty);
+	access->may_source = empty;
+	access->schedule = isl_schedule_empty(space);
+	access->schedule_map = NULL;
+
+	if (!access->sink || !access->must_source ||
+	    !access->may_source || !access->schedule)
+		return isl_union_access_info_free(access);
+
+	return access;
+error:
+	isl_union_map_free(sink);
+	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)
+{
+	if (!access || !must_source)
+		goto error;
+
+	isl_union_map_free(access->must_source);
+	access->must_source = must_source;
+
+	return access;
+error:
+	isl_union_access_info_free(access);
+	isl_union_map_free(must_source);
+	return NULL;
+}
+
+/* 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)
+{
+	if (!access || !may_source)
+		goto error;
+
+	isl_union_map_free(access->may_source);
+	access->may_source = may_source;
+
+	return access;
+error:
+	isl_union_access_info_free(access);
+	isl_union_map_free(may_source);
+	return NULL;
+}
+
+/* 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;
+
+	if (!access)
+		return NULL;
+	copy = isl_union_access_info_from_sink(
+				isl_union_map_copy(access->sink));
+	copy = isl_union_access_info_set_must_source(copy,
+				isl_union_map_copy(access->must_source));
+	copy = isl_union_access_info_set_may_source(copy,
+				isl_union_map_copy(access->may_source));
+	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;
+}
+
+/* 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;
+
+	if (!access)
+		return NULL;
+
+	space = isl_union_map_get_space(access->sink);
+	space = isl_space_align_params(space,
+				isl_union_map_get_space(access->must_source));
+	space = isl_space_align_params(space,
+				isl_union_map_get_space(access->may_source));
+	if (access->schedule_map)
+		space = isl_space_align_params(space,
+				isl_union_map_get_space(access->schedule_map));
+	access->sink = isl_union_map_align_params(access->sink,
+							isl_space_copy(space));
+	access->must_source = isl_union_map_align_params(access->must_source,
+							isl_space_copy(space));
+	access->may_source = isl_union_map_align_params(access->may_source,
+							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);
+	}
+
+	if (!access->sink || !access->must_source || !access->may_source)
+		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;
+
+	if (!access)
+		return NULL;
+
+	sm = isl_union_map_reverse(access->schedule_map);
+	sm = isl_union_map_range_map(sm);
+	access->sink = isl_union_map_apply_range(isl_union_map_copy(sm),
+						access->sink);
+	access->may_source = isl_union_map_apply_range(isl_union_map_copy(sm),
+						access->may_source);
+	access->must_source = isl_union_map_apply_range(isl_union_map_copy(sm),
+						access->must_source);
+	access->schedule_map = sm;
+
+	if (!access->sink || !access->must_source ||
+	    !access->may_source || !access->schedule_map)
+		return isl_union_access_info_free(access);
+
+	return access;
+}
+
+/* This structure epresents the result of a dependence analysis computation.
+ *
+ * "must_dep" represents the definite dependences.
+ * "may_dep" represents the non-definite dependences.
+ * "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 definite dependences in "flow".
+ */
+__isl_give isl_union_map *isl_union_flow_get_must_dependence(
+	__isl_keep isl_union_flow *flow)
+{
+	if (!flow)
+		return NULL;
+	return isl_union_map_copy(flow->must_dep);
+}
+
+/* Return the possible dependences in "flow", including the definite
+ * dependences.
+ */
+__isl_give isl_union_map *isl_union_flow_get_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 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;
+}
+
+/* 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.
+ */
+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_factor_range(flow->must_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;
+}
+
+/* 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.
+ */
+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->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 = isl_access_info_compute_flow(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;
+}
+
+/* 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->may_source = isl_union_map_subtract(access->may_source,
+				    isl_union_map_copy(access->must_source));
+	if (!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;
+
+	access = isl_union_access_info_align_params(access);
+	access = isl_union_access_info_introduce_schedule(access);
+	if (!access)
+		return NULL;
+
+	data.must_source = access->must_source;
+	data.may_source = access->may_source;
+
+	data.flow = isl_union_flow_alloc(isl_union_map_get_space(access->sink));
+
+	if (isl_union_map_foreach_map(access->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->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->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->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.
+ *
+ * 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_union_map(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->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->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->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;
+}
+
+/* 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".
+ */
+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);
+	access = add_matching_sources(access, sink, data);
+
+	flow = isl_access_info_compute_flow(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_factor_range(isl_map_copy(flow->dep[i].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.
+ *
+ * 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 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_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;
+
+	flow = isl_union_flow_alloc(isl_union_map_get_space(access->sink));
+
+	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.
+ *
+ * We check whether the schedule is available as a schedule tree
+ * or a schedule map and call the correpsonding function to perform
+ * the analysis.
+ */
+__isl_give isl_union_flow *isl_union_access_info_compute_flow(
+	__isl_take isl_union_access_info *access)
+{
+	access = isl_union_access_info_normalize(access);
+	if (!access)
+		return NULL;
+	if (access->schedule)
+		return compute_flow_schedule(access);
+	else
+		return compute_flow_union_map(access);
+}
+
+/* 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..a7f088a
--- /dev/null
+++ b/final/lib/External/isl/isl_fold.c
@@ -0,0 +1,1753 @@
+/*
+ * 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;
+}
+
+__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 = type == isl_dim_in ? isl_dim_set : 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 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_templ.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)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	u = isl_union_pw_qpolynomial_fold_cow(u);
+
+	if (!part || !u)
+		goto error;
+
+	isl_assert(u->space->ctx,
+	    isl_space_match(part->dim, isl_dim_param, u->space, isl_dim_param),
+	    goto error);
+
+	hash = isl_space_get_hash(part->dim);
+	entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
+			&isl_union_pw_qpolynomial_fold_has_same_domain_space,
+			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);
+}
+
+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;
+
+	if (n == 0)
+		return fold;
+
+	fold = isl_qpolynomial_fold_cow(fold);
+	if (!fold)
+		return NULL;
+
+	fold->dim = isl_space_move_dims(fold->dim, dst_type, dst_pos,
+						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_ctx *ctx;
+	isl_pw_qpolynomial_fold *pwf;
+	isl_union_pw_qpolynomial_fold **upwf;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	upwf = (isl_union_pw_qpolynomial_fold **)user;
+
+	ctx = pwqp->dim->ctx;
+	hash = isl_space_get_hash(pwqp->dim);
+	entry = isl_hash_table_find(ctx, &(*upwf)->table, hash,
+			 &isl_union_pw_qpolynomial_fold_has_same_domain_space,
+			 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)) {
+			isl_pw_qpolynomial_fold_free(entry->data);
+			isl_hash_table_remove(ctx, &(*upwf)->table, 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 int join_compatible(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2)
+{
+	int m;
+	m = isl_space_match(dim1, isl_dim_param, dim2, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(dim1, isl_dim_out, dim2, 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;
+	int 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)
+		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;
+	int 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) {
+		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..cd444d1
--- /dev/null
+++ b/final/lib/External/isl/isl_hash.c
@@ -0,0 +1,228 @@
+/*
+ * 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.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);
+}
+
+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_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_hmap_templ.c b/final/lib/External/isl/isl_hmap_templ.c
new file mode 100644
index 0000000..c6a6747
--- /dev/null
+++ b/final/lib/External/isl/isl_hmap_templ.c
@@ -0,0 +1,389 @@
+/*
+ * 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 xCAT(A,B) A ## B
+#define CAT(A,B) xCAT(A,B)
+#define KEY CAT(isl_,KEY_BASE)
+#define VAL CAT(isl_,VAL_BASE)
+#define xFN(TYPE,NAME) TYPE ## _ ## NAME
+#define FN(TYPE,NAME) xFN(TYPE,NAME)
+#define xHMAP(KEY,VAL_BASE) KEY ## _to_ ## VAL_BASE
+#define yHMAP(KEY,VAL_BASE) xHMAP(KEY,VAL_BASE)
+#define HMAP yHMAP(KEY,VAL_BASE)
+#define HMAP_BASE yHMAP(KEY_BASE,VAL_BASE)
+#define xS(TYPE1,TYPE2,NAME) struct isl_ ## TYPE1 ## _ ## TYPE2 ## _ ## NAME
+#define yS(TYPE1,TYPE2,NAME) xS(TYPE1,TYPE2,NAME)
+#define S(NAME) yS(KEY_BASE,VAL_BASE,NAME)
+
+struct HMAP {
+	int ref;
+	isl_ctx *ctx;
+	struct isl_hash_table table;
+};
+
+S(pair) {
+	KEY *key;
+	VAL *val;
+};
+
+__isl_give HMAP *FN(HMAP,alloc)(isl_ctx *ctx, int min_size)
+{
+	HMAP *hmap;
+
+	hmap = isl_calloc_type(ctx, 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 FN(HMAP,free)(hmap);
+
+	return hmap;
+}
+
+static isl_stat free_pair(void **entry, void *user)
+{
+	S(pair) *pair = *entry;
+	FN(KEY,free)(pair->key);
+	FN(VAL,free)(pair->val);
+	free(pair);
+	*entry = NULL;
+	return isl_stat_ok;
+}
+
+__isl_null HMAP *FN(HMAP,free)(__isl_take 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 *FN(HMAP,get_ctx)(__isl_keep 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 KEY *key, __isl_take VAL *val,
+	void *user)
+{
+	HMAP **hmap = (HMAP **) user;
+
+	*hmap = FN(HMAP,set)(*hmap, key, val);
+
+	if (!*hmap)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+__isl_give HMAP *FN(HMAP,dup)(__isl_keep HMAP *hmap)
+{
+	HMAP *dup;
+
+	if (!hmap)
+		return NULL;
+
+	dup = FN(HMAP,alloc)(hmap->ctx, hmap->table.n);
+	if (FN(HMAP,foreach)(hmap, &add_key_val, &dup) < 0)
+		return FN(HMAP,free)(dup);
+
+	return dup;
+}
+
+__isl_give HMAP *FN(HMAP,cow)(__isl_take HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+
+	if (hmap->ref == 1)
+		return hmap;
+	hmap->ref--;
+	return FN(HMAP,dup)(hmap);
+}
+
+__isl_give HMAP *FN(HMAP,copy)(__isl_keep HMAP *hmap)
+{
+	if (!hmap)
+		return NULL;
+
+	hmap->ref++;
+	return hmap;
+}
+
+static int has_key(const void *entry, const void *c_key)
+{
+	const S(pair) *pair = entry;
+	KEY *key = (KEY *) c_key;
+
+	return KEY_EQUAL(pair->key, key);
+}
+
+isl_bool FN(HMAP,has)(__isl_keep HMAP *hmap, __isl_keep KEY *key)
+{
+	uint32_t hash;
+
+	if (!hmap)
+		return isl_bool_error;
+
+	hash = FN(KEY,get_hash)(key);
+	return !!isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+}
+
+__isl_give VAL *FN(HMAP,get)(__isl_keep HMAP *hmap, __isl_take KEY *key)
+{
+	struct isl_hash_table_entry *entry;
+	S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key)
+		goto error;
+
+	hash = FN(KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	FN(KEY,free)(key);
+
+	if (!entry)
+		return NULL;
+
+	pair = entry->data;
+
+	return FN(VAL,copy)(pair->val);
+error:
+	FN(KEY,free)(key);
+	return NULL;
+}
+
+/* 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 HMAP *FN(HMAP,drop)(__isl_take HMAP *hmap, __isl_take KEY *key)
+{
+	struct isl_hash_table_entry *entry;
+	S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key)
+		goto error;
+
+	hash = FN(KEY,get_hash)(key);
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	if (!entry) {
+		FN(KEY,free)(key);
+		return hmap;
+	}
+
+	hmap = FN(HMAP,cow)(hmap);
+	if (!hmap)
+		goto error;
+	entry = isl_hash_table_find(hmap->ctx, &hmap->table, hash,
+					&has_key, key, 0);
+	FN(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);
+	FN(KEY,free)(pair->key);
+	FN(VAL,free)(pair->val);
+	free(pair);
+
+	return hmap;
+error:
+	FN(KEY,free)(key);
+	FN(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 HMAP *FN(HMAP,set)(__isl_take HMAP *hmap,
+	__isl_take KEY *key, __isl_take VAL *val)
+{
+	struct isl_hash_table_entry *entry;
+	S(pair) *pair;
+	uint32_t hash;
+
+	if (!hmap || !key || !val)
+		goto error;
+
+	hash = FN(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 = VAL_EQUAL(pair->val, val);
+		if (equal < 0)
+			goto error;
+		if (equal) {
+			FN(KEY,free)(key);
+			FN(VAL,free)(val);
+			return hmap;
+		}
+	}
+
+	hmap = FN(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;
+		FN(VAL,free)(pair->val);
+		pair->val = val;
+		FN(KEY,free)(key);
+		return hmap;
+	}
+
+	pair = isl_alloc_type(hmap->ctx, S(pair));
+	if (!pair)
+		goto error;
+
+	entry->data = pair;
+	pair->key = key;
+	pair->val = val;
+	return hmap;
+error:
+	FN(KEY,free)(key);
+	FN(VAL,free)(val);
+	return FN(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.
+ */
+S(foreach_data) {
+	isl_stat (*fn)(__isl_take KEY *key, __isl_take 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)
+{
+	S(pair) *pair = *entry;
+	S(foreach_data) *data = (S(foreach_data) *) user;
+
+	return data->fn(FN(KEY,copy)(pair->key), FN(VAL,copy)(pair->val),
+			data->user);
+}
+
+/* Call "fn" on each pair of key and value in "hmap".
+ */
+isl_stat FN(HMAP,foreach)(__isl_keep HMAP *hmap,
+	isl_stat (*fn)(__isl_take KEY *key, __isl_take VAL *val, void *user),
+	void *user)
+{
+	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.
+ */
+S(print_data) {
+	isl_printer *p;
+	int first;
+};
+
+/* Print the given key-value pair to data->p.
+ */
+static isl_stat print_pair(__isl_take KEY *key, __isl_take VAL *val, void *user)
+{
+	S(print_data) *data = user;
+
+	if (!data->first)
+		data->p = isl_printer_print_str(data->p, ", ");
+	data->p = FN(isl_printer_print,KEY_BASE)(data->p, key);
+	data->p = isl_printer_print_str(data->p, ": ");
+	data->p = FN(isl_printer_print,VAL_BASE)(data->p, val);
+	data->first = 0;
+
+	FN(KEY,free)(key);
+	FN(VAL,free)(val);
+	return isl_stat_ok;
+}
+
+/* Print the associative array to "p".
+ */
+__isl_give isl_printer *FN(isl_printer_print,HMAP_BASE)(
+	__isl_take isl_printer *p, __isl_keep HMAP *hmap)
+{
+	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 (FN(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 FN(HMAP,dump)(__isl_keep HMAP *hmap)
+{
+	isl_printer *printer;
+
+	if (!hmap)
+		return;
+
+	printer = isl_printer_to_file(FN(HMAP,get_ctx)(hmap), stderr);
+	printer = FN(isl_printer_print,HMAP_BASE)(printer, hmap);
+	printer = isl_printer_end_line(printer);
+
+	isl_printer_free(printer);
+}
diff --git a/final/lib/External/isl/isl_id.c b/final/lib/External/isl/isl_id.c
new file mode 100644
index 0000000..37ba6db
--- /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,
+	__isl_give 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..f8ac7f7
--- /dev/null
+++ b/final/lib/External/isl/isl_id_to_ast_expr.c
@@ -0,0 +1,11 @@
+#include <isl/id_to_ast_expr.h>
+#include <isl/ast.h>
+
+#define isl_id_is_equal(id1,id2)	id1 == id2
+
+#define KEY_BASE	id
+#define KEY_EQUAL	isl_id_is_equal
+#define VAL_BASE	ast_expr
+#define VAL_EQUAL	isl_ast_expr_is_equal
+
+#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..2fce240
--- /dev/null
+++ b/final/lib/External/isl/isl_id_to_pw_aff.c
@@ -0,0 +1,11 @@
+#include <isl/id_to_pw_aff.h>
+#include <isl/aff.h>
+
+#define isl_id_is_equal(id1,id2)	id1 == id2
+
+#define KEY_BASE	id
+#define KEY_EQUAL	isl_id_is_equal
+#define VAL_BASE	pw_aff
+#define VAL_EQUAL	isl_pw_aff_plain_is_equal
+
+#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..06e56e8
--- /dev/null
+++ b/final/lib/External/isl/isl_ilp.c
@@ -0,0 +1,642 @@
+/*
+ * 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_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 struct isl_basic_set *unit_box_base_points(struct 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 struct isl_vec *initial_solution(struct 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 struct isl_basic_set *add_bounds(struct 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 struct isl_vec *solve_ilp_search(struct isl_basic_set *bset,
+	isl_int *f, isl_int *opt, struct 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(struct isl_basic_set *bset,
+				      isl_int *f, isl_int *opt,
+				      struct 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(struct isl_basic_set *bset, int max,
+				      isl_int *f, isl_int *opt,
+				      struct 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(struct isl_basic_set *bset, int max,
+				      isl_int *f, isl_int *opt,
+				      struct 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, goto 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;
+error:
+	isl_basic_set_free(bset);
+	return isl_lp_error;
+}
+
+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_ok)
+			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;
+
+	if (!set || !obj)
+		return isl_lp_error;
+
+	if (isl_space_match(set->dim, isl_dim_param,
+			    obj->ls->dim, isl_dim_param))
+		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 "bset" 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 "bset" 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 "bset" 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);
+}
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..cffd79a
--- /dev/null
+++ b/final/lib/External/isl/isl_imath.c
@@ -0,0 +1,55 @@
+#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);
+}
diff --git a/final/lib/External/isl/isl_imath.h b/final/lib/External/isl/isl_imath.h
new file mode 100644
index 0000000..d51e03c
--- /dev/null
+++ b/final/lib/External/isl/isl_imath.h
@@ -0,0 +1,8 @@
+#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);
diff --git a/final/lib/External/isl/isl_input.c b/final/lib/External/isl/isl_input.c
new file mode 100644
index 0000000..99cf7e4
--- /dev/null
+++ b/final/lib/External/isl/isl_input.c
@@ -0,0 +1,3781 @@
+/*
+ * 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;
+		}
+		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;
+}
+
+static int is_comparator(struct isl_token *tok)
+{
+	if (!tok)
+		return 0;
+
+	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_range_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);
+}
+
+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 (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);
+}
+
+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 = NULL;
+	isl_pw_aff_list *list1 = NULL, *list2 = NULL;
+	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);
+		tok = NULL;
+		goto error;
+	}
+	for (;;) {
+		list2 = accept_affine_list(s, isl_set_get_space(set), v);
+		if (!list2)
+			goto error;
+
+		set = construct_constraints(set, tok->type, list1, list2,
+						rational);
+		isl_token_free(tok);
+		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;
+		}
+	}
+	isl_pw_aff_list_free(list1);
+
+	return isl_set_unwrap(set);
+error:
+	if (tok)
+		isl_token_free(tok);
+	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, '}')) {
+		isl_space *dim = isl_map_get_space(map);
+		isl_map_free(map);
+		return isl_map_universe(dim);
+	}
+
+	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.
+ * 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;
+
+	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;
+	}
+	if (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;
+}
+
+/* Read an isl_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_pw_multi_aff.
+ * It would be more efficient if we were to construct the isl_pw_multi_aff
+ * directly.
+ */
+__isl_give isl_pw_multi_aff *isl_stream_read_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)
+		return isl_pw_multi_aff_from_map(obj.v);
+	if (obj.type == isl_obj_set)
+		return isl_pw_multi_aff_from_set(obj.v);
+
+	obj.type->free(obj.v);
+	isl_die(s->ctx, isl_error_invalid, "unexpected object type",
+		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.
+ *
+ * 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 reading am isl_multi_pw_aff so we check
+ * that the definition of the output/set dimensions does not involve any
+ * output/set dimensions.
+ * We then 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.
+ */
+__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;
+	int dim, i, n;
+	isl_space *space, *dom_space;
+	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;
+
+	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);
+	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)
+			goto error;
+		if (isl_pw_aff_involves_dims(pa, isl_dim_in, dim, i + 1)) {
+			isl_pw_aff_free(pa);
+			isl_die(s->ctx, isl_error_invalid,
+				"not an affine expression", goto error);
+		}
+		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);
+	}
+
+	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;
+}
+
+/* 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..08f2857
--- /dev/null
+++ b/final/lib/External/isl/isl_int_gmp.h
@@ -0,0 +1,88 @@
+#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_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..e5b7186
--- /dev/null
+++ b/final/lib/External/isl/isl_int_imath.h
@@ -0,0 +1,76 @@
+#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_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)	impz_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..e4bd795
--- /dev/null
+++ b/final/lib/External/isl/isl_int_sioimath.c
@@ -0,0 +1,221 @@
+#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.
+ */
+inline 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_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..91bec90
--- /dev/null
+++ b/final/lib/External/isl/isl_int_sioimath.h
@@ -0,0 +1,1216 @@
+/*
+ * 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))
+
+/* 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 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);
+}
+
+/* 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.
+ */
+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_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;
+#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_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..aa900b9
--- /dev/null
+++ b/final/lib/External/isl/isl_list_templ.c
@@ -0,0 +1,522 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2011      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 <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;
+}
+
+__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 - 1; i >= pos; --i)
+			list->p[i + 1] = list->p[i];
+		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 (!list)
+		return NULL;
+	if (index < 0 || index >= list->n)
+		isl_die(list->ctx, isl_error_invalid,
+			"index out of bounds", 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 (index < 0 || index >= list->n)
+		isl_die(list->ctx, isl_error_invalid,
+			"index out of bounds", 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;
+}
+
+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;
+}
+
+/* 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;
+}
+
+__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;
+
+	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_space.c b/final/lib/External/isl/isl_local_space.c
new file mode 100644
index 0000000..7b3347c
--- /dev/null
+++ b/final/lib/External/isl/isl_local_space.c
@@ -0,0 +1,1380 @@
+/*
+ * 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>
+
+isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
+{
+	return ls ? ls->dim->ctx : NULL;
+}
+
+__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;
+}
+
+/* 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;
+
+	if (!ls1 || !ls2)
+		return isl_bool_error;
+
+	equal = isl_space_is_equal(ls1->dim, ls2->dim);
+	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.
+ *
+ * The order is fairly arbitrary.  We do "prefer" divs that only involve
+ * earlier dimensions in the sense that we consider local spaces where
+ * the first differing div involves earlier dimensions to be smaller.
+ */
+int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
+	__isl_keep isl_local_space *ls2)
+{
+	int i;
+	int cmp;
+	int known1, known2;
+	int last1, last2;
+	int n_col;
+
+	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;
+
+	if (ls1->div->n_row != ls2->div->n_row)
+		return ls1->div->n_row - ls2->div->n_row;
+
+	n_col = isl_mat_cols(ls1->div);
+	for (i = 0; i < ls1->div->n_row; ++i) {
+		known1 = isl_local_space_div_is_known(ls1, i);
+		known2 = isl_local_space_div_is_known(ls2, i);
+		if (!known1 && !known2)
+			continue;
+		if (!known1)
+			return 1;
+		if (!known2)
+			return -1;
+		last1 = isl_seq_last_non_zero(ls1->div->row[i] + 1, n_col - 1);
+		last2 = isl_seq_last_non_zero(ls2->div->row[i] + 1, n_col - 1);
+		if (last1 != last2)
+			return last1 - last2;
+		cmp = isl_seq_cmp(ls1->div->row[i], ls2->div->row[i], n_col);
+		if (cmp != 0)
+			return cmp;
+	}
+
+	return 0;
+}
+
+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;
+}
+
+__isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
+	int pos)
+{
+	isl_aff *aff;
+
+	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);
+
+	if (isl_int_is_zero(ls->div->row[pos][0]))
+		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);
+
+	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;
+}
+
+__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;
+	int 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_local_space_free(ls1);
+	isl_local_space_free(ls2);
+	return NULL;
+}
+
+/* Does "ls" have an explicit representation for div "div"?
+ */
+int isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
+{
+	if (!ls)
+		return -1;
+	if (div < 0 || div >= ls->div->n_row)
+		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
+			"position out of bounds", return -1);
+	return !isl_int_is_zero(ls->div->row[div][0]);
+}
+
+int isl_local_space_divs_known(__isl_keep isl_local_space *ls)
+{
+	int i;
+
+	if (!ls)
+		return -1;
+
+	for (i = 0; i < ls->div->n_row; ++i)
+		if (isl_int_is_zero(ls->div->row[i][0]))
+			return 0;
+
+	return 1;
+}
+
+__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);
+}
+
+int isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type)
+{
+	if (!ls)
+		return -1;
+	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
+ */
+int isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
+	isl_int *constraint, unsigned div)
+{
+	unsigned pos;
+
+	if (!ls)
+		return -1;
+
+	if (isl_int_is_zero(ls->div->row[div][0]))
+		return 0;
+
+	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 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    ls->div->n_row-div-1) != -1)
+			return 0;
+	} 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 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    ls->div->n_row-div-1) != -1)
+			return 0;
+	} else
+		return 0;
+
+	return 1;
+}
+
+/*
+ * 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..4d7e69f
--- /dev/null
+++ b/final/lib/External/isl/isl_local_space_private.h
@@ -0,0 +1,75 @@
+#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;
+};
+
+__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);
+int isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div);
+int 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);
+
+int isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
+	enum isl_dim_type type);
+
+__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);
+
+int 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..1d5ae6e
--- /dev/null
+++ b/final/lib/External/isl/isl_lp.c
@@ -0,0 +1,362 @@
+/*
+ * 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>
+
+enum isl_lp_result isl_tab_solve_lp(struct isl_basic_map *bmap, int maximize,
+				      isl_int *f, isl_int denom, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct 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,
+ * minmimal or maximal value returned in *opt).
+ */
+enum isl_lp_result isl_basic_map_solve_lp(struct isl_basic_map *bmap, int max,
+				      isl_int *f, isl_int d, isl_int *opt,
+				      isl_int *opt_denom,
+				      struct 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((struct isl_basic_map *)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((struct isl_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_val *res;
+
+	if (!bset || !obj)
+		return NULL;
+
+	if (isl_space_match(bset->dim, isl_dim_param,
+			    obj->ls->dim, isl_dim_param))
+		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..4898e6d
--- /dev/null
+++ b/final/lib/External/isl/isl_map.c
@@ -0,0 +1,12691 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 2010      INRIA Saclay
+ * Copyright 2012-2014 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 <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>
+
+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;
+	}
+}
+
+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 *dim = bmap->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;
+	}
+}
+
+unsigned isl_basic_set_offset(struct isl_basic_set *bset,
+					enum isl_dim_type type)
+{
+	return isl_basic_map_offset(bset, type);
+}
+
+static unsigned map_offset(struct 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(const struct 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(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->n_in : 0;
+}
+
+unsigned isl_basic_map_n_out(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->n_out : 0;
+}
+
+unsigned isl_basic_map_n_param(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->dim->nparam : 0;
+}
+
+unsigned isl_basic_map_n_div(const struct isl_basic_map *bmap)
+{
+	return bmap ? bmap->n_div : 0;
+}
+
+unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap)
+{
+	return bmap ? isl_space_dim(bmap->dim, isl_dim_all) + bmap->n_div : 0;
+}
+
+unsigned isl_map_n_in(const struct isl_map *map)
+{
+	return map ? map->dim->n_in : 0;
+}
+
+unsigned isl_map_n_out(const struct isl_map *map)
+{
+	return map ? map->dim->n_out : 0;
+}
+
+unsigned isl_map_n_param(const struct isl_map *map)
+{
+	return map ? map->dim->nparam : 0;
+}
+
+int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set)
+{
+	int m;
+	if (!map || !set)
+		return -1;
+	m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					set->dim, isl_dim_set);
+}
+
+int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset)
+{
+	int m;
+	if (!bmap || !bset)
+		return -1;
+	m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(bmap->dim, isl_dim_in,
+					bset->dim, isl_dim_set);
+}
+
+int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set)
+{
+	int m;
+	if (!map || !set)
+		return -1;
+	m = isl_space_match(map->dim, isl_dim_param, set->dim, isl_dim_param);
+	if (m < 0 || !m)
+		return m;
+	return isl_space_tuple_is_equal(map->dim, isl_dim_out,
+					set->dim, isl_dim_set);
+}
+
+int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset)
+{
+	int m;
+	if (!bmap || !bset)
+		return -1;
+	m = isl_space_match(bmap->dim, isl_dim_param, bset->dim, isl_dim_param);
+	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;
+}
+
+__isl_give isl_space *isl_basic_map_get_space(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	return isl_space_copy(bmap->dim);
+}
+
+__isl_give isl_space *isl_basic_set_get_space(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return NULL;
+	return isl_space_copy(bset->dim);
+}
+
+/* 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);
+}
+
+__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);
+		if (isl_basic_map_add_div_constraints(bmap, i) < 0)
+			goto error;
+	}
+					
+	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)
+{
+	if (!map)
+		return NULL;
+	return isl_space_copy(map->dim);
+}
+
+__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 (isl_set *)isl_map_set_tuple_name((isl_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 (isl_basic_set *)isl_basic_map_set_dim_name(
+		(isl_basic_map *)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 (isl_set *)isl_map_set_dim_name((isl_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);
+}
+
+/* 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);
+}
+
+int isl_basic_map_is_rational(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+}
+
+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.
+ */
+int isl_basic_map_has_rational(__isl_keep isl_basic_map *bmap)
+{
+	int has_rational = 1;
+	unsigned total;
+
+	if (!bmap)
+		return -1;
+	if (isl_basic_map_plain_is_empty(bmap))
+		return 0;
+	if (!isl_basic_map_is_rational(bmap))
+		return 0;
+	bmap = isl_basic_map_copy(bmap);
+	bmap = isl_basic_map_implicit_equalities(bmap);
+	if (!bmap)
+		return -1;
+	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 = 0;
+	}
+	isl_basic_map_free(bmap);
+
+	return has_rational;
+}
+
+/* Does "map" contain any rational points?
+ */
+int isl_map_has_rational(__isl_keep isl_map *map)
+{
+	int i;
+	int has_rational;
+
+	if (!map)
+		return -1;
+	for (i = 0; i < map->n; ++i) {
+		has_rational = isl_basic_map_has_rational(map->p[i]);
+		if (has_rational < 0)
+			return -1;
+		if (has_rational)
+			return 1;
+	}
+	return 0;
+}
+
+/* Does "set" contain any rational points?
+ */
+int isl_set_has_rational(__isl_keep isl_set *set)
+{
+	return isl_map_has_rational(set);
+}
+
+/* Is this basic set a parameter domain?
+ */
+int isl_basic_set_is_params(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return -1;
+	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.
+ */
+int isl_map_is_params(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	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 (struct isl_basic_set *)bmap;
+}
+
+struct 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 (struct isl_basic_set *)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);
+}
+
+struct isl_basic_map *isl_basic_map_dup(struct 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((struct isl_basic_map *)bset);
+	return (struct isl_basic_set *)dup;
+}
+
+struct isl_basic_set *isl_basic_set_copy(struct 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);
+}
+
+struct isl_set *isl_set_copy(struct isl_set *set)
+{
+	if (!set)
+		return NULL;
+
+	set->ref++;
+	return set;
+}
+
+struct isl_basic_map *isl_basic_map_copy(struct 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;
+}
+
+struct isl_map *isl_map_copy(struct 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((struct isl_basic_map *)bset);
+}
+
+static int room_for_con(struct isl_basic_map *bmap, unsigned n)
+{
+	return bmap->n_eq + bmap->n_ineq + n <= bmap->c_size;
+}
+
+__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_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+		return fn(map1, map2);
+	if (!isl_space_has_named_params(map1->dim) ||
+	    !isl_space_has_named_params(map2->dim))
+		isl_die(map1->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", 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_space_match(map1->dim, isl_dim_param, map2->dim, isl_dim_param))
+		return fn(map1, map2);
+	if (!isl_space_has_named_params(map1->dim) ||
+	    !isl_space_has_named_params(map2->dim))
+		isl_die(map1->ctx, isl_error_invalid,
+			"unaligned unnamed parameters", 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((struct isl_basic_map *)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((struct isl_basic_map *)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;
+}
+
+int isl_basic_set_drop_equality(struct isl_basic_set *bset, unsigned pos)
+{
+	return isl_basic_map_drop_equality((struct isl_basic_map *)bset, pos);
+}
+
+/* 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(struct 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(struct isl_basic_set *bset)
+{
+	return isl_basic_map_alloc_inequality((struct isl_basic_map *)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((struct isl_basic_map *)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((struct isl_basic_map *)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 (isl_basic_set *)
+		isl_basic_map_add_eq((isl_basic_map *)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 (isl_basic_set *)
+		isl_basic_map_add_ineq((isl_basic_map *)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((struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n)
+{
+	if (!bmap)
+		return -1;
+	isl_assert(bmap->ctx, n <= bmap->n_div, return -1);
+	bmap->n_div -= n;
+	return 0;
+}
+
+int isl_basic_set_free_div(struct isl_basic_set *bset, unsigned n)
+{
+	return isl_basic_map_free_div((struct isl_basic_map *)bset, n);
+}
+
+/* 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_n_param(src_map);
+	unsigned dst_nparam = isl_basic_map_n_param(dst_map);
+	unsigned src_in = isl_basic_map_n_in(src_map);
+	unsigned dst_in = isl_basic_map_n_in(dst_map);
+	unsigned src_out = isl_basic_map_n_out(src_map);
+	unsigned dst_out = isl_basic_map_n_out(dst_map);
+	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 struct isl_basic_map *add_constraints(struct isl_basic_map *bmap1,
+		struct 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 (struct isl_basic_set *)
+		add_constraints((struct isl_basic_map *)bset1,
+				(struct isl_basic_map *)bset2, 0, pos);
+}
+
+struct isl_basic_map *isl_basic_map_extend_space(struct 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;
+}
+
+struct isl_basic_set *isl_basic_set_extend_space(struct isl_basic_set *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_extend_space((struct isl_basic_map *)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 (struct isl_basic_set *)
+		isl_basic_map_extend((struct isl_basic_map *)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)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_extend_constraints((struct isl_basic_map *)base,
+						    n_eq, n_ineq);
+}
+
+struct isl_basic_set *isl_basic_set_cow(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_cow((struct isl_basic_map *)bset);
+}
+
+struct isl_basic_map *isl_basic_map_cow(struct 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;
+}
+
+struct isl_set *isl_set_cow(struct isl_set *set)
+{
+	if (!set)
+		return NULL;
+
+	if (set->ref == 1)
+		return set;
+	set->ref--;
+	return isl_set_dup(set);
+}
+
+struct isl_map *isl_map_cow(struct isl_map *map)
+{
+	if (!map)
+		return NULL;
+
+	if (map->ref == 1)
+		return 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;
+}
+
+struct isl_basic_map *isl_basic_map_set_to_empty(struct isl_basic_map *bmap)
+{
+	int i = 0;
+	unsigned total;
+	if (!bmap)
+		goto error;
+	total = isl_basic_map_total_dim(bmap);
+	isl_basic_map_free_div(bmap, bmap->n_div);
+	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;
+}
+
+struct isl_basic_set *isl_basic_set_set_to_empty(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_set_to_empty((struct isl_basic_map *)bset);
+}
+
+/* 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);
+}
+
+/* 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 (isl_set *)isl_map_eliminate((isl_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 (struct isl_basic_set *)isl_basic_map_remove_divs(
+			(struct isl_basic_map *)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);
+}
+
+struct isl_basic_map *isl_basic_map_remove_dims(struct isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	if (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+			goto error);
+	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;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* Return true if the definition of the given div (recursively) involves
+ * any of the given variables.
+ */
+static int 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 0;
+	if (isl_seq_first_non_zero(bmap->div[div] + 1 + first, n) >= 0)
+		return 1;
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+			continue;
+		if (div_involves_vars(bmap, i, first, n))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* 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 (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+			goto error);
+	first += isl_basic_map_offset(bmap, type);
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (!div_involves_vars(bmap, i, first, n))
+			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;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__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 (isl_set *)isl_map_remove_divs_involving_dims((isl_map *)set,
+							      type, first, n);
+}
+
+/* Does the desciption 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 (!bmap)
+		return isl_bool_error;
+
+	if (first + n > isl_basic_map_dim(bmap, type))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"index out of bounds", 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);
+}
+
+/* Return true if the definition of the given div is unknown or depends
+ * on unknown divs.
+ */
+static int div_is_unknown(__isl_keep isl_basic_map *bmap, int div)
+{
+	int i;
+	unsigned div_offset = isl_basic_map_offset(bmap, isl_dim_div);
+
+	if (isl_int_is_zero(bmap->div[div][0]))
+		return 1;
+
+	for (i = bmap->n_div - 1; i >= 0; --i) {
+		if (isl_int_is_zero(bmap->div[div][1 + div_offset + i]))
+			continue;
+		if (div_is_unknown(bmap, i))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* 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 (!div_is_unknown(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 (isl_set *)isl_map_remove_unknown_divs((isl_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)
+{
+	return (isl_basic_set *)
+	    isl_basic_map_remove_dims((isl_basic_map *)bset, type, first, n);
+}
+
+struct isl_map *isl_map_remove_dims(struct 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 (isl_set *)isl_map_remove_dims((isl_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_n_in(bmap);
+	unsigned dim = in + isl_basic_map_n_out(bmap);
+	unsigned nparam = isl_basic_map_n_param(bmap);
+	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((struct isl_basic_map *)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 *dim, int n,
+	unsigned flags)
+{
+	struct isl_set *set;
+
+	if (!dim)
+		return NULL;
+	isl_assert(dim->ctx, dim->n_in == 0, goto error);
+	isl_assert(dim->ctx, n >= 0, goto error);
+	set = isl_alloc(dim->ctx, struct isl_set,
+			sizeof(struct isl_set) +
+			(n - 1) * sizeof(struct isl_basic_set *));
+	if (!set)
+		goto error;
+
+	set->ctx = dim->ctx;
+	isl_ctx_ref(set->ctx);
+	set->ref = 1;
+	set->size = n;
+	set->n = 0;
+	set->dim = dim;
+	set->flags = flags;
+	return set;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_set *isl_set_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned dim, int n, unsigned flags)
+{
+	struct isl_set *set;
+	isl_space *dims;
+
+	dims = isl_space_alloc(ctx, nparam, 0, dim);
+	if (!dims)
+		return NULL;
+
+	set = isl_set_alloc_space(dims, n, flags);
+	return set;
+}
+
+/* Make sure "map" has room for at least "n" more basic maps.
+ */
+struct isl_map *isl_map_grow(struct 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 (struct isl_set *)isl_map_grow((struct isl_map *)set, n);
+}
+
+struct isl_set *isl_set_dup(struct isl_set *set)
+{
+	int i;
+	struct isl_set *dup;
+
+	if (!set)
+		return NULL;
+
+	dup = isl_set_alloc_space(isl_space_copy(set->dim), set->n, set->flags);
+	if (!dup)
+		return NULL;
+	for (i = 0; i < set->n; ++i)
+		dup = isl_set_add_basic_set(dup, isl_basic_set_copy(set->p[i]));
+	return dup;
+}
+
+struct isl_set *isl_set_from_basic_set(struct isl_basic_set *bset)
+{
+	return isl_map_from_basic_map(bset);
+}
+
+struct isl_map *isl_map_from_basic_map(struct 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 (struct isl_set *)isl_map_add_basic_map((struct isl_map *)set,
+						(struct isl_basic_map *)bset);
+}
+
+__isl_null isl_set *isl_set_free(__isl_take isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return NULL;
+
+	if (--set->ref > 0)
+		return NULL;
+
+	isl_ctx_deref(set->ctx);
+	for (i = 0; i < set->n; ++i)
+		isl_basic_set_free(set->p[i]);
+	isl_space_free(set->dim);
+	free(set);
+
+	return NULL;
+}
+
+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);
+	}
+}
+
+struct isl_basic_map *isl_basic_map_intersect_domain(
+		struct isl_basic_map *bmap, struct isl_basic_set *bset)
+{
+	struct isl_basic_map *bmap_domain;
+
+	if (!bmap || !bset)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
+					bset->dim, isl_dim_param), 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;
+}
+
+struct isl_basic_map *isl_basic_map_intersect_range(
+		struct isl_basic_map *bmap, struct isl_basic_set *bset)
+{
+	struct isl_basic_map *bmap_range;
+
+	if (!bmap || !bset)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_match(bmap->dim, isl_dim_param,
+					bset->dim, isl_dim_param), goto error);
+
+	if (isl_space_dim(bset->dim, isl_dim_set) != 0)
+		isl_assert(bset->ctx,
+		    isl_basic_map_compatible_range(bmap, bset), goto error);
+
+	if (isl_basic_set_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 = isl_basic_map_from_basic_set(bset, isl_space_copy(bset->dim));
+	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_error;
+
+	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((struct isl_basic_map *)bset, vec);
+}
+
+struct isl_basic_map *isl_basic_map_intersect(
+		struct isl_basic_map *bmap1, struct isl_basic_map *bmap2)
+{
+	struct isl_vec *sample = NULL;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
+				     bmap2->dim, isl_dim_param), 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 (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 (struct isl_basic_set *)
+		isl_basic_map_intersect(
+			(struct isl_basic_map *)bset1,
+			(struct isl_basic_map *)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);
+
+	isl_assert(map2->ctx,
+		    map2->p[0]->n_eq + map2->p[0]->n_ineq == 1, goto error);
+
+	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 (struct isl_set *)
+		isl_map_intersect((struct isl_map *)set1,
+				  (struct isl_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);
+}
+
+struct isl_basic_map *isl_basic_map_reverse(struct 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_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);
+	if (isl_basic_map_is_rational(bmap))
+		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 (isl_set *)isl_map_add_dims((isl_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)
+		return bmap;
+
+	isl_assert(bmap->ctx, src_pos + n <= isl_basic_map_dim(bmap, src_type),
+		goto error);
+
+	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)
+{
+	return (isl_basic_set *)isl_basic_map_move_dims(
+		(isl_basic_map *)bset, dst_type, dst_pos, src_type, src_pos, 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)
+{
+	if (!set)
+		return NULL;
+	isl_assert(set->ctx, dst_type != isl_dim_in, goto error);
+	return (isl_set *)isl_map_move_dims((isl_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)
+		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;
+}
+
+/* Turn the n dimensions of type type, starting at first
+ * into existentially quantified variables.
+ */
+__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)
+{
+	if (n == 0)
+		return basic_map_space_reset(bmap, type);
+
+	if (!bmap)
+		return NULL;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
+		return isl_basic_map_remove_dims(bmap, type, first, n);
+
+	isl_assert(bmap->ctx, first + n <= isl_basic_map_dim(bmap, type),
+			goto error);
+
+	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 (isl_basic_set *)isl_basic_map_project_out(
+			(isl_basic_map *)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 (isl_set *)isl_map_project_out((isl_map *)set, type, first, n);
+}
+
+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 (!bmap1 || !bmap2)
+		goto error;
+	if (!isl_space_match(bmap1->dim, isl_dim_param,
+				bmap2->dim, isl_dim_param))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"parameters don't match", 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_n_in(bmap1);
+	n_out = isl_basic_map_n_out(bmap2);
+	n = isl_basic_map_n_out(bmap1);
+	nparam = isl_basic_map_n_param(bmap1);
+
+	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 (struct isl_basic_set *)
+		isl_basic_map_apply_range((struct isl_basic_map *)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 (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx,
+	    isl_basic_map_n_in(bmap1) == isl_basic_map_n_in(bmap2), goto error);
+	isl_assert(bmap1->ctx,
+	    isl_basic_map_n_param(bmap1) == isl_basic_map_n_param(bmap2),
+	    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)
+ */
+struct isl_basic_map *isl_basic_map_sum(
+		struct isl_basic_map *bmap1, struct 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_n_param(bmap1);
+	n_in = isl_basic_map_n_in(bmap1);
+	n_out = isl_basic_map_n_out(bmap1);
+
+	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)
+ */
+struct isl_map *isl_map_sum(struct isl_map *map1, struct 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 (isl_set *)isl_map_sum((isl_map *)set1, (isl_map *)set2);
+}
+
+/* Given a basic map A -> f(A), construct A -> -f(A).
+ */
+struct isl_basic_map *isl_basic_map_neg(struct 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).
+ */
+struct isl_map *isl_map_neg(struct 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 (isl_set *)isl_map_neg((isl_map *)set);
+}
+
+/* Given a basic map A -> f(A) and an integer d, construct a basic map
+ * A -> floor(f(A)/d).
+ */
+struct isl_basic_map *isl_basic_map_floordiv(struct 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_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	n_out = isl_basic_map_n_out(bmap);
+
+	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).
+ */
+struct isl_map *isl_map_floordiv(struct 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 struct isl_basic_map *var_equal(struct 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_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	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 constraints to "bmap" expressing i_pos < o_pos
+ */
+static struct isl_basic_map *var_less(struct 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_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	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_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	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 constraints to "bmap" expressing i_pos > o_pos
+ */
+static struct isl_basic_map *var_more(struct 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_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	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_n_param(bmap);
+	n_in = isl_basic_map_n_in(bmap);
+	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 of dimension "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 pairs of sets of dimension "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 of dimension "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;
+}
+
+__isl_give isl_basic_map *isl_basic_map_from_basic_set(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim)
+{
+	struct isl_basic_map *bmap;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !dim)
+		goto error;
+
+	isl_assert(bset->ctx, isl_space_compatible(bset->dim, dim), goto error);
+	isl_space_free(bset->dim);
+	bmap = (struct isl_basic_map *) bset;
+	bmap->dim = dim;
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_set_free(bset);
+	isl_space_free(dim);
+	return NULL;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ *		f - m d >= 0
+ */
+static int 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 -1;
+	isl_seq_cpy(bmap->ineq[i], div + 1, 1 + total);
+	isl_int_neg(bmap->ineq[i][1 + pos], div[0]);
+
+	return 0;
+}
+
+/* For a div d = floor(f/m), add the constraint
+ *
+ *		-(f-(n-1)) + m d >= 0
+ */
+static int 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 -1;
+	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 0;
+}
+
+/* For a div d = floor(f/m), add the constraints
+ *
+ *		f - m d >= 0
+ *		-(f-(n-1)) + m d >= 0
+ *
+ * Note that the second constraint is the negation of
+ *
+ *		f - m d >= n
+ */
+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((isl_basic_map *)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-(n-1)) + m d >= 0
+ */
+__isl_give isl_basic_map *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);
+	}
+
+	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-(n-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]);
+}
+
+int isl_basic_set_add_div_constraints(struct isl_basic_set *bset, unsigned div)
+{
+	return isl_basic_map_add_div_constraints(bset, div);
+}
+
+struct isl_basic_set *isl_basic_map_underlying_set(
+		struct 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 (struct isl_basic_set *)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 (struct isl_basic_set *)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((isl_basic_map *)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;
+}
+
+struct isl_basic_map *isl_basic_map_overlying_set(
+	struct isl_basic_set *bset, struct 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 (isl_space_is_equal(bset->dim, like->dim) && like->n_div == 0) {
+		isl_basic_map_free(like);
+		return (struct isl_basic_map *)bset;
+	}
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		goto error;
+	total = bset->dim->n_out + bset->extra;
+	bmap = (struct isl_basic_map *)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 (struct isl_basic_set *)
+		isl_basic_map_overlying_set(bset, (struct isl_basic_map *)like);
+}
+
+struct isl_set *isl_set_from_underlying_set(
+	struct isl_set *set, struct isl_basic_set *like)
+{
+	int i;
+
+	if (!set || !like)
+		goto error;
+	isl_assert(set->ctx, set->dim->n_out == isl_basic_set_total_dim(like),
+		    goto error);
+	if (isl_space_is_equal(set->dim, like->dim) && like->n_div == 0) {
+		isl_basic_set_free(like);
+		return set;
+	}
+	set = isl_set_cow(set);
+	if (!set)
+		goto error;
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_from_underlying_set(set->p[i],
+						      isl_basic_set_copy(like));
+		if (!set->p[i])
+			goto error;
+	}
+	isl_space_free(set->dim);
+	set->dim = isl_space_copy(like->dim);
+	if (!set->dim)
+		goto error;
+	isl_basic_set_free(like);
+	return set;
+error:
+	isl_basic_set_free(like);
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_set *isl_map_underlying_set(struct 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] = (struct isl_basic_map *)
+				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 (struct isl_set *)map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_to_underlying_set(struct isl_set *set)
+{
+	return (struct isl_set *)isl_map_underlying_set((struct isl_map *)set);
+}
+
+__isl_give isl_basic_map *isl_basic_map_reset_space(
+	__isl_take isl_basic_map *bmap, __isl_take isl_space *dim)
+{
+	bmap = isl_basic_map_cow(bmap);
+	if (!bmap || !dim)
+		goto error;
+
+	isl_space_free(bmap->dim);
+	bmap->dim = dim;
+
+	bmap = isl_basic_map_finalize(bmap);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_basic_set *isl_basic_set_reset_space(
+	__isl_take isl_basic_set *bset, __isl_take isl_space *dim)
+{
+	return (isl_basic_set *)isl_basic_map_reset_space((isl_basic_map *)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 (struct isl_set *) isl_map_reset_space((struct isl_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_space *space;
+	unsigned n;
+
+	if (isl_basic_set_is_params(bset))
+		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_n_out(bmap);
+	bmap = isl_basic_map_project_out(bmap, isl_dim_out, 0, n_out);
+
+	return isl_basic_map_reset_space(bmap, space);
+}
+
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	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.
+ */
+int isl_basic_map_is_set(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	return isl_space_is_set(bmap->dim);
+}
+
+struct isl_basic_set *isl_basic_map_range(struct isl_basic_map *bmap)
+{
+	if (!bmap)
+		return NULL;
+	if (isl_basic_map_is_set(bmap))
+		return bmap;
+	return isl_basic_map_domain(isl_basic_map_reverse(bmap));
+}
+
+__isl_give isl_basic_map *isl_basic_map_domain_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, k;
+	isl_space *dim;
+	isl_basic_map *domain;
+	int nparam, n_in, n_out;
+	unsigned total;
+
+	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);
+
+	total = isl_basic_map_total_dim(bmap);
+
+	for (i = 0; i < n_in; ++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_in + n_out + i], 1);
+	}
+
+	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_range_map(
+	__isl_take isl_basic_map *bmap)
+{
+	int i, k;
+	isl_space *dim;
+	isl_basic_map *range;
+	int nparam, n_in, n_out;
+	unsigned total;
+
+	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);
+
+	total = isl_basic_map_total_dim(bmap);
+
+	for (i = 0; i < n_out; ++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 + n_in + i], -1);
+		isl_int_set_si(bmap->eq[k][1 + nparam + n_in + n_out + i], 1);
+	}
+
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	return isl_basic_map_finalize(bmap);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+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.
+ */
+int isl_map_is_set(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	return isl_space_is_set(map->dim);
+}
+
+struct isl_set *isl_map_range(struct isl_map *map)
+{
+	int i;
+	struct isl_set *set;
+
+	if (!map)
+		goto error;
+	if (isl_map_is_set(map))
+		return (isl_set *)map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		goto error;
+
+	set = (struct isl_set *) 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_map *isl_map_from_set(__isl_take isl_set *set,
+	__isl_take isl_space *dim)
+{
+	int i;
+	struct isl_map *map = NULL;
+
+	set = isl_set_cow(set);
+	if (!set || !dim)
+		goto error;
+	isl_assert(set->ctx, isl_space_compatible(set->dim, dim), goto error);
+	map = (struct isl_map *)set;
+	for (i = 0; i < set->n; ++i) {
+		map->p[i] = isl_basic_map_from_basic_set(
+				set->p[i], isl_space_copy(dim));
+		if (!map->p[i])
+			goto error;
+	}
+	isl_space_free(map->dim);
+	map->dim = dim;
+	return map;
+error:
+	isl_space_free(dim);
+	isl_set_free(set);
+	return NULL;
+}
+
+__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 (isl_basic_map *)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 (struct isl_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);
+}
+
+__isl_give isl_map *isl_map_alloc_space(__isl_take isl_space *dim, int n,
+	unsigned flags)
+{
+	struct isl_map *map;
+
+	if (!dim)
+		return NULL;
+	if (n < 0)
+		isl_die(dim->ctx, isl_error_internal,
+			"negative number of basic maps", goto error);
+	map = isl_alloc(dim->ctx, struct isl_map,
+			sizeof(struct isl_map) +
+			(n - 1) * sizeof(struct isl_basic_map *));
+	if (!map)
+		goto error;
+
+	map->ctx = dim->ctx;
+	isl_ctx_ref(map->ctx);
+	map->ref = 1;
+	map->size = n;
+	map->n = 0;
+	map->dim = dim;
+	map->flags = flags;
+	return map;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+struct isl_map *isl_map_alloc(struct isl_ctx *ctx,
+		unsigned nparam, unsigned in, unsigned out, int n,
+		unsigned flags)
+{
+	struct isl_map *map;
+	isl_space *dims;
+
+	dims = isl_space_alloc(ctx, nparam, in, out);
+	if (!dims)
+		return NULL;
+
+	map = isl_map_alloc_space(dims, n, flags);
+	return map;
+}
+
+__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;
+
+	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;
+}
+
+struct isl_basic_map *isl_basic_map_fix_si(struct isl_basic_map *bmap,
+		enum isl_dim_type type, unsigned pos, int value)
+{
+	if (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+	return isl_basic_map_fix_pos_si(bmap,
+		isl_basic_map_offset(bmap, type) + pos, value);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__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 (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+	return isl_basic_map_fix_pos(bmap,
+		isl_basic_map_offset(bmap, type) + pos, value);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* 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 (pos >= isl_basic_map_dim(bmap, type))
+		isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,
+			"index out of bounds", 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 (struct isl_basic_set *)
+		isl_basic_map_fix_si((struct isl_basic_map *)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 (struct isl_basic_set *)
+		isl_basic_map_fix((struct isl_basic_map *)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 (struct isl_basic_set *)
+		isl_basic_map_fix_si((struct isl_basic_map *)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;
+}
+
+struct isl_map *isl_map_fix_si(struct 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 (struct isl_set *)
+		isl_map_fix_si((struct isl_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 (struct isl_set *)isl_map_fix((isl_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 (struct isl_set *)
+		isl_map_fix_si((struct isl_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 (!bmap)
+		return NULL;
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type), goto error);
+	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);
+}
+
+struct isl_basic_set *isl_basic_set_lower_bound_dim(struct isl_basic_set *bset,
+	unsigned dim, isl_int value)
+{
+	int j;
+
+	bset = isl_basic_set_cow(bset);
+	bset = isl_basic_set_extend_constraints(bset, 0, 1);
+	j = isl_basic_set_alloc_inequality(bset);
+	if (j < 0)
+		goto error;
+	isl_seq_clr(bset->ineq[j], 1 + isl_basic_set_total_dim(bset));
+	isl_int_set_si(bset->ineq[j][1 + isl_basic_set_n_param(bset) + dim], 1);
+	isl_int_neg(bset->ineq[j][0], value);
+	bset = isl_basic_set_simplify(bset);
+	return isl_basic_set_finalize(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+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 (struct isl_set *)
+		isl_map_lower_bound_si((struct isl_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 (!bmap)
+		return NULL;
+	if (pos >= isl_basic_map_dim(bmap, type))
+		isl_die(bmap->ctx, isl_error_invalid,
+			"index out of bounds", goto error);
+	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;
+}
+
+struct isl_set *isl_set_lower_bound_dim(struct isl_set *set, unsigned dim,
+					isl_int value)
+{
+	int i;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	isl_assert(set->ctx, dim < isl_set_n_dim(set), goto error);
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_lower_bound_dim(set->p[i], dim, value);
+		if (!set->p[i])
+			goto error;
+	}
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_map *isl_map_reverse(struct 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;
+}
+
+static struct isl_map *isl_basic_map_partial_lexopt(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty, int max)
+{
+	return isl_tab_basic_map_partial_lexopt(bmap, dom, empty, max);
+}
+
+struct isl_map *isl_basic_map_partial_lexmax(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return isl_basic_map_partial_lexopt(bmap, dom, empty, 1);
+}
+
+struct isl_map *isl_basic_map_partial_lexmin(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return isl_basic_map_partial_lexopt(bmap, dom, empty, 0);
+}
+
+struct isl_set *isl_basic_set_partial_lexmin(
+		struct isl_basic_set *bset, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return (struct isl_set *)
+		isl_basic_map_partial_lexmin((struct isl_basic_map *)bset,
+			dom, empty);
+}
+
+struct isl_set *isl_basic_set_partial_lexmax(
+		struct isl_basic_set *bset, struct isl_basic_set *dom,
+		struct isl_set **empty)
+{
+	return (struct isl_set *)
+		isl_basic_map_partial_lexmax((struct isl_basic_map *)bset,
+			dom, empty);
+}
+
+__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)
+{
+	return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 0);
+}
+
+__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)
+{
+	return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, empty, 1);
+}
+
+__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)
+{
+	return isl_basic_map_partial_lexmin_pw_multi_aff(bset, dom, 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)
+{
+	return isl_basic_map_partial_lexmax_pw_multi_aff(bset, dom, empty);
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexopt_pw_multi_aff(
+	__isl_take isl_basic_map *bmap, int max)
+{
+	isl_basic_set *dom = NULL;
+	isl_space *dom_space;
+
+	if (!bmap)
+		goto error;
+	dom_space = isl_space_domain(isl_space_copy(bmap->dim));
+	dom = isl_basic_set_universe(dom_space);
+	return isl_basic_map_partial_lexopt_pw_multi_aff(bmap, dom, NULL, max);
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_pw_multi_aff *isl_basic_map_lexmin_pw_multi_aff(
+	__isl_take isl_basic_map *bmap)
+{
+	return isl_basic_map_lexopt_pw_multi_aff(bmap, 0);
+}
+
+#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.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * 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".
+ */
+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, int max)
+{
+	int i;
+	isl_pw_multi_aff *res;
+	isl_set *todo;
+
+	if (!map || !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), &todo, max);
+
+	for (i = 1; i < map->n; ++i) {
+		isl_pw_multi_aff *res_i;
+		isl_set *todo_i;
+
+		res_i = basic_map_partial_lexopt_pw_multi_aff(
+					    isl_basic_map_copy(map->p[i]),
+					    isl_set_copy(dom), &todo_i, max);
+
+		if (max)
+			res = isl_pw_multi_aff_union_lexmax(res, res_i);
+		else
+			res = isl_pw_multi_aff_union_lexmin(res, res_i);
+
+		todo = isl_set_intersect(todo, todo_i);
+	}
+
+	isl_set_free(dom);
+	isl_map_free(map);
+
+	if (empty)
+		*empty = todo;
+	else
+		isl_set_free(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.
+ * Set *empty to those elements in dom that do not have an image element.
+ *
+ * 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".
+ *
+ * Let res^k and todo^k be the results after k steps and let i = k + 1.
+ * Assume we are computing the lexicographical maximum.
+ * We first compute the lexicographically maximal element in basic map i.
+ * This results in a partial solution res_i and a subset todo_i.
+ * Then we combine these results with those obtain for the first k basic maps
+ * to obtain a result that is valid for the first k+1 basic maps.
+ * In particular, the set where there is no solution is the set where
+ * there is no solution for the first k basic maps and also no solution
+ * for the ith basic map, i.e.,
+ *
+ *	todo^i = todo^k * todo_i
+ *
+ * On dom(res^k) * dom(res_i), we need to pick the larger of the two
+ * solutions, arbitrarily breaking ties in favor of res^k.
+ * That is, when res^k(a) >= res_i(a), we pick res^k and
+ * when res^k(a) < res_i(a), we pick res_i.  (Here, ">=" and "<" denote
+ * the lexicographic order.)
+ * In practice, we compute
+ *
+ *	res^k * (res_i . "<=")
+ *
+ * and
+ *
+ *	res_i * (res^k . "<")
+ *
+ * Finally, we consider the symmetric difference of dom(res^k) and dom(res_i),
+ * where only one of res^k and res_i provides a solution and we simply pick
+ * that one, i.e.,
+ *
+ *	res^k * todo_i
+ * and
+ *	res_i * todo^k
+ *
+ * Note that we only compute these intersections when dom(res^k) intersects
+ * dom(res_i).  Otherwise, the only effect of these intersections is to
+ * potentially break up res^k and res_i into smaller pieces.
+ * We want to avoid such splintering as much as possible.
+ * In fact, an earlier implementation of this function would look for
+ * better results in the domain of res^k and for extra results in todo^k,
+ * but this would always result in a splintering according to todo^k,
+ * even when the domain of basic map i is disjoint from the domains of
+ * the previous basic maps.
+ */
+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, int max)
+{
+	int i;
+	struct isl_map *res;
+	struct isl_set *todo;
+
+	if (!map || !dom)
+		goto error;
+
+	if (isl_map_plain_is_empty(map)) {
+		if (empty)
+			*empty = dom;
+		else
+			isl_set_free(dom);
+		return map;
+	}
+
+	res = basic_map_partial_lexopt(isl_basic_map_copy(map->p[0]),
+					isl_set_copy(dom), &todo, max);
+
+	for (i = 1; i < map->n; ++i) {
+		isl_map *lt, *le;
+		isl_map *res_i;
+		isl_set *todo_i;
+		isl_space *dim = isl_space_range(isl_map_get_space(res));
+
+		res_i = basic_map_partial_lexopt(isl_basic_map_copy(map->p[i]),
+					isl_set_copy(dom), &todo_i, max);
+
+		if (max) {
+			lt = isl_map_lex_lt(isl_space_copy(dim));
+			le = isl_map_lex_le(dim);
+		} else {
+			lt = isl_map_lex_gt(isl_space_copy(dim));
+			le = isl_map_lex_ge(dim);
+		}
+		lt = isl_map_apply_range(isl_map_copy(res), lt);
+		lt = isl_map_intersect(lt, isl_map_copy(res_i));
+		le = isl_map_apply_range(isl_map_copy(res_i), le);
+		le = isl_map_intersect(le, isl_map_copy(res));
+
+		if (!isl_map_is_empty(lt) || !isl_map_is_empty(le)) {
+			res = isl_map_intersect_domain(res,
+							isl_set_copy(todo_i));
+			res_i = isl_map_intersect_domain(res_i,
+							isl_set_copy(todo));
+		}
+
+		res = isl_map_union_disjoint(res, res_i);
+		res = isl_map_union_disjoint(res, lt);
+		res = isl_map_union_disjoint(res, le);
+
+		todo = isl_set_intersect(todo, todo_i);
+	}
+
+	isl_set_free(dom);
+	isl_map_free(map);
+
+	if (empty)
+		*empty = todo;
+	else
+		isl_set_free(todo);
+
+	return res;
+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, 1);
+}
+
+__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 (struct isl_set *)
+		isl_map_partial_lexmin((struct isl_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 (struct isl_set *)
+		isl_map_partial_lexmax((struct isl_map *)set,
+			dom, empty);
+}
+
+/* Compute the lexicographic minimum (or maximum if "max" is set)
+ * of "bmap" over its domain.
+ *
+ * Since we are not interested in the part of the domain space where
+ * there is no solution, we initialize the domain 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.
+ */
+__isl_give isl_map *isl_basic_map_lexopt(__isl_take isl_basic_map *bmap, int max)
+{
+	int n_div;
+	int n_out;
+	isl_basic_map *copy;
+	isl_basic_set *dom;
+
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+	n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	copy = isl_basic_map_copy(bmap);
+	copy = isl_basic_map_drop_constraints_involving_dims(copy,
+							isl_dim_div, 0, n_div);
+	copy = isl_basic_map_drop_constraints_involving_dims(copy,
+							isl_dim_out, 0, n_out);
+	dom = isl_basic_map_domain(copy);
+	return isl_basic_map_partial_lexopt(bmap, dom, NULL, max);
+}
+
+__isl_give isl_map *isl_basic_map_lexmin(__isl_take isl_basic_map *bmap)
+{
+	return isl_basic_map_lexopt(bmap, 0);
+}
+
+__isl_give isl_map *isl_basic_map_lexmax(__isl_take isl_basic_map *bmap)
+{
+	return isl_basic_map_lexopt(bmap, 1);
+}
+
+__isl_give isl_set *isl_basic_set_lexmin(__isl_take isl_basic_set *bset)
+{
+	return (isl_set *)isl_basic_map_lexmin((isl_basic_map *)bset);
+}
+
+__isl_give isl_set *isl_basic_set_lexmax(__isl_take isl_basic_set *bset)
+{
+	return (isl_set *)isl_basic_map_lexmax((isl_basic_map *)bset);
+}
+
+/* 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 int 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 0;
+error:
+	isl_basic_set_free(dom);
+	isl_aff_list_free(list);
+	return -1;
+}
+
+/* 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;
+	int 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 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 struct isl_basic_set *basic_set_parameter_preimage(
+	struct isl_basic_set *bset, struct 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 struct isl_set *set_parameter_preimage(
+	struct isl_set *set, struct isl_mat *mat)
+{
+	isl_space *dim = NULL;
+	unsigned nparam;
+
+	if (!set || !mat)
+		goto error;
+
+	dim = isl_space_copy(set->dim);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		goto error;
+
+	nparam = isl_set_dim(set, isl_dim_param);
+
+	isl_assert(set->ctx, mat->n_row == 1 + nparam, goto error);
+
+	dim->nparam = 0;
+	dim->n_out = nparam;
+	isl_set_reset_space(set, dim);
+	set = isl_set_preimage(set, mat);
+	if (!set)
+		goto error2;
+	dim = isl_space_copy(set->dim);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		goto error2;
+	dim->nparam = dim->n_out;
+	dim->n_out = 0;
+	isl_set_reset_space(set, dim);
+	return set;
+error:
+	isl_space_free(dim);
+	isl_mat_free(mat);
+error2:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* Intersect the basic set "bset" with the affine space specified by the
+ * equalities in "eq".
+ */
+static struct isl_basic_set *basic_set_append_equalities(
+	struct isl_basic_set *bset, struct 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(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(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;
+	unsigned n_known;
+	int i;
+
+	bmap = isl_basic_map_sort_divs(bmap);
+	bmap = isl_basic_map_cow(bmap);
+	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;
+
+	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 = (struct isl_basic_set *)bmap;
+
+	set = parameter_compute_divs(bset);
+	map = (struct isl_map *)set;
+	map = replace_space_by_local_space(map, ls);
+
+	return map;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+int isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap)
+{
+	int i;
+	unsigned off;
+
+	if (!bmap)
+		return -1;
+
+	off = 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]))
+			return 0;
+		isl_assert(bmap->ctx, isl_int_is_zero(bmap->div[i][1+1+off+i]),
+				return -1);
+	}
+	return 1;
+}
+
+static int map_divs_known(__isl_keep isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		int known = isl_basic_map_divs_known(map->p[i]);
+		if (known <= 0)
+			return known;
+	}
+
+	return 1;
+}
+
+/* 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.
+ */
+struct isl_map *isl_basic_map_compute_divs(struct 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;
+}
+
+struct isl_map *isl_map_compute_divs(struct isl_map *map)
+{
+	int i;
+	int known;
+	struct isl_map *res;
+
+	if (!map)
+		return NULL;
+	if (map->n == 0)
+		return map;
+
+	known = 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;
+}
+
+struct isl_set *isl_basic_set_compute_divs(struct isl_basic_set *bset)
+{
+	return (struct isl_set *)
+		isl_basic_map_compute_divs((struct isl_basic_map *)bset);
+}
+
+struct isl_set *isl_set_compute_divs(struct isl_set *set)
+{
+	return (struct isl_set *)
+		isl_map_compute_divs((struct isl_map *)set);
+}
+
+struct isl_set *isl_map_domain(struct isl_map *map)
+{
+	int i;
+	struct isl_set *set;
+
+	if (!map)
+		goto error;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	set = (struct isl_set *)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);
+}
+
+struct isl_set *isl_set_union_disjoint(
+			struct isl_set *set1, struct isl_set *set2)
+{
+	return (struct isl_set *)
+		isl_map_union_disjoint(
+			(struct isl_map *)set1, (struct isl_map *)set2);
+}
+
+struct isl_set *isl_set_union(struct isl_set *set1, struct isl_set *set2)
+{
+	return (struct isl_set *)
+		isl_map_union((struct isl_map *)set1, (struct isl_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)
+{
+	if (!map || !set)
+		goto error;
+
+	if (!isl_map_compatible_range(map, set))
+		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)
+{
+	if (!map || !set)
+		goto error;
+
+	if (!isl_map_compatible_domain(map, set))
+		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);
+}
+
+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
+ */
+struct isl_basic_set *isl_basic_map_deltas(struct 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_n_in(bmap);
+	nparam = isl_basic_map_n_param(bmap);
+	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 int foreach_orthant(__isl_take isl_set *set, int *signs, int first,
+	int len, int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user)
+{
+	isl_set *half;
+
+	if (!set)
+		return -1;
+	if (isl_set_plain_is_empty(set)) {
+		isl_set_free(set);
+		return 0;
+	}
+	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 -1;
+}
+
+/* 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.
+ */
+int isl_set_foreach_orthant(__isl_keep isl_set *set,
+	int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user)
+{
+	unsigned nparam;
+	unsigned nvar;
+	int *signs;
+	int r;
+
+	if (!set)
+		return -1;
+	if (isl_set_plain_is_empty(set))
+		return 0;
+
+	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((struct isl_map *)set1, (struct isl_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(
+		(struct isl_basic_map *)bset1, (struct isl_basic_map *)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((struct isl_map *)set);
+}
+
+int isl_map_has_equal_space(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	if (!map1 || !map2)
+		return -1;
+
+	return isl_space_is_equal(map1->dim, map2->dim);
+}
+
+int isl_set_has_equal_space(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	if (!set1 || !set2)
+		return -1;
+
+	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;
+}
+
+isl_bool isl_map_is_equal(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	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((isl_map *)set1, (isl_map *)set2);
+}
+
+isl_bool isl_basic_map_is_universe(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return isl_bool_error;
+	return bmap->n_eq == 0 && bmap->n_ineq == 0;
+}
+
+isl_bool isl_basic_set_is_universe(__isl_keep isl_basic_set *bset)
+{
+	if (!bset)
+		return isl_bool_error;
+	return bset->n_eq == 0 && bset->n_ineq == 0;
+}
+
+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_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((isl_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;
+	unsigned total;
+
+	if (!bmap)
+		return isl_bool_error;
+
+	if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_EMPTY))
+		return isl_bool_true;
+
+	if (isl_basic_map_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;
+	}
+
+	total = 1 + isl_basic_map_total_dim(bmap);
+	if (bmap->sample && bmap->sample->size == total) {
+		int contains = isl_basic_map_contains(bmap, bmap->sample);
+		if (contains < 0)
+			return isl_bool_error;
+		if (contains)
+			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);
+}
+
+isl_bool isl_basic_set_is_empty(__isl_keep isl_basic_set *bset)
+{
+	return isl_basic_map_is_empty((struct isl_basic_map *)bset);
+}
+
+struct isl_map *isl_basic_map_union(
+	struct isl_basic_map *bmap1, struct 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 (struct isl_set *)isl_basic_map_union(
+					    (struct isl_basic_map *)bset1,
+					    (struct isl_basic_map *)bset2);
+}
+
+/* Order divs such that any div only depends on previous divs */
+struct isl_basic_map *isl_basic_map_order_divs(struct 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;
+		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 (struct isl_basic_set *)
+		isl_basic_map_order_divs((struct isl_basic_map *)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;
+}
+
+/* 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)
+{
+	int i, j;
+	int n_div;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !div)
+		goto error;
+
+	if (div->n_row < bset->n_div)
+		isl_die(isl_mat_get_ctx(div), isl_error_invalid,
+			"not an expansion", goto error);
+
+	n_div = bset->n_div;
+	bset = isl_basic_map_extend_space(bset, isl_space_copy(bset->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_set_alloc_div(bset) < 0)
+			goto error;
+
+	j = n_div - 1;
+	for (i = div->n_row - 1; i >= 0; --i) {
+		if (j >= 0 && exp[j] == i) {
+			if (i != j)
+				isl_basic_map_swap_div(bset, i, j);
+			j--;
+		} else {
+			isl_seq_cpy(bset->div[i], div->row[i], div->n_col);
+			if (isl_basic_map_add_div_constraints(bset, i) < 0)
+				goto error;
+		}
+	}
+
+	isl_mat_free(div);
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	isl_mat_free(div);
+	return NULL;
+}
+
+/* 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(struct isl_basic_map *dst,
+			struct 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;
+}
+
+struct isl_basic_set *isl_basic_set_align_divs(
+		struct isl_basic_set *dst, struct isl_basic_set *src)
+{
+	return (struct isl_basic_set *)isl_basic_map_align_divs(
+		(struct isl_basic_map *)dst, (struct isl_basic_map *)src);
+}
+
+struct isl_map *isl_map_align_divs(struct 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;
+}
+
+struct isl_set *isl_set_align_divs(struct isl_set *set)
+{
+	return (struct isl_set *)isl_map_align_divs((struct isl_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(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)
+{
+	if (!set || !map)
+		goto error;
+	isl_assert(set->ctx, isl_map_compatible_domain(map, set), 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.
+ */
+struct isl_map *isl_map_remove_empty_parts(struct 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 (struct isl_set *)
+		isl_map_remove_empty_parts((struct isl_map *)set);
+}
+
+struct isl_basic_map *isl_map_copy_basic_map(struct isl_map *map)
+{
+	struct isl_basic_map *bmap;
+	if (!map || map->n == 0)
+		return NULL;
+	bmap = map->p[map->n-1];
+	isl_assert(map->ctx, ISL_F_ISSET(bmap, ISL_BASIC_SET_FINAL), return NULL);
+	return isl_basic_map_copy(bmap);
+}
+
+struct isl_basic_set *isl_set_copy_basic_set(struct isl_set *set)
+{
+	return (struct isl_basic_set *)
+		isl_map_copy_basic_map((struct isl_map *)set);
+}
+
+__isl_give isl_map *isl_map_drop_basic_map(__isl_take isl_map *map,
+						__isl_keep isl_basic_map *bmap)
+{
+	int i;
+
+	if (!map || !bmap)
+		goto error;
+	for (i = map->n-1; i >= 0; --i) {
+		if (map->p[i] != bmap)
+			continue;
+		map = isl_map_cow(map);
+		if (!map)
+			goto error;
+		isl_basic_map_free(map->p[i]);
+		if (i != map->n-1) {
+			ISL_F_CLR(map, ISL_SET_NORMALIZED);
+			map->p[i] = map->p[map->n-1];
+		}
+		map->n--;
+		return map;
+	}
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+struct isl_set *isl_set_drop_basic_set(struct isl_set *set,
+						struct isl_basic_set *bset)
+{
+	return (struct isl_set *)isl_map_drop_basic_map((struct isl_map *)set,
+						(struct isl_basic_map *)bset);
+}
+
+/* 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_space *dims;
+	struct isl_basic_map *bmap1 = NULL;
+	struct isl_basic_map *bmap2 = NULL;
+	struct isl_ctx *ctx;
+	struct isl_vec *obj;
+	unsigned total;
+	unsigned nparam;
+	unsigned dim1, dim2;
+	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);
+	dim2 = isl_basic_set_n_dim(bset2);
+	dims = isl_space_alloc(bset1->ctx, nparam, pos, dim1 - pos);
+	bmap1 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset1), dims);
+	dims = isl_space_alloc(bset2->ctx, nparam, pos, dim2 - pos);
+	bmap2 = isl_basic_map_from_basic_set(isl_basic_set_copy(bset2), dims);
+	if (!bmap1 || !bmap2)
+		goto error;
+	bmap1 = isl_basic_map_cow(bmap1);
+	bmap1 = isl_basic_map_extend(bmap1, nparam,
+			pos, (dim1 - pos) + (dim2 - pos),
+			bmap2->n_div, bmap2->n_eq, bmap2->n_ineq);
+	bmap1 = add_constraints(bmap1, bmap2, 0, dim1 - pos);
+	if (!bmap1)
+		goto error2;
+	total = isl_basic_map_total_dim(bmap1);
+	ctx = bmap1->ctx;
+	obj = isl_vec_alloc(ctx, 1 + total);
+	if (!obj)
+		goto error2;
+	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(bmap2);
+error2:
+	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 int 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 -1;
+	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 0;
+		if (isl_seq_first_non_zero(bmap->eq[i]+1+d+1, total-d-1) != -1)
+			return 0;
+		if (!isl_int_is_one(bmap->eq[i][1+d]))
+			return 0;
+		if (val)
+			isl_int_neg(*val, bmap->eq[i][0]);
+		return 1;
+	}
+	return 0;
+}
+
+static int isl_map_plain_has_fixed_var(__isl_keep isl_map *map,
+	unsigned pos, isl_int *val)
+{
+	int i;
+	isl_int v;
+	isl_int tmp;
+	int fixed;
+
+	if (!map)
+		return -1;
+	if (map->n == 0)
+		return 0;
+	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 == 1 && i < map->n; ++i) {
+		fixed = isl_basic_map_plain_has_fixed_var(map->p[i], pos, &tmp); 
+		if (fixed == 1 && isl_int_ne(tmp, v))
+			fixed = 0;
+	}
+	if (val)
+		isl_int_set(*val, v);
+	isl_int_clear(tmp);
+	isl_int_clear(v);
+	return fixed;
+}
+
+static int 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((struct isl_basic_map *)bset,
+						pos, val);
+}
+
+static int isl_set_plain_has_fixed_var(__isl_keep isl_set *set, unsigned pos,
+	isl_int *val)
+{
+	return isl_map_plain_has_fixed_var((struct isl_map *)set, pos, val);
+}
+
+int isl_basic_map_plain_is_fixed(__isl_keep isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned pos, isl_int *val)
+{
+	if (pos >= isl_basic_map_dim(bmap, type))
+		return -1;
+	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;
+	int 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);
+}
+
+int 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))
+		return -1;
+	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;
+	int 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);
+}
+
+int 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.
+ */
+int 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);
+}
+
+/* Check if dimension dim has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_set_plain_dim_is_fixed(__isl_keep isl_set *set,
+	unsigned dim, isl_int *val)
+{
+	return isl_set_plain_has_fixed_var(set, isl_set_n_param(set) + dim, val);
+}
+
+/* Check if input variable in has fixed value and if so and if val is not NULL,
+ * then return this fixed value in *val.
+ */
+int isl_map_plain_input_is_fixed(__isl_keep isl_map *map,
+	unsigned in, isl_int *val)
+{
+	return isl_map_plain_has_fixed_var(map, isl_map_n_param(map) + in, val);
+}
+
+/* Check if dimension dim has an (obvious) fixed lower bound and if so
+ * and if val is not NULL, then return this lower bound in *val.
+ */
+int isl_basic_set_plain_dim_has_fixed_lower_bound(
+	__isl_keep isl_basic_set *bset, unsigned dim, isl_int *val)
+{
+	int i, i_eq = -1, i_ineq = -1;
+	isl_int *c;
+	unsigned total;
+	unsigned nparam;
+
+	if (!bset)
+		return -1;
+	total = isl_basic_set_total_dim(bset);
+	nparam = isl_basic_set_n_param(bset);
+	for (i = 0; i < bset->n_eq; ++i) {
+		if (isl_int_is_zero(bset->eq[i][1+nparam+dim]))
+			continue;
+		if (i_eq != -1)
+			return 0;
+		i_eq = i;
+	}
+	for (i = 0; i < bset->n_ineq; ++i) {
+		if (!isl_int_is_pos(bset->ineq[i][1+nparam+dim]))
+			continue;
+		if (i_eq != -1 || i_ineq != -1)
+			return 0;
+		i_ineq = i;
+	}
+	if (i_eq == -1 && i_ineq == -1)
+		return 0;
+	c = i_eq != -1 ? bset->eq[i_eq] : bset->ineq[i_ineq];
+	/* The coefficient should always be one due to normalization. */
+	if (!isl_int_is_one(c[1+nparam+dim]))
+		return 0;
+	if (isl_seq_first_non_zero(c+1, nparam+dim) != -1)
+		return 0;
+	if (isl_seq_first_non_zero(c+1+nparam+dim+1,
+					total - nparam - dim - 1) != -1)
+		return 0;
+	if (val)
+		isl_int_neg(*val, c[0]);
+	return 1;
+}
+
+int isl_set_plain_dim_has_fixed_lower_bound(__isl_keep isl_set *set,
+	unsigned dim, isl_int *val)
+{
+	int i;
+	isl_int v;
+	isl_int tmp;
+	int fixed;
+
+	if (!set)
+		return -1;
+	if (set->n == 0)
+		return 0;
+	if (set->n == 1)
+		return isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
+								dim, val);
+	isl_int_init(v);
+	isl_int_init(tmp);
+	fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[0],
+								dim, &v);
+	for (i = 1; fixed == 1 && i < set->n; ++i) {
+		fixed = isl_basic_set_plain_dim_has_fixed_lower_bound(set->p[i],
+								dim, &tmp);
+		if (fixed == 1 && isl_int_ne(tmp, v))
+			fixed = 0;
+	}
+	if (val)
+		isl_int_set(*val, v);
+	isl_int_clear(tmp);
+	isl_int_clear(v);
+	return fixed;
+}
+
+/* uset_gist depends on constraints without existentially quantified
+ * variables sorting first.
+ */
+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;
+
+	l1 = isl_seq_last_non_zero(*c1 + 1, size);
+	l2 = isl_seq_last_non_zero(*c2 + 1, size);
+
+	if (l1 != l2)
+		return l1 - l2;
+
+	return isl_seq_cmp(*c1 + 1, *c2 + 1, size);
+}
+
+static struct isl_basic_map *isl_basic_map_sort_constraints(
+	struct 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)
+{
+	return (struct isl_basic_set *)isl_basic_map_sort_constraints(
+						(struct isl_basic_map *)bset);
+}
+
+struct isl_basic_map *isl_basic_map_normalize(struct 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;
+}
+
+struct isl_basic_set *isl_basic_set_normalize(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)isl_basic_map_normalize(
+						(struct isl_basic_map *)bset);
+}
+
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
+	const __isl_keep isl_basic_map *bmap2)
+{
+	int i, cmp;
+	unsigned total;
+
+	if (!bmap1 || !bmap2)
+		return -1;
+
+	if (bmap1 == bmap2)
+		return 0;
+	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_basic_map_n_param(bmap1) != isl_basic_map_n_param(bmap2))
+		return isl_basic_map_n_param(bmap1) - isl_basic_map_n_param(bmap2);
+	if (isl_basic_map_n_in(bmap1) != isl_basic_map_n_in(bmap2))
+		return isl_basic_map_n_out(bmap1) - isl_basic_map_n_out(bmap2);
+	if (isl_basic_map_n_out(bmap1) != isl_basic_map_n_out(bmap2))
+		return isl_basic_map_n_out(bmap1) - isl_basic_map_n_out(bmap2);
+	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(const __isl_keep isl_basic_set *bset1,
+	const __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((isl_basic_map *)bset1,
+					    (isl_basic_map *)bset2);
+}
+
+static int qsort_bmap_cmp(const void *p1, const void *p2)
+{
+	const struct isl_basic_map *bmap1 = *(const struct isl_basic_map **)p1;
+	const struct isl_basic_map *bmap2 = *(const struct 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 (struct isl_set *)isl_map_normalize((struct isl_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((struct isl_map *)set1,
+						(struct isl_map *)set2);
+}
+
+/* Return an interval that ranges from min to max (inclusive)
+ */
+struct isl_basic_set *isl_basic_set_interval(struct isl_ctx *ctx,
+	isl_int min, isl_int max)
+{
+	int k;
+	struct isl_basic_set *bset = NULL;
+
+	bset = isl_basic_set_alloc(ctx, 0, 1, 0, 0, 2);
+	if (!bset)
+		goto error;
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_int_set_si(bset->ineq[k][1], 1);
+	isl_int_neg(bset->ineq[k][0], min);
+
+	k = isl_basic_set_alloc_inequality(bset);
+	if (k < 0)
+		goto error;
+	isl_int_set_si(bset->ineq[k][1], -1);
+	isl_int_set(bset->ineq[k][0], max);
+
+	return bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* 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 Cartesian product of the basic sets in list (in the given order).
+ */
+__isl_give isl_basic_set *isl_basic_set_list_product(
+	__isl_take struct isl_basic_set_list *list)
+{
+	int i;
+	unsigned dim;
+	unsigned nparam;
+	unsigned extra;
+	unsigned n_eq;
+	unsigned n_ineq;
+	struct isl_basic_set *product = NULL;
+
+	if (!list)
+		goto error;
+	isl_assert(list->ctx, list->n > 0, goto error);
+	isl_assert(list->ctx, list->p[0], goto error);
+	nparam = isl_basic_set_n_param(list->p[0]);
+	dim = isl_basic_set_n_dim(list->p[0]);
+	extra = list->p[0]->n_div;
+	n_eq = list->p[0]->n_eq;
+	n_ineq = list->p[0]->n_ineq;
+	for (i = 1; i < list->n; ++i) {
+		isl_assert(list->ctx, list->p[i], goto error);
+		isl_assert(list->ctx,
+		    nparam == isl_basic_set_n_param(list->p[i]), goto error);
+		dim += isl_basic_set_n_dim(list->p[i]);
+		extra += list->p[i]->n_div;
+		n_eq += list->p[i]->n_eq;
+		n_ineq += list->p[i]->n_ineq;
+	}
+	product = isl_basic_set_alloc(list->ctx, nparam, dim, extra,
+					n_eq, n_ineq);
+	if (!product)
+		goto error;
+	dim = 0;
+	for (i = 0; i < list->n; ++i) {
+		isl_basic_set_add_constraints(product,
+					isl_basic_set_copy(list->p[i]), dim);
+		dim += isl_basic_set_n_dim(list->p[i]);
+	}
+	isl_basic_set_list_free(list);
+	return product;
+error:
+	isl_basic_set_free(product);
+	isl_basic_set_list_free(list);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_product(
+		struct isl_basic_map *bmap1, struct 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 (!bmap1 || !bmap2)
+		goto error;
+
+	isl_assert(bmap1->ctx, isl_space_match(bmap1->dim, isl_dim_param,
+				     bmap2->dim, isl_dim_param), goto error);
+	dim_result = isl_space_product(isl_space_copy(bmap1->dim),
+						   isl_space_copy(bmap2->dim));
+
+	in1 = isl_basic_map_n_in(bmap1);
+	in2 = isl_basic_map_n_in(bmap2);
+	out1 = isl_basic_map_n_out(bmap1);
+	out2 = isl_basic_map_n_out(bmap2);
+	nparam = isl_basic_map_n_param(bmap1);
+
+	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_space *dim_result = NULL;
+	isl_basic_map *bmap;
+	unsigned in, out1, out2, nparam, total, pos;
+	struct isl_dim_map *dim_map1, *dim_map2;
+
+	if (!bmap1 || !bmap2)
+		goto error;
+
+	if (!isl_space_match(bmap1->dim, isl_dim_param,
+			    bmap2->dim, isl_dim_param))
+		isl_die(isl_basic_map_get_ctx(bmap1), isl_error_invalid,
+			"parameters don't match", 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_n_out(bmap1);
+	out2 = isl_basic_map_n_out(bmap2);
+	nparam = isl_basic_map_n_param(bmap1);
+
+	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);
+	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;
+
+	if (!map1 || !map2)
+		goto error;
+
+	isl_assert(map1->ctx, isl_space_match(map1->dim, isl_dim_param,
+					 map2->dim, isl_dim_param), 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((isl_basic_map *)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((isl_map *)set);
+}
+
+/* Check if the value for dimension dim is completely determined
+ * by the values of the other parameters and variables.
+ * That is, check if dimension dim is involved in an equality.
+ */
+int isl_basic_set_dim_is_unique(struct isl_basic_set *bset, unsigned dim)
+{
+	int i;
+	unsigned nparam;
+
+	if (!bset)
+		return -1;
+	nparam = isl_basic_set_n_param(bset);
+	for (i = 0; i < bset->n_eq; ++i)
+		if (!isl_int_is_zero(bset->eq[i][1 + nparam + dim]))
+			return 1;
+	return 0;
+}
+
+/* Check if the value for dimension dim is completely determined
+ * by the values of the other parameters and variables.
+ * That is, check if dimension dim is involved in an equality
+ * for each of the subsets.
+ */
+int isl_set_dim_is_unique(struct isl_set *set, unsigned dim)
+{
+	int i;
+
+	if (!set)
+		return -1;
+	for (i = 0; i < set->n; ++i) {
+		int unique;
+		unique = isl_basic_set_dim_is_unique(set->p[i], dim);
+		if (unique != 1)
+			return unique;
+	}
+	return 1;
+}
+
+/* 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 = isl_set_align_divs(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;
+}
+
+__isl_give isl_map *isl_set_lifting(__isl_take isl_set *set)
+{
+	isl_space *dim;
+	struct isl_basic_map *bmap;
+	unsigned n_set;
+	unsigned n_div;
+	unsigned n_param;
+	unsigned total;
+	int i, k, l;
+
+	set = isl_set_align_divs(set);
+
+	if (!set)
+		return NULL;
+
+	dim = isl_set_get_space(set);
+	if (set->n == 0 || set->p[0]->n_div == 0) {
+		isl_set_free(set);
+		return isl_map_identity(isl_space_map_from_set(dim));
+	}
+
+	n_div = set->p[0]->n_div;
+	dim = isl_space_map_from_set(dim);
+	n_param = isl_space_dim(dim, isl_dim_param);
+	n_set = isl_space_dim(dim, isl_dim_in);
+	dim = isl_space_extend(dim, n_param, n_set, n_set + n_div);
+	bmap = isl_basic_map_alloc_space(dim, 0, n_set, 2 * n_div);
+	for (i = 0; i < n_set; ++i)
+		bmap = var_equal(bmap, i);
+
+	total = n_param + n_set + n_set + n_div;
+	for (i = 0; i < n_div; ++i) {
+		k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->ineq[k], set->p[0]->div[i]+1, 1+n_param);
+		isl_seq_clr(bmap->ineq[k]+1+n_param, n_set);
+		isl_seq_cpy(bmap->ineq[k]+1+n_param+n_set,
+			    set->p[0]->div[i]+1+1+n_param, n_set + n_div);
+		isl_int_neg(bmap->ineq[k][1+n_param+n_set+n_set+i],
+			    set->p[0]->div[i][0]);
+
+		l = isl_basic_map_alloc_inequality(bmap);
+		if (l < 0)
+			goto error;
+		isl_seq_neg(bmap->ineq[l], bmap->ineq[k], 1 + total);
+		isl_int_add(bmap->ineq[l][0], bmap->ineq[l][0],
+			    set->p[0]->div[i][0]);
+		isl_int_sub_ui(bmap->ineq[l][0], bmap->ineq[l][0], 1);
+	}
+
+	isl_set_free(set);
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	return isl_map_from_basic_map(bmap);
+error:
+	isl_set_free(set);
+	isl_basic_map_free(bmap);
+	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 (!bmap)
+		return isl_bool_error;
+
+	isl_assert(bmap->ctx, pos < isl_basic_map_dim(bmap, type),
+		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;
+}
+
+int 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);
+}
+
+int isl_map_dim_is_bounded(__isl_keep isl_map *map,
+	enum isl_dim_type type, unsigned pos)
+{
+	int i;
+
+	if (!map)
+		return -1;
+
+	for (i = 0; i < map->n; ++i) {
+		int bounded;
+		bounded = isl_basic_map_dim_is_bounded(map->p[i], type, pos);
+		if (bounded < 0 || !bounded)
+			return bounded;
+	}
+
+	return 1;
+}
+
+/* Return 1 if the specified dim is involved in both an upper bound
+ * and a lower bound.
+ */
+int isl_set_dim_is_bounded(__isl_keep isl_set *set,
+	enum isl_dim_type type, unsigned pos)
+{
+	return isl_map_dim_is_bounded((isl_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.
+ */
+int 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 -1;
+
+	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 0;
+error:
+	isl_tab_free(tab);
+	isl_vec_free(bound);
+	return -1;
+}
+
+int 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 -1;
+	isl_assert(bset->ctx, first + n <= isl_basic_set_dim(bset, type),
+		return -1);
+
+	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 int 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 1;
+
+	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 1;
+
+	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) {
+		if (isl_int_is_zero(bmap->div[div][1 + o_div + i]))
+			continue;
+		if (div_may_involve_output(bmap, i))
+			return 1;
+	}
+
+	return 0;
+}
+
+/* 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.
+ * 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 j, k;
+	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);
+
+	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;
+		for (k = 0; k < n_div; ++k) {
+			if (isl_int_is_zero(bmap->eq[j][o_div + k]))
+				continue;
+			if (div_may_involve_output(bmap, k))
+				break;
+		}
+		if (k >= n_div)
+			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);
+		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((isl_map *)set);
+}
+
+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;
+}
+
+int isl_basic_set_is_box(__isl_keep isl_basic_set *bset)
+{
+	int i, j;
+	unsigned nvar;
+	unsigned ovar;
+
+	if (!bset)
+		return -1;
+
+	if (isl_basic_set_dim(bset, isl_dim_div) != 0)
+		return 0;
+
+	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 0;
+			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 0;
+			if (isl_int_is_pos(bset->ineq[i][1 + ovar + j]))
+				lower = 1;
+			else
+				upper = 1;
+		}
+		if (!lower || !upper)
+			return 0;
+	}
+
+	return 1;
+}
+
+int isl_set_is_box(__isl_keep isl_set *set)
+{
+	if (!set)
+		return -1;
+	if (set->n != 1)
+		return 0;
+
+	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);
+}
+
+/* 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);
+}
+
+/* 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 (isl_basic_set *)bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+__isl_give isl_set *isl_map_wrap(__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 *)isl_basic_map_wrap(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_wrap(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return (isl_set *)map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__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 (isl_basic_map *)bset;
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+__isl_give isl_map *isl_set_unwrap(__isl_take isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return NULL;
+
+	if (!isl_set_is_wrapping(set))
+		isl_die(set->ctx, isl_error_invalid, "not a wrapping set",
+			goto error);
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = (isl_basic_set *)isl_basic_set_unwrap(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+
+	set->dim = isl_space_unwrap(set->dim);
+	if (!set->dim)
+		goto error;
+
+	return (isl_map *)set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+__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 (isl_basic_set *)isl_basic_map_flatten((isl_basic_map *)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;
+}
+
+__isl_give isl_map *isl_map_flatten(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[0] && !map->dim->nested[1])
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_flatten(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_flatten(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_set *isl_set_flatten(__isl_take isl_set *set)
+{
+	return (isl_set *)isl_map_flatten((isl_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;
+}
+
+__isl_give isl_map *isl_map_flatten_domain(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[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_flatten_domain(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_flatten_domain(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give isl_map *isl_map_flatten_range(__isl_take isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!map->dim->nested[1])
+		return map;
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_flatten_range(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+	map->dim = isl_space_flatten_range(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* Reorder the dimensions of "bmap" according to the given dim_map
+ * and set the dimension specification to "dim".
+ */
+__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_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 (isl_set *)isl_map_realign((isl_map *)set, r);
+}
+
+__isl_give isl_map *isl_map_align_params(__isl_take isl_map *map,
+	__isl_take isl_space *model)
+{
+	isl_ctx *ctx;
+
+	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_space_has_named_params(map->dim))
+		isl_die(ctx, isl_error_invalid,
+			"relation has unnamed parameters", goto error);
+	if (!isl_space_match(map->dim, isl_dim_param, model, isl_dim_param)) {
+		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;
+
+	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);
+	if (!isl_space_match(bmap->dim, isl_dim_param, model, isl_dim_param)) {
+		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;
+}
+
+/* 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((isl_basic_map *)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((isl_basic_map *)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)
+{
+	return (isl_basic_set*)
+	    isl_basic_map_from_constraint_matrices(dim, eq, ineq,
+						   c1, c2, c3, c4, isl_dim_in);
+}
+
+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;
+	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;
+	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)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_map_can_curry(map))
+		isl_die(map->ctx, isl_error_invalid, "map cannot be curried",
+			goto error);
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_curry(map->p[i]);
+		if (!map->p[i])
+			goto error;
+	}
+
+	map->dim = isl_space_curry(map->dim);
+	if (!map->dim)
+		goto error;
+
+	return map;
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+/* 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);
+	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)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+
+	if (!isl_map_can_uncurry(map))
+		isl_die(map->ctx, isl_error_invalid, "map cannot be uncurried",
+			return isl_map_free(map));
+
+	map = isl_map_cow(map);
+	if (!map)
+		return NULL;
+
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_uncurry(map->p[i]);
+		if (!map->p[i])
+			return isl_map_free(map);
+	}
+
+	map->dim = isl_space_uncurry(map->dim);
+	if (!map->dim)
+		return isl_map_free(map);
+
+	return map;
+}
+
+/* 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)
+{
+	int k;
+	int pos;
+	isl_local_space *ls;
+	isl_basic_map *bmap;
+
+	if (!aff)
+		return NULL;
+
+	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);
+	bmap = isl_basic_map_finalize(bmap);
+	return bmap;
+error:
+	isl_aff_free(aff);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+/* 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.
+ */
+__isl_give isl_basic_map *isl_basic_map_from_multi_aff(
+	__isl_take isl_multi_aff *maff)
+{
+	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));
+
+	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_aff(aff);
+
+		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 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".
+ * Return -1 if anything is wrong.
+ */
+static int check_basic_map_compatible_range_multi_aff(
+	__isl_keep isl_basic_map *bmap, enum isl_dim_type type,
+	__isl_keep isl_multi_aff *ma)
+{
+	int m;
+	isl_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+
+	m = isl_space_match(bmap->dim, isl_dim_param, ma_space, isl_dim_param);
+	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 m;
+error:
+	isl_space_free(ma_space);
+	return -1;
+}
+
+/* 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_set_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.
+ */
+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 i, k;
+	int div;
+	int total;
+	int n_param;
+	int n_in;
+	int n_div;
+
+	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);
+	n_div = isl_multi_aff_dim(ma, isl_dim_div);
+	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);
+		o_bmap += n_div;
+		o_ma += n_div;
+		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;
+	int rational, 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);
+
+	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_set_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 -1 if anything is wrong.
+ */
+static int check_map_compatible_range_multi_aff(
+	__isl_keep isl_map *map, enum isl_dim_type type,
+	__isl_keep isl_multi_aff *ma)
+{
+	int 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 && !m)
+		isl_die(isl_map_get_ctx(map), isl_error_invalid,
+			"spaces don't match", return -1);
+	return m;
+}
+
+/* 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)
+{
+	if (!map || !ma)
+		goto error;
+
+	if (isl_space_match(map->dim, isl_dim_param, ma->space, isl_dim_param))
+		return map_preimage_multi_aff(map, type, ma);
+
+	if (!isl_space_has_named_params(map->dim) ||
+	    !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)
+{
+	if (!map || !pma)
+		goto error;
+
+	if (isl_space_match(map->dim, isl_dim_param, pma->dim, isl_dim_param))
+		return isl_map_preimage_pw_multi_aff_aligned(map, type, pma);
+
+	if (!isl_space_has_named_params(map->dim) ||
+	    !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);
+}
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..1196a87
--- /dev/null
+++ b/final/lib/External/isl/isl_map_lexopt_templ.c
@@ -0,0 +1,142 @@
+/*
+ * 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)
+
+/* Given a basic map "bmap", 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.
+ *
+ * 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.
+ */
+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, int max)
+{
+	int i;
+	TYPE *res;
+
+	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, max);
+		
+	for (i = 1; i < dom->n; ++i) {
+		TYPE *res_i;
+		isl_set *empty_i;
+
+		res_i = SF(isl_basic_map_partial_lexopt,SUFFIX)(
+				isl_basic_map_copy(bmap),
+				isl_basic_set_copy(dom->p[i]), &empty_i, max);
+
+		res = ADD(res, res_i);
+		*empty = isl_set_union_disjoint(*empty, empty_i);
+	}
+
+	isl_set_free(dom);
+	isl_basic_map_free(bmap);
+	return res;
+error:
+	*empty = NULL;
+	isl_set_free(dom);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+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, int max);
+
+/* 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, int max)
+{
+	if (!map || !dom)
+		goto error;
+	if (isl_space_match(map->dim, isl_dim_param, dom->dim, isl_dim_param))
+		return SF(isl_map_partial_lexopt_aligned,SUFFIX)(map, dom,
+								empty, max);
+	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, max);
+error:
+	if (empty)
+		*empty = NULL;
+	isl_set_free(dom);
+	isl_map_free(map);
+	return NULL;
+}
+
+__isl_give TYPE *SF(isl_map_lexopt,SUFFIX)(__isl_take isl_map *map, int max)
+{
+	isl_set *dom = NULL;
+	isl_space *dom_space;
+
+	if (!map)
+		goto error;
+	dom_space = isl_space_domain(isl_space_copy(map->dim));
+	dom = isl_set_universe(dom_space);
+	return SF(isl_map_partial_lexopt,SUFFIX)(map, dom, NULL, max);
+error:
+	isl_map_free(map);
+	return NULL;
+}
+
+__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, 1);
+}
+
+__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..15b041e
--- /dev/null
+++ b/final/lib/External/isl/isl_map_private.h
@@ -0,0 +1,472 @@
+/*
+ * 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_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.
+ */
+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;
+
+	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_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_alloc(isl_ctx *ctx,
+	unsigned nparam, unsigned dim, int n, unsigned flags);
+__isl_give isl_set *isl_set_add_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *bset);
+__isl_give isl_set *isl_set_finalize(__isl_take isl_set *set);
+__isl_give isl_set *isl_set_dup(__isl_keep isl_set *set);
+
+__isl_give isl_map *isl_map_alloc(isl_ctx *ctx,
+	unsigned nparam, unsigned in, unsigned out, int n, unsigned flags);
+__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_map *isl_map_finalize(__isl_take 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_set *isl_set_from_underlying_set(
+	__isl_take isl_set *set, __isl_take isl_basic_set *like);
+__isl_give isl_set *isl_set_to_underlying_set(__isl_take isl_set *set);
+
+__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_map *isl_map_reset(__isl_take isl_map *map,
+	enum isl_dim_type type);
+
+__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(struct isl_basic_set *bset,
+					enum isl_dim_type type);
+
+int isl_basic_map_may_be_set(__isl_keep isl_basic_map *bmap);
+int isl_map_may_be_set(__isl_keep isl_map *map);
+int isl_map_compatible_domain(struct isl_map *map, struct isl_set *set);
+int isl_basic_map_compatible_domain(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset);
+int isl_basic_map_compatible_range(struct isl_basic_map *bmap,
+		struct isl_basic_set *bset);
+
+struct isl_basic_map *isl_basic_map_extend_space(struct isl_basic_map *base,
+		__isl_take isl_space *dim, unsigned extra,
+		unsigned n_eq, unsigned n_ineq);
+struct isl_basic_set *isl_basic_set_extend_space(struct 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);
+
+struct isl_map *isl_map_grow(struct 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);
+
+unsigned isl_basic_map_total_dim(const struct isl_basic_map *bmap);
+
+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(struct isl_basic_set *bset);
+int isl_basic_map_alloc_inequality(struct 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);
+int isl_basic_set_alloc_div(struct isl_basic_set *bset);
+int isl_basic_map_free_div(struct isl_basic_map *bmap, unsigned n);
+int isl_basic_set_free_div(struct isl_basic_set *bset, unsigned n);
+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_equality(struct isl_basic_set *bset, 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);
+
+int isl_inequality_negate(struct isl_basic_map *bmap, unsigned pos);
+
+struct isl_basic_set *isl_basic_set_cow(struct isl_basic_set *bset);
+struct isl_basic_map *isl_basic_map_cow(struct isl_basic_map *bmap);
+struct isl_set *isl_set_cow(struct isl_set *set);
+struct isl_map *isl_map_cow(struct isl_map *map);
+
+uint32_t isl_basic_map_get_hash(__isl_keep isl_basic_map *bmap);
+
+struct isl_basic_map *isl_basic_map_set_to_empty(struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_set_to_empty(struct 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);
+struct isl_basic_map *isl_basic_map_order_divs(struct isl_basic_map *bmap);
+__isl_give isl_map *isl_map_order_divs(__isl_take isl_map *map);
+struct isl_basic_map *isl_basic_map_align_divs(
+		struct isl_basic_map *dst, struct isl_basic_map *src);
+struct isl_basic_set *isl_basic_set_align_divs(
+		struct isl_basic_set *dst, struct isl_basic_set *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_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);
+struct isl_basic_map *isl_basic_map_gauss(
+	struct isl_basic_map *bmap, int *progress);
+struct isl_basic_set *isl_basic_set_gauss(
+	struct isl_basic_set *bset, int *progress);
+__isl_give isl_basic_set *isl_basic_set_sort_constraints(
+	__isl_take isl_basic_set *bset);
+int isl_basic_map_plain_cmp(const __isl_keep isl_basic_map *bmap1,
+	const __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);
+struct isl_basic_map *isl_basic_map_normalize_constraints(
+	struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_normalize_constraints(
+	struct isl_basic_set *bset);
+struct isl_basic_map *isl_basic_map_implicit_equalities(
+						struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_map_underlying_set(struct 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);
+struct isl_set *isl_map_underlying_set(struct isl_map *map);
+struct isl_basic_map *isl_basic_map_overlying_set(struct isl_basic_set *bset,
+	struct isl_basic_map *like);
+__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);
+struct isl_basic_map *isl_basic_map_drop(struct isl_basic_map *bmap,
+	enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_set *isl_set_drop(struct isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n);
+struct isl_basic_set *isl_basic_set_drop_dims(
+		struct isl_basic_set *bset, unsigned first, unsigned n);
+struct isl_set *isl_set_drop_dims(
+		struct isl_set *set, unsigned first, unsigned n);
+struct isl_map *isl_map_drop_inputs(
+		struct isl_map *map, unsigned first, unsigned n);
+struct isl_map *isl_map_drop(struct isl_map *map,
+	enum isl_dim_type type, unsigned first, unsigned n);
+
+__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);
+
+struct isl_map *isl_map_remove_empty_parts(struct 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);
+
+struct isl_basic_map *isl_basic_map_eliminate_vars(
+	struct 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_set_constraint_is_redundant(struct isl_basic_set **bset,
+	isl_int *c, isl_int *opt_n, isl_int *opt_d);
+
+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);
+struct isl_basic_map *isl_basic_map_drop_redundant_divs(
+	struct isl_basic_map *bmap);
+struct isl_basic_set *isl_basic_set_drop_redundant_divs(
+	struct isl_basic_set *bset);
+
+struct isl_basic_set *isl_basic_set_recession_cone(struct isl_basic_set *bset);
+struct isl_basic_set *isl_basic_set_lineality_space(struct isl_basic_set *bset);
+
+struct isl_basic_set *isl_basic_set_set_rational(struct 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);
+
+int isl_map_has_rational(__isl_keep isl_map *map);
+int isl_set_has_rational(__isl_keep isl_set *set);
+
+struct isl_mat;
+
+struct isl_basic_set *isl_basic_set_preimage(struct isl_basic_set *bset,
+	struct isl_mat *mat);
+struct isl_set *isl_set_preimage(struct isl_set *set, struct isl_mat *mat);
+
+__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);
+
+int isl_basic_set_vars_get_sign(__isl_keep isl_basic_set *bset,
+	unsigned first, unsigned n, int *signs);
+int isl_set_foreach_orthant(__isl_keep isl_set *set,
+	int (*fn)(__isl_take isl_set *orthant, int *signs, void *user),
+	void *user);
+
+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);
+int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+	isl_int *constraint, unsigned div);
+int 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);
+
+int isl_basic_map_divs_known(__isl_keep isl_basic_map *bmap);
+__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_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));
+
+int isl_basic_map_foreach_lexopt(__isl_keep isl_basic_map *bmap, int max,
+	int (*fn)(__isl_take isl_basic_set *dom, __isl_take isl_aff_list *list,
+		  void *user),
+	void *user);
+int isl_basic_set_foreach_lexopt(__isl_keep isl_basic_set *bset, int max,
+	int (*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);
+
+int isl_map_compatible_range(__isl_keep isl_map *map, __isl_keep isl_set *set);
+
+isl_bool isl_basic_map_plain_is_single_valued(__isl_keep isl_basic_map *bmap);
+
+int isl_map_is_set(__isl_keep isl_map *map);
+
+int isl_basic_set_plain_dim_is_fixed(__isl_keep isl_basic_set *bset,
+	unsigned dim, isl_int *val);
+
+__isl_give isl_basic_map *isl_basic_map_plain_affine_hull(
+	__isl_take isl_basic_map *bmap);
+
+int isl_basic_set_dim_residue_class(struct isl_basic_set *bset,
+	int pos, isl_int *modulo, isl_int *residue);
+int isl_set_dim_residue_class(struct 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_set *isl_set_fix(__isl_take isl_set *set,
+	enum isl_dim_type type, unsigned pos, isl_int value);
+int 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);
+
+__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);
+
+#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..255c50f
--- /dev/null
+++ b/final/lib/External/isl/isl_map_simplify.c
@@ -0,0 +1,3605 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * 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 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>
+
+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;
+	}
+}
+
+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.
+ */
+struct isl_basic_set *isl_basic_set_drop_dims(
+		struct isl_basic_set *bset, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!bset)
+		goto error;
+
+	isl_assert(bset->ctx, first + n <= bset->dim->n_out, goto error);
+
+	if (n == 0 && !isl_space_get_tuple_name(bset->dim, isl_dim_set))
+		return bset;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset)
+		return NULL;
+
+	for (i = 0; i < bset->n_eq; ++i)
+		constraint_drop_vars(bset->eq[i]+1+bset->dim->nparam+first, n,
+				     (bset->dim->n_out-first-n)+bset->extra);
+
+	for (i = 0; i < bset->n_ineq; ++i)
+		constraint_drop_vars(bset->ineq[i]+1+bset->dim->nparam+first, n,
+				     (bset->dim->n_out-first-n)+bset->extra);
+
+	for (i = 0; i < bset->n_div; ++i)
+		constraint_drop_vars(bset->div[i]+1+1+bset->dim->nparam+first, n,
+				     (bset->dim->n_out-first-n)+bset->extra);
+
+	bset->dim = isl_space_drop_outputs(bset->dim, first, n);
+	if (!bset->dim)
+		goto error;
+
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+	bset = isl_basic_set_simplify(bset);
+	return isl_basic_set_finalize(bset);
+error:
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_set *isl_set_drop_dims(
+		struct isl_set *set, unsigned first, unsigned n)
+{
+	int i;
+
+	if (!set)
+		goto error;
+
+	isl_assert(set->ctx, first + n <= set->dim->n_out, goto error);
+
+	if (n == 0 && !isl_space_get_tuple_name(set->dim, isl_dim_set))
+		return set;
+	set = isl_set_cow(set);
+	if (!set)
+		goto error;
+	set->dim = isl_space_drop_outputs(set->dim, first, n);
+	if (!set->dim)
+		goto error;
+
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_drop_dims(set->p[i], first, n);
+		if (!set->p[i])
+			goto error;
+	}
+
+	ISL_F_CLR(set, ISL_SET_NORMALIZED);
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+/* 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.
+ */
+struct isl_basic_map *isl_basic_map_drop(struct 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;
+		isl_basic_map_free_div(bmap, n);
+	} 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 (isl_basic_set *)isl_basic_map_drop((isl_basic_map *)bset,
+							type, first, n);
+}
+
+struct isl_basic_map *isl_basic_map_drop_inputs(
+		struct isl_basic_map *bmap, unsigned first, unsigned n)
+{
+	return isl_basic_map_drop(bmap, isl_dim_in, first, n);
+}
+
+struct isl_map *isl_map_drop(struct 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_get_tuple_name(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;
+}
+
+struct isl_set *isl_set_drop(struct isl_set *set,
+	enum isl_dim_type type, unsigned first, unsigned n)
+{
+	return (isl_set *)isl_map_drop((isl_map *)set, type, first, n);
+}
+
+struct isl_map *isl_map_drop_inputs(
+		struct isl_map *map, unsigned first, unsigned n)
+{
+	return isl_map_drop(map, isl_dim_in, first, n);
+}
+
+/*
+ * We don't cow, as the div is assumed to be redundant.
+ */
+static struct isl_basic_map *isl_basic_map_drop_div(
+		struct 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);
+	isl_basic_map_free_div(bmap, 1);
+
+	return bmap;
+error:
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_basic_map *isl_basic_map_normalize_constraints(
+	struct 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;
+}
+
+struct isl_basic_set *isl_basic_set_normalize_constraints(
+	struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)isl_basic_map_normalize_constraints(
+		(struct isl_basic_map *)bset);
+}
+
+/* Assuming the variable at position "pos" has an integer coefficient
+ * in integer division "div", extract it 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 * x_pos + ...)/d)
+ *
+ * Replace it by
+ *
+ *	floor((... + 0 * x_pos + ...)/d) + c * x_pos
+ */
+static __isl_give isl_basic_map *remove_var_from_div(
+	__isl_take isl_basic_map *bmap, int div, int pos)
+{
+	isl_int shift;
+
+	isl_int_init(shift);
+	isl_int_divexact(shift, bmap->div[div][1 + pos], bmap->div[div][0]);
+	isl_int_neg(shift, shift);
+	bmap = isl_basic_map_shift_div(bmap, div, pos, shift);
+	isl_int_clear(shift);
+
+	return bmap;
+}
+
+/* Check if integer division "div" has any integral coefficient
+ * (or constant term).  If so, extract them from the integer division.
+ */
+static __isl_give isl_basic_map *remove_independent_vars_from_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) {
+		if (isl_int_is_zero(bmap->div[div][1 + i]))
+			continue;
+		if (!isl_int_is_divisible_by(bmap->div[div][1 + i],
+					     bmap->div[div][0]))
+			continue;
+		bmap = remove_var_from_div(bmap, div, i);
+		if (!bmap)
+			break;
+	}
+
+	return bmap;
+}
+
+/* Check if any known integer division has any integral coefficient
+ * (or constant term).  If so, extract them from the integer division.
+ */
+static __isl_give isl_basic_map *remove_independent_vars_from_divs(
+	__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 = remove_independent_vars_from_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 int ok_to_eliminate_div(struct 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 1;
+
+	for (k = 0; k <= last_div; ++k) {
+		if (isl_int_is_zero(bmap->div[k][0]))
+			return 1;
+		if (!isl_int_is_zero(bmap->div[k][1 + 1 + pos]))
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Elimininate divs based on equalities
+ */
+static struct isl_basic_map *eliminate_divs_eq(
+		struct 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) {
+			if (!isl_int_is_one(bmap->eq[i][off + d]) &&
+			    !isl_int_is_negone(bmap->eq[i][off + d]))
+				continue;
+			if (!ok_to_eliminate_div(bmap, bmap->eq[i], d))
+				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;
+}
+
+/* Elimininate divs based on inequalities
+ */
+static struct isl_basic_map *eliminate_divs_ineq(
+		struct 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;
+}
+
+struct isl_basic_map *isl_basic_map_gauss(
+	struct 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 &&
+		    isl_int_is_zero(bmap->div[last_var - total_var][0])) {
+			unsigned div = last_var - total_var;
+			isl_seq_neg(bmap->div[div]+1, bmap->eq[done], 1+total);
+			isl_int_set_si(bmap->div[div][1+1+last_var], 0);
+			isl_int_set(bmap->div[div][0],
+				    bmap->eq[done][1+last_var]);
+			if (progress)
+				*progress = 1;
+			ISL_F_CLR(bmap, ISL_BASIC_MAP_NORMALIZED);
+		}
+	}
+	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;
+}
+
+struct isl_basic_set *isl_basic_set_gauss(
+	struct isl_basic_set *bset, int *progress)
+{
+	return (struct isl_basic_set*)isl_basic_map_gauss(
+			(struct isl_basic_map *)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;
+}
+
+static int hash_index(isl_int ***index, unsigned int size, int bits,
+			struct isl_basic_map *bmap, int k)
+{
+	int h;
+	unsigned total = isl_basic_map_total_dim(bmap);
+	uint32_t hash = isl_seq_get_hash_bits(bmap->ineq[k]+1, total, bits);
+	for (h = hash; index[h]; h = (h+1) % size)
+		if (&bmap->ineq[k] != index[h] &&
+		    isl_seq_eq(bmap->ineq[k]+1, index[h][0]+1, total))
+			break;
+	return h;
+}
+
+static int set_hash_index(isl_int ***index, unsigned int size, int bits,
+			  struct isl_basic_set *bset, int k)
+{
+	return hash_index(index, size, bits, (struct isl_basic_map *)bset, k);
+}
+
+/* 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 struct isl_basic_map *remove_duplicate_divs(
+	struct 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 struct isl_basic_map *normalize_divs(
+	struct 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;
+	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:
+	isl_mat_free(C);
+	isl_mat_free(C2);
+	isl_mat_free(T);
+	return bmap;
+}
+
+static struct isl_basic_map *set_div_from_lower_bound(
+	struct 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 int ok_to_set_div_from_bound(struct 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 0;
+	}
+
+	/* 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 0;
+	}
+
+	return 1;
+}
+
+/* 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 int 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 1;
+
+	if (isl_seq_last_non_zero(bmap->ineq[ineq] + total + div + 1,
+				  bmap->n_div - (div + 1)) >= 0)
+		return 0;
+
+	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 struct isl_basic_map *check_for_div_constraints(
+	struct 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) {
+		if (isl_int_is_zero(bmap->ineq[k][total + i]))
+			continue;
+		if (isl_int_abs_ge(sum, bmap->ineq[k][total + i]))
+			continue;
+		if (!better_div_constraint(bmap, i, k))
+			continue;
+		if (!ok_to_set_div_from_bound(bmap, i, k))
+			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)
+{
+	unsigned int size;
+	isl_int ***index;
+	int k, l, h;
+	int bits;
+	unsigned total = isl_basic_map_total_dim(bmap);
+	isl_int sum;
+	isl_ctx *ctx;
+
+	if (!bmap || bmap->n_ineq <= 1)
+		return bmap;
+
+	size = round_up(4 * (bmap->n_ineq+1) / 3 - 1);
+	if (size == 0)
+		return bmap;
+	bits = ffs(size) - 1;
+	ctx = isl_basic_map_get_ctx(bmap);
+	index = isl_calloc_array(ctx, isl_int **, size);
+	if (!index)
+		return bmap;
+
+	index[isl_seq_get_hash_bits(bmap->ineq[0]+1, total, bits)] = &bmap->ineq[0];
+	for (k = 1; k < bmap->n_ineq; ++k) {
+		h = hash_index(index, size, bits, bmap, k);
+		if (!index[h]) {
+			index[h] = &bmap->ineq[k];
+			continue;
+		}
+		if (progress)
+			*progress = 1;
+		l = 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(index, size, bits, bmap, k);
+		isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
+		if (!index[h])
+			continue;
+		l = 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);
+
+	free(index);
+	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 use 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;
+}
+
+struct isl_basic_map *isl_basic_map_simplify(struct isl_basic_map *bmap)
+{
+	int progress = 1;
+	if (!bmap)
+		return NULL;
+	while (progress) {
+		progress = 0;
+		if (!bmap)
+			break;
+		if (isl_basic_map_plain_is_empty(bmap))
+			break;
+		bmap = isl_basic_map_normalize_constraints(bmap);
+		bmap = remove_independent_vars_from_divs(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 (struct isl_basic_set *)
+		isl_basic_map_simplify((struct isl_basic_map *)bset);
+}
+
+
+int isl_basic_map_is_div_constraint(__isl_keep isl_basic_map *bmap,
+	isl_int *constraint, unsigned div)
+{
+	unsigned pos;
+
+	if (!bmap)
+		return -1;
+
+	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 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    bmap->n_div-div-1) != -1)
+			return 0;
+	} else if (isl_int_abs_eq(constraint[pos], bmap->div[div][0])) {
+		if (!isl_seq_eq(constraint, bmap->div[div]+1, pos))
+			return 0;
+		if (isl_seq_first_non_zero(constraint+pos+1,
+					    bmap->n_div-div-1) != -1)
+			return 0;
+	} else
+		return 0;
+
+	return 1;
+}
+
+int 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 int div_is_redundant(struct 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 0;
+
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		if (isl_int_is_zero(bmap->ineq[i][pos]))
+			continue;
+		if (!isl_basic_map_is_div_constraint(bmap, bmap->ineq[i], div))
+			return 0;
+	}
+
+	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 0;
+	}
+
+	return 1;
+}
+
+/*
+ * 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 struct isl_basic_map *remove_redundant_divs(struct isl_basic_map *bmap)
+{
+	int i;
+
+	if (!bmap)
+		return NULL;
+
+	for (i = bmap->n_div-1; i >= 0; --i) {
+		if (!div_is_redundant(bmap, i))
+			continue;
+		bmap = isl_basic_map_drop_div(bmap, i);
+	}
+	return bmap;
+}
+
+struct isl_basic_map *isl_basic_map_finalize(struct isl_basic_map *bmap)
+{
+	bmap = remove_redundant_divs(bmap);
+	if (!bmap)
+		return NULL;
+	ISL_F_SET(bmap, ISL_BASIC_SET_FINAL);
+	return bmap;
+}
+
+struct isl_basic_set *isl_basic_set_finalize(struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+		isl_basic_map_finalize((struct isl_basic_map *)bset);
+}
+
+struct isl_set *isl_set_finalize(struct isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return NULL;
+	for (i = 0; i < set->n; ++i) {
+		set->p[i] = isl_basic_set_finalize(set->p[i]);
+		if (!set->p[i])
+			goto error;
+	}
+	return set;
+error:
+	isl_set_free(set);
+	return NULL;
+}
+
+struct isl_map *isl_map_finalize(struct isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_finalize(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;
+}
+
+
+/* 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 struct isl_basic_map *remove_dependent_vars(struct 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;
+		isl_int_set_si(bmap->div[i][0], 0);
+	}
+	return bmap;
+}
+
+/* Eliminate the specified variables from the constraints using
+ * Fourier-Motzkin.  The variables themselves are not removed.
+ */
+struct isl_basic_map *isl_basic_map_eliminate_vars(
+	struct 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 (struct isl_basic_set *)isl_basic_map_eliminate_vars(
+			(struct isl_basic_map *)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);
+}
+
+/* Don't assume equalities are in order, because align_divs
+ * may have changed the order of the divs.
+ */
+static void compute_elimination_index(struct 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(struct isl_basic_set *bset, int *elim)
+{
+	compute_elimination_index((struct isl_basic_map *)bset, elim);
+}
+
+static int reduced_using_equalities(isl_int *dst, isl_int *src,
+	struct 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,
+	struct isl_basic_set *bset, int *elim)
+{
+	return reduced_using_equalities(dst, src,
+					(struct isl_basic_map *)bset, elim);
+}
+
+static struct isl_basic_set *isl_basic_set_reduce_using_equalities(
+	struct isl_basic_set *bset, struct 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;
+}
+
+static struct isl_basic_set *remove_shifted_constraints(
+	struct isl_basic_set *bset, struct isl_basic_set *context)
+{
+	unsigned int size;
+	isl_int ***index;
+	int bits;
+	int k, h, l;
+	isl_ctx *ctx;
+
+	if (!bset || !context)
+		return bset;
+
+	size = round_up(4 * (context->n_ineq+1) / 3 - 1);
+	if (size == 0)
+		return bset;
+	bits = ffs(size) - 1;
+	ctx = isl_basic_set_get_ctx(bset);
+	index = isl_calloc_array(ctx, isl_int **, size);
+	if (!index)
+		return bset;
+
+	for (k = 0; k < context->n_ineq; ++k) {
+		h = set_hash_index(index, size, bits, context, k);
+		index[h] = &context->ineq[k];
+	}
+	for (k = 0; k < bset->n_ineq; ++k) {
+		h = set_hash_index(index, size, bits, bset, k);
+		if (!index[h])
+			continue;
+		l = index[h] - &context->ineq[0];
+		if (isl_int_lt(bset->ineq[k][0], context->ineq[l][0]))
+			continue;
+		bset = isl_basic_set_cow(bset);
+		if (!bset)
+			goto error;
+		isl_basic_set_drop_inequality(bset, k);
+		--k;
+	}
+	free(index);
+	return bset;
+error:
+	free(index);
+	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 "bset" that do not involve any of
+ * the dimensions marked "relevant".
+ */
+static __isl_give isl_basic_set *drop_unrelated_constraints(
+	__isl_take isl_basic_set *bset, int *relevant)
+{
+	int i, dim;
+
+	dim = isl_basic_set_dim(bset, isl_dim_set);
+	for (i = 0; i < dim; ++i)
+		if (!relevant[i])
+			break;
+	if (i >= dim)
+		return bset;
+
+	for (i = bset->n_eq - 1; i >= 0; --i)
+		if (!is_related(bset->eq[i] + 1, dim, relevant))
+			isl_basic_set_drop_equality(bset, i);
+
+	for (i = bset->n_ineq - 1; i >= 0; --i)
+		if (!is_related(bset->ineq[i] + 1, dim, relevant))
+			isl_basic_set_drop_inequality(bset, i);
+
+	return bset;
+}
+
+/* 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;
+	}
+}
+
+/* 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 construct groups of variables that collect variables that
+ * (indirectly) appear in some common constraint of "context".
+ * Each group is identified by the first variable in the group,
+ * except for the special group of variables that appear in "bset"
+ * (or are related to those variables), which is identified by -1.
+ * 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 the -1 group with the variables that appear in "bset".
+ * Then we initialize groups for the remaining variables.
+ * Then we iterate over the constraints of "context" 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.
+ */
+static __isl_give isl_basic_set *drop_irrelevant_constraints(
+	__isl_take isl_basic_set *context, __isl_keep isl_basic_set *bset)
+{
+	isl_ctx *ctx;
+	int *group;
+	int dim;
+	int i, j;
+	int last;
+
+	if (!context || !bset)
+		return isl_basic_set_free(context);
+
+	dim = isl_basic_set_dim(bset, isl_dim_set);
+	ctx = isl_basic_set_get_ctx(bset);
+	group = isl_calloc_array(ctx, int, dim);
+
+	if (!group)
+		goto error;
+
+	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;
+	}
+
+	last = -1;
+	for (i = 0; i < dim; ++i)
+		if (group[i] >= 0)
+			last = group[i] = i;
+	if (last < 0) {
+		free(group);
+		return context;
+	}
+
+	for (i = 0; i < context->n_eq; ++i)
+		update_groups(dim, group, context->eq[i] + 1);
+	for (i = 0; i < context->n_ineq; ++i)
+		update_groups(dim, group, context->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;
+
+	context = drop_unrelated_constraints(context, group);
+
+	free(group);
+	return context;
+error:
+	free(group);
+	return isl_basic_set_free(context);
+}
+
+/* Remove all information from bset that is redundant in the context
+ * of context.  Both bset and context are assumed to be full-dimensional.
+ *
+ * We first remove the inequalities from "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_basic_set *context)
+{
+	int i, k;
+	isl_basic_set *combined = NULL;
+	struct isl_tab *tab = NULL;
+	unsigned context_ineq;
+	unsigned total;
+
+	if (!bset || !context)
+		goto error;
+
+	if (isl_basic_set_is_universe(bset)) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	if (isl_basic_set_is_universe(context)) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	bset = remove_shifted_constraints(bset, context);
+	if (!bset)
+		goto error;
+	if (bset->n_ineq == 0)
+		goto done;
+
+	context = drop_irrelevant_constraints(context, bset);
+	if (!context)
+		goto error;
+	if (isl_basic_set_is_universe(context)) {
+		isl_basic_set_free(context);
+		return bset;
+	}
+
+	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, i) < 0)
+			goto error;
+	if (isl_tab_extend_cons(tab, bset->n_ineq) < 0)
+		goto error;
+	for (i = 0; i < bset->n_ineq; ++i)
+		if (isl_tab_add_ineq(tab, bset->ineq[i]) < 0)
+			goto error;
+	bset = isl_basic_set_add_constraints(combined, bset, 0);
+	combined = NULL;
+	if (!bset)
+		goto error;
+	if (isl_tab_detect_redundant(tab) < 0)
+		goto error;
+	total = isl_basic_set_total_dim(bset);
+	for (i = context_ineq; i < bset->n_ineq; ++i) {
+		int is_empty;
+		if (tab->con[i].is_redundant)
+			continue;
+		tab->con[i].is_redundant = 1;
+		combined = isl_basic_set_dup(bset);
+		combined = isl_basic_set_update_from_tab(combined, tab);
+		combined = isl_basic_set_extend_constraints(combined, 0, 1);
+		k = isl_basic_set_alloc_inequality(combined);
+		if (k < 0)
+			goto error;
+		isl_seq_neg(combined->ineq[k], bset->ineq[i], 1 + total);
+		isl_int_sub_ui(combined->ineq[k][0], combined->ineq[k][0], 1);
+		is_empty = isl_basic_set_is_empty(combined);
+		if (is_empty < 0)
+			goto error;
+		isl_basic_set_free(combined);
+		combined = NULL;
+		if (!is_empty)
+			tab->con[i].is_redundant = 0;
+	}
+	for (i = 0; i < context_ineq; ++i)
+		tab->con[i].is_redundant = 1;
+	bset = isl_basic_set_update_from_tab(bset, tab);
+	if (bset) {
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_IMPLICIT);
+		ISL_F_SET(bset, ISL_BASIC_SET_NO_REDUNDANT);
+	}
+
+	isl_tab_free(tab);
+done:
+	bset = isl_basic_set_simplify(bset);
+	bset = isl_basic_set_finalize(bset);
+	isl_basic_set_free(context);
+	return bset;
+error:
+	isl_tab_free(tab);
+	isl_basic_set_free(combined);
+	isl_basic_set_free(context);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+/* 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 integer affine hull of the intersection,
+ * compute the gist inside this affine hull and then add back
+ * those equalities that are not implied by the context.
+ *
+ * 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, *T2;
+	isl_basic_set *aff;
+	isl_basic_set *aff_context;
+	unsigned total;
+
+	if (!bset || !context)
+		goto error;
+
+	context = drop_irrelevant_constraints(context, bset);
+
+	aff = isl_basic_set_copy(bset);
+	aff = isl_basic_set_intersect(aff, isl_basic_set_copy(context));
+	aff = isl_basic_set_affine_hull(aff);
+	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_full(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, &T2);
+	if (T && T->n_col == 0) {
+		isl_mat_free(T);
+		isl_mat_free(T2);
+		isl_basic_set_free(context);
+		isl_basic_set_free(aff);
+		return isl_basic_set_set_to_empty(bset);
+	}
+
+	aff_context = isl_basic_set_affine_hull(isl_basic_set_copy(context));
+
+	bset = isl_basic_set_preimage(bset, isl_mat_copy(T));
+	context = isl_basic_set_preimage(context, T);
+
+	bset = uset_gist_full(bset, context);
+	bset = isl_basic_set_preimage(bset, T2);
+	bset = isl_basic_set_intersect(bset, aff);
+	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;
+}
+
+/* Normalize the divs in "bmap" in the context of the equalities in "context".
+ * We simply add the equalities in context to bmap and then do a regular
+ * div normalizations.  Better results can be obtained by normalizing
+ * only the divs in bmap than do not also appear in context.
+ * We need to be careful to reduce the divs using the equalities
+ * so that later calls to isl_basic_map_overlying_set wouldn't introduce
+ * spurious constraints.
+ */
+static struct isl_basic_map *normalize_divs_in_context(
+	struct isl_basic_map *bmap, struct isl_basic_map *context)
+{
+	int i;
+	unsigned total_context;
+	int div_eq;
+
+	div_eq = n_pure_div_eq(bmap);
+	if (div_eq == 0)
+		return bmap;
+
+	bmap = isl_basic_map_cow(bmap);
+	if (context->n_div > 0)
+		bmap = isl_basic_map_align_divs(bmap, context);
+
+	total_context = isl_basic_map_total_dim(context);
+	bmap = isl_basic_map_extend_constraints(bmap, context->n_eq, 0);
+	for (i = 0; i < context->n_eq; ++i) {
+		int k;
+		k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			return isl_basic_map_free(bmap);
+		isl_seq_cpy(bmap->eq[k], context->eq[i], 1 + total_context);
+		isl_seq_clr(bmap->eq[k] + 1 + total_context,
+				isl_basic_map_total_dim(bmap) - total_context);
+	}
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	bmap = normalize_divs(bmap, NULL);
+	bmap = isl_basic_map_gauss(bmap, NULL);
+	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.
+ */
+struct isl_basic_map *isl_basic_map_gist(struct isl_basic_map *bmap,
+	struct isl_basic_map *context)
+{
+	isl_basic_set *bset, *eq;
+	isl_basic_map *eq_bmap;
+	unsigned n_div, n_eq, n_ineq;
+
+	if (!bmap || !context)
+		goto error;
+
+	if (isl_basic_map_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;
+
+	if (context->n_eq)
+		bmap = normalize_divs_in_context(bmap, context);
+
+	context = isl_basic_map_align_divs(context, bmap);
+	bmap = isl_basic_map_align_divs(bmap, context);
+	n_div = isl_basic_map_dim(bmap, isl_dim_div);
+
+	bset = uset_gist(isl_basic_map_underlying_set(isl_basic_map_copy(bmap)),
+		    isl_basic_map_underlying_set(isl_basic_map_copy(context)));
+
+	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 = 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;
+}
+
+/* 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 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;
+	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) {
+		isl_map *res = isl_map_universe(isl_map_get_space(map));
+		isl_map_free(map);
+		isl_map_free(context);
+		return res;
+	}
+
+	context = isl_map_compute_divs(context);
+	if (!context)
+		goto error;
+	if (isl_map_n_basic_map(context) == 1) {
+		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 (struct isl_basic_set *)isl_basic_map_gist(
+		(struct isl_basic_map *)bset, (struct isl_basic_map *)context);
+}
+
+__isl_give isl_set *isl_set_gist_basic_set(__isl_take isl_set *set,
+	__isl_take isl_basic_set *context)
+{
+	return (struct isl_set *)isl_map_gist_basic_map((struct isl_map *)set,
+					(struct isl_basic_map *)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 (struct isl_set *)isl_map_gist((struct isl_map *)set,
+					(struct isl_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((struct isl_basic_map *)bset1,
+					      (struct isl_basic_map *)bset2);
+}
+
+/* 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.
+ *
+ * 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)
+{
+	int i, j;
+	isl_bool disjoint;
+	isl_bool intersect;
+	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;
+
+	match = isl_space_match(map1->dim, isl_dim_param,
+				map2->dim, isl_dim_param);
+	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;
+
+	for (i = 0; i < map1->n; ++i) {
+		for (j = 0; j < map2->n; ++j) {
+			isl_bool d = isl_basic_map_plain_is_disjoint(map1->p[i],
+								   map2->p[j]);
+			if (d != isl_bool_true)
+				return d;
+		}
+	}
+	return isl_bool_true;
+}
+
+/* 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 none of these cases apply, we compute the intersection and see if
+ * the result is empty.
+ */
+isl_bool isl_map_is_disjoint(__isl_keep isl_map *map1, __isl_keep isl_map *map2)
+{
+	isl_bool disjoint;
+	isl_bool intersect;
+	isl_map *test;
+
+	disjoint = isl_map_plain_is_disjoint(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;
+
+	test = isl_map_intersect(isl_map_copy(map1), isl_map_copy(map2));
+	disjoint = isl_map_is_empty(test);
+	isl_map_free(test);
+
+	return disjoint;
+}
+
+/* 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_is_universe(bmap1);
+	if (intersect < 0 || intersect)
+		return intersect < 0 ? isl_bool_error : isl_bool_false;
+
+	intersect = isl_basic_map_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((struct isl_map *)set1,
+					(struct isl_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);
+}
+
+/* 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 (execpt for the lower and upper bound)
+ * are of the form
+ *
+ *	e + f (a + m b) >= 0
+ *
+ * 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]))
+				continue;
+			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;
+}
+
+/* Given a lower and an upper bound on div i, construct an inequality
+ * that when nonnegative ensures that this pair of bounds always allows
+ * for an integer value of the given div.
+ * The lower bound is inequality l, while the upper bound is inequality u.
+ * The constructed inequality is stored in ineq.
+ * g, fl, fu are temporary scalars.
+ *
+ * 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
+ */
+static void construct_test_ineq(struct isl_basic_map *bmap, int i,
+	int l, int u, isl_int *ineq, isl_int g, isl_int fl, isl_int fu)
+{
+	unsigned dim;
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+
+	isl_int_gcd(g, bmap->ineq[l][1 + dim + i], bmap->ineq[u][1 + dim + i]);
+	isl_int_divexact(fl, bmap->ineq[l][1 + dim + i], g);
+	isl_int_divexact(fu, bmap->ineq[u][1 + dim + i], g);
+	isl_int_neg(fu, fu);
+	isl_seq_combine(ineq, fl, bmap->ineq[u], fu, bmap->ineq[l],
+			1 + dim + bmap->n_div);
+	isl_int_add(ineq[0], ineq[0], fl);
+	isl_int_add(ineq[0], ineq[0], fu);
+	isl_int_sub_ui(ineq[0], ineq[0], 1);
+	isl_int_mul(g, g, fl);
+	isl_int_mul(g, g, fu);
+	isl_int_sub(ineq[0], ineq[0], g);
+}
+
+/* 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,
+ * the we can eliminate the div using Fourier-Motzkin without
+ * introducing any spurious solutions.
+ */
+static struct isl_basic_map *drop_more_redundant_divs(
+	struct isl_basic_map *bmap, int *pairs, int n)
+{
+	struct isl_tab *tab = NULL;
+	struct isl_vec *vec = NULL;
+	unsigned dim;
+	int remove = -1;
+	isl_int g, fl, fu;
+
+	isl_int_init(g);
+	isl_int_init(fl);
+	isl_int_init(fu);
+
+	if (!bmap)
+		goto error;
+
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+	vec = isl_vec_alloc(bmap->ctx, 1 + dim + bmap->n_div);
+	if (!vec)
+		goto error;
+
+	tab = isl_tab_from_basic_map(bmap, 0);
+
+	while (n > 0) {
+		int i, l, u;
+		int best = -1;
+		enum isl_lp_result res;
+
+		for (i = 0; i < bmap->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][1 + dim + i]))
+				continue;
+			for (u = 0; u < bmap->n_ineq; ++u) {
+				if (!isl_int_is_neg(bmap->ineq[u][1 + dim + i]))
+					continue;
+				construct_test_ineq(bmap, i, l, u,
+						    vec->el, g, fl, fu);
+				res = isl_tab_min(tab, vec->el,
+						  bmap->ctx->one, &g, NULL, 0);
+				if (res == isl_lp_error)
+					goto error;
+				if (res == isl_lp_empty) {
+					bmap = isl_basic_map_set_to_empty(bmap);
+					break;
+				}
+				if (res != isl_lp_ok || isl_int_is_neg(g))
+					break;
+			}
+			if (u < bmap->n_ineq)
+				break;
+		}
+		if (l == bmap->n_ineq) {
+			remove = i;
+			break;
+		}
+		pairs[i] = 0;
+		--n;
+	}
+
+	isl_tab_free(tab);
+	isl_vec_free(vec);
+
+	isl_int_clear(g);
+	isl_int_clear(fl);
+	isl_int_clear(fu);
+
+	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);
+	isl_tab_free(tab);
+	isl_vec_free(vec);
+	isl_int_clear(g);
+	isl_int_clear(fl);
+	isl_int_clear(fu);
+	return NULL;
+}
+
+/* Given a pair of divs div1 and div2 such that, expect 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
+ * (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 the l be
+ *
+ *	div1 + f >=0
+ *
+ * and u
+ *
+ *	-div1 + f' >= 0
+ *
+ * A lower bound on div2
+ *
+ *	n div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ *	(n * (m div 2 + div1) + m t + n f)/g >= 0
+ *
+ * with g = gcd(m,n).
+ * An upper bound
+ *
+ *	-n div2 + t >= 0
+ *
+ * can be replaced by
+ *
+ *	(-n * (m div2 + div1) + m t + n f')/g >= 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.
+ */
+static struct isl_basic_map *coalesce_divs(struct isl_basic_map *bmap,
+	unsigned div1, unsigned div2, unsigned l, unsigned u)
+{
+	isl_int a;
+	isl_int b;
+	isl_int m;
+	unsigned dim, total;
+	int i;
+
+	dim = isl_space_dim(bmap->dim, isl_dim_all);
+	total = 1 + dim + bmap->n_div;
+
+	isl_int_init(a);
+	isl_int_init(b);
+	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])) {
+			isl_int_gcd(b, m, bmap->ineq[i][1 + dim + div2]);
+			isl_int_divexact(a, m, b);
+			isl_int_divexact(b, bmap->ineq[i][1 + dim + div2], b);
+			if (isl_int_is_pos(b)) {
+				isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i],
+						b, bmap->ineq[l], total);
+			} else {
+				isl_int_neg(b, b);
+				isl_seq_combine(bmap->ineq[i], a, bmap->ineq[i],
+						b, 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(a);
+	isl_int_clear(b);
+	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_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 struct isl_basic_map *coalesce_or_drop_more_redundant_divs(
+	struct 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))
+		return bmap;
+
+	return drop_more_redundant_divs(bmap, pairs, n);
+}
+
+/* Remove divs that are not strictly needed.
+ * 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 coefficent of the div in the constraints,
+ * then we can also simply drop the div.
+ *
+ * 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.
+ */
+struct isl_basic_map *isl_basic_map_drop_redundant_divs(
+	struct 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;
+
+		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);
+			free(pairs);
+			return isl_basic_map_drop_redundant_divs(bmap);
+		}
+		if (pairs[i] != 1)
+			continue;
+		if (!isl_seq_is_neg(bmap->ineq[last_pos] + 1,
+				    bmap->ineq[last_neg] + 1,
+				    off + bmap->n_div))
+			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) {
+			if (defined ||
+			    !ok_to_set_div_from_bound(bmap, i, last_pos)) {
+				pairs[i] = 0;
+				--n;
+				continue;
+			}
+			bmap = set_div_from_lower_bound(bmap, i, last_pos);
+			bmap = isl_basic_map_simplify(bmap);
+			free(pairs);
+			return isl_basic_map_drop_redundant_divs(bmap);
+		}
+		if (last_pos > last_neg) {
+			isl_basic_map_drop_inequality(bmap, last_pos);
+			isl_basic_map_drop_inequality(bmap, last_neg);
+		} else {
+			isl_basic_map_drop_inequality(bmap, last_neg);
+			isl_basic_map_drop_inequality(bmap, last_pos);
+		}
+		bmap = isl_basic_map_drop_div(bmap, i);
+		free(pairs);
+		return isl_basic_map_drop_redundant_divs(bmap);
+	}
+
+	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;
+}
+
+struct isl_basic_set *isl_basic_set_drop_redundant_divs(
+	struct isl_basic_set *bset)
+{
+	return (struct isl_basic_set *)
+	    isl_basic_map_drop_redundant_divs((struct isl_basic_map *)bset);
+}
+
+struct isl_map *isl_map_drop_redundant_divs(struct isl_map *map)
+{
+	int i;
+
+	if (!map)
+		return NULL;
+	for (i = 0; i < map->n; ++i) {
+		map->p[i] = isl_basic_map_drop_redundant_divs(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;
+}
+
+struct isl_set *isl_set_drop_redundant_divs(struct isl_set *set)
+{
+	return (struct isl_set *)
+	    isl_map_drop_redundant_divs((struct isl_map *)set);
+}
+
+/* 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.
+ */
+__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);
+	}
+
+	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 (!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..cc75a95
--- /dev/null
+++ b/final/lib/External/isl/isl_map_subtract.c
@@ -0,0 +1,927 @@
+/*
+ * 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>
+
+/* 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 int 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 -1;
+
+	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 -1;
+
+	v = isl_vec_alloc(bmap->ctx, 1 + tab_total);
+	if (!v)
+		return -1;
+
+	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 0;
+error:
+	isl_vec_free(v);
+	return -1;
+}
+
+/* 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.
+ */
+static int 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;
+	int r;
+
+	if (!tab || !bmap)
+		return -1;
+
+	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 -1;
+
+	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 int 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 -1;
+	if (!bmap->n_div)
+		return 0;
+
+	if (!*div_map)
+		*div_map = isl_alloc_array(bmap->ctx, int, bmap->n_div);
+	if (!*div_map)
+		return -1;
+
+	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 -1;
+
+	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, NULL, NULL) < 0)
+				goto error;
+		}
+	}
+
+	isl_vec_free(vec);
+
+	return 0;
+error:
+	isl_vec_free(vec);
+
+	return -1;
+}
+
+/* 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 {
+	int (*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 int 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 ? 0 : -1;
+}
+
+/* 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 (struct isl_set *)
+		isl_map_subtract(
+			(struct isl_map *)set1, (struct isl_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_map *ext_dom;
+
+	if (!isl_map_compatible_domain(map, dom))
+		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_map *ext_dom;
+
+	if (!isl_map_compatible_range(map, dom))
+		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 int 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 -1;
+}
+
+/* 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 1 if "bmap" contains a single element.
+ */
+int isl_basic_map_plain_is_singleton(__isl_keep isl_basic_map *bmap)
+{
+	if (!bmap)
+		return -1;
+	if (bmap->n_div)
+		return 0;
+	if (bmap->n_ineq)
+		return 0;
+	return bmap->n_eq == isl_basic_map_total_dim(bmap);
+}
+
+/* Return 1 if "map" contains a single element.
+ */
+int isl_map_plain_is_singleton(__isl_keep isl_map *map)
+{
+	if (!map)
+		return -1;
+	if (map->n != 1)
+		return 0;
+
+	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;
+	int 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;
+
+	map2 = isl_map_compute_divs(isl_map_copy(map2));
+	if (isl_map_plain_is_singleton(map1)) {
+		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(
+			(struct isl_map *)set1, (struct isl_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 (struct isl_set *)isl_map_make_disjoint((struct isl_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..6755d52
--- /dev/null
+++ b/final/lib/External/isl/isl_map_to_basic_set.c
@@ -0,0 +1,10 @@
+#include <isl/map_to_basic_set.h>
+#include <isl/map.h>
+#include <isl/set.h>
+
+#define KEY_BASE	map
+#define KEY_EQUAL	isl_map_plain_is_equal
+#define VAL_BASE	basic_set
+#define VAL_EQUAL	isl_basic_set_plain_is_equal
+
+#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..f859601
--- /dev/null
+++ b/final/lib/External/isl/isl_mat.c
@@ -0,0 +1,1748 @@
+/*
+ * 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;
+}
+
+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);
+}
+
+struct isl_mat *isl_mat_copy(struct isl_mat *mat)
+{
+	if (!mat)
+		return NULL;
+
+	mat->ref++;
+	return mat;
+}
+
+struct isl_mat *isl_mat_dup(struct 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;
+}
+
+struct isl_mat *isl_mat_cow(struct 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;
+}
+
+int isl_mat_get_element(__isl_keep isl_mat *mat, int row, int col, isl_int *v)
+{
+	if (!mat)
+		return -1;
+	if (row < 0 || row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			return -1);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(mat->ctx, isl_error_invalid, "column out of range",
+			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 (!mat)
+		return NULL;
+	ctx = isl_mat_get_ctx(mat);
+	if (row < 0 || row >= mat->n_row)
+		isl_die(ctx, isl_error_invalid, "row out of range",
+			return NULL);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(ctx, isl_error_invalid, "column out of range",
+			return NULL);
+	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 (!mat)
+		return NULL;
+	if (row < 0 || row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			goto error);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(mat->ctx, isl_error_invalid, "column out of range",
+			goto error);
+	isl_int_set(mat->row[row][col], v);
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+__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 (!mat)
+		return NULL;
+	if (row < 0 || row >= mat->n_row)
+		isl_die(mat->ctx, isl_error_invalid, "row out of range",
+			goto error);
+	if (col < 0 || col >= mat->n_col)
+		isl_die(mat->ctx, isl_error_invalid, "column out of range",
+			goto error);
+	isl_int_set_si(mat->row[row][col], v);
+	return mat;
+error:
+	isl_mat_free(mat);
+	return NULL;
+}
+
+/* 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;
+}
+
+__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;
+}
+
+struct isl_vec *isl_mat_vec_product(struct isl_mat *mat, struct 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;
+}
+
+struct isl_vec *isl_vec_mat_product(struct isl_vec *vec, struct 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;
+}
+
+struct isl_mat *isl_mat_aff_direct_sum(struct isl_mat *left,
+	struct 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.
+ */
+struct isl_mat *isl_mat_left_hermite(struct isl_mat *M, int neg,
+	struct isl_mat **U, struct 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;
+}
+
+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;
+}
+
+struct isl_mat *isl_mat_lin_to_aff(struct 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 void inv_exchange(struct isl_mat *left, struct isl_mat *right,
+	unsigned i, unsigned j)
+{
+	left = isl_mat_swap_rows(left, i, j);
+	right = isl_mat_swap_rows(right, i, j);
+}
+
+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
+ */
+struct isl_mat *isl_mat_inverse_product(struct isl_mat *left,
+	struct 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)
+			inv_exchange(left, right, pivot, row);
+		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]))
+				inv_exchange(left, right, row, first);
+			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);
+}
+
+struct isl_mat *isl_mat_right_inverse(struct 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;
+}
+
+struct isl_mat *isl_mat_transpose(struct 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;
+}
+
+struct isl_mat *isl_mat_swap_cols(struct 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;
+}
+
+struct isl_mat *isl_mat_swap_rows(struct 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 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.
+ */
+struct isl_basic_set *isl_basic_set_preimage(struct isl_basic_set *bset,
+	struct 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;
+}
+
+struct isl_set *isl_set_preimage(struct isl_set *set, struct isl_mat *mat)
+{
+	int i;
+
+	set = isl_set_cow(set);
+	if (!set)
+		return NULL;
+
+	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 pos in the rows q
+ * by x' with x = M x' with M the matrix mat.
+ * That is, replace the corresponding coefficients c by c M.
+ */
+static int transform(isl_ctx *ctx, isl_int **q, unsigned n,
+	unsigned pos, __isl_take isl_mat *mat)
+{
+	int i;
+	isl_mat *t;
+
+	t = isl_mat_sub_alloc6(ctx, q, 0, n, pos, 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] + pos, t->row[i], t->n_col);
+	isl_mat_free(t);
+	return 0;
+}
+
+/* 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)
+{
+	isl_ctx *ctx;
+	unsigned pos;
+
+	bset = isl_basic_set_cow(bset);
+	if (!bset || !trans)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(bset);
+	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_set_dim(bset, type))
+		isl_die(trans->ctx, isl_error_invalid,
+			"oversized transformation matrix", goto error);
+
+	pos = isl_basic_set_offset(bset, type) + first;
+
+	if (transform(ctx, bset->eq, bset->n_eq, pos, isl_mat_copy(trans)) < 0)
+		goto error;
+	if (transform(ctx, bset->ineq, bset->n_ineq, pos,
+		      isl_mat_copy(trans)) < 0)
+		goto error;
+	if (transform(ctx, bset->div, bset->n_div, 1 + pos,
+		      isl_mat_copy(trans)) < 0)
+		goto error;
+
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED);
+	ISL_F_CLR(bset, ISL_BASIC_SET_NORMALIZED_DIVS);
+
+	isl_mat_free(trans);
+	return bset;
+error:
+	isl_mat_free(trans);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+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);
+}
+
+struct isl_mat *isl_mat_drop_cols(struct 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;
+}
+
+struct isl_mat *isl_mat_drop_rows(struct 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]);
+}
+
+struct isl_mat *isl_mat_unimodular_complete(struct 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;
+}
+
+int isl_mat_is_equal(__isl_keep isl_mat *mat1, __isl_keep isl_mat *mat2)
+{
+	int i;
+
+	if (!mat1 || !mat2)
+		return -1;
+
+	if (mat1->n_row != mat2->n_row)
+		return 0;
+
+	if (mat1->n_col != mat2->n_col)
+		return 0;
+
+	for (i = 0; i < mat1->n_row; ++i)
+		if (!isl_seq_eq(mat1->row[i], mat2->row[i], mat1->n_col))
+			return 0;
+
+	return 1;
+}
+
+__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;
+}
+
+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);
+}
+
+__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..566634d
--- /dev/null
+++ b/final/lib/External/isl/isl_mat_private.h
@@ -0,0 +1,46 @@
+#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;
+};
+
+__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_give isl_mat *isl_mat_diag(isl_ctx *ctx, unsigned n_row, isl_int d);
+
+__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);
+
+int isl_mat_is_scaled_identity(__isl_keep isl_mat *mat);
+
+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);
+
+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_morph.c b/final/lib/External/isl/isl_morph.c
new file mode 100644
index 0000000..9c14c80
--- /dev/null
+++ b/final/lib/External/isl/isl_morph.c
@@ -0,0 +1,917 @@
+/*
+ * 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>
+
+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);
+}
+
+void isl_morph_free(__isl_take isl_morph *morph)
+{
+	if (!morph)
+		return;
+
+	if (--morph->ref > 0)
+		return;
+
+	isl_basic_set_free(morph->dom);
+	isl_basic_set_free(morph->ran);
+	isl_mat_free(morph->map);
+	isl_mat_free(morph->inv);
+	free(morph);
+}
+
+/* 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));
+}
+
+/* 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;
+}
+
+/* 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 + k], 1 + total);
+	}
+
+	return eq;
+error:
+	isl_basic_set_free(eq);
+	return NULL;
+}
+
+/* Given a basic set, exploit the equalties in the basic set to construct
+ * a morphishm that maps the basic set to a lower-dimensional space.
+ * Specifically, the morphism reduces the number of dimensions of type "type".
+ *
+ * This function is a slight generalization of isl_mat_variable_compression
+ * in that it allows the input to be parametric and that it allows for the
+ * compression of either parameters or set variables.
+ *
+ * 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.
+ *
+ * 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(p) + H1 x1' = 0   or   x1' = H1^{-1} C(p) = C'(p)
+ *
+ * If the denominator of the constant term does not divide the
+ * the common denominator of the parametric terms, 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, an empty morphism is returned.
+ * Otherwise, the transformation is given by
+ *
+ *		x = U1 H1^{-1} C(p) + U2 x2'
+ *
+ * The inverse transformation is simply
+ *
+ *		x2' = Q2 x
+ *
+ * Both matrices are extended to map the full original space to the full
+ * compressed space.
+ */
+__isl_give isl_morph *isl_basic_set_variable_compression(
+	__isl_keep isl_basic_set *bset, enum isl_dim_type type)
+{
+	unsigned otype;
+	unsigned ntype;
+	unsigned orest;
+	unsigned nrest;
+	int f_eq, n_eq;
+	isl_space *dim;
+	isl_mat *H, *U, *Q, *C = NULL, *H1, *U1, *U2;
+	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);
+
+	H = isl_mat_sub_alloc6(bset->ctx, bset->eq, f_eq, n_eq, otype, ntype);
+	H = isl_mat_left_hermite(H, 0, &U, &Q);
+	if (!H || !U || !Q)
+		goto error;
+	Q = isl_mat_drop_rows(Q, 0, n_eq);
+	Q = isl_mat_diagonal(isl_mat_identity(bset->ctx, otype), Q);
+	Q = isl_mat_diagonal(Q, isl_mat_identity(bset->ctx, nrest));
+	C = isl_mat_alloc(bset->ctx, 1 + n_eq, otype);
+	if (!C)
+		goto error;
+	isl_int_set_si(C->row[0][0], 1);
+	isl_seq_clr(C->row[0] + 1, otype - 1);
+	isl_mat_sub_neg(C->ctx, C->row + 1, bset->eq + f_eq, n_eq, 0, 0, otype);
+	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])) {
+		int i;
+		isl_int g;
+
+		isl_int_init(g);
+		for (i = 0; i < n_eq; ++i) {
+			isl_seq_gcd(C->row[1 + i] + 1, otype - 1, &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 < n_eq) {
+			isl_mat_free(C);
+			isl_mat_free(U);
+			isl_mat_free(Q);
+			return isl_morph_empty(bset);
+		}
+
+		C = isl_mat_normalize(C);
+	}
+
+	U1 = isl_mat_sub_alloc(U, 0, U->n_row, 0, n_eq);
+	U1 = isl_mat_lin_to_aff(U1);
+	U2 = isl_mat_sub_alloc(U, 0, U->n_row, n_eq, U->n_row - n_eq);
+	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, otype - 1);
+	C = isl_mat_diagonal(C, isl_mat_identity(bset->ctx, nrest));
+
+	dim = isl_space_copy(bset->dim);
+	dim = isl_space_drop_dims(dim, type, 0, ntype);
+	dim = isl_space_add_dims(dim, type, ntype - n_eq);
+	ran = isl_basic_set_universe(dim);
+	dom = copy_equalities(bset, f_eq, n_eq);
+
+	return isl_morph_alloc(dom, ran, Q, C);
+error:
+	isl_mat_free(C);
+	isl_mat_free(H);
+	isl_mat_free(U);
+	isl_mat_free(Q);
+	return NULL;
+}
+
+/* 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 equalties
+ * 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..4f6b8d4
--- /dev/null
+++ b/final/lib/External/isl/isl_morph.h
@@ -0,0 +1,86 @@
+/*
+ * 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);
+void 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_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..d4f70b2
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_apply_templ.c
@@ -0,0 +1,81 @@
+/*
+ * 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_ctx *ctx;
+
+	if (!multi || !set)
+		goto error;
+
+	if (isl_space_match(multi->space, isl_dim_param,
+			    set->dim, isl_dim_param))
+		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_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_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..4fac96b
--- /dev/null
+++ b/final/lib/External/isl/isl_multi_templ.c
@@ -0,0 +1,1488 @@
+/*
+ * 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;
+	int 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_reordering *exp;
+
+	if (!multi || !model)
+		goto error;
+
+	if (isl_space_match(multi->space, isl_dim_param,
+			     model, isl_dim_param)) {
+		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),cow)(multi));
+
+	multi->space = isl_space_drop_dims(multi->space, type, first, n);
+	if (!multi->space)
+		return FN(MULTI(BASE),cow)(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),cow)(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;
+
+	if (!multi1 || !multi2)
+		goto error;
+	if (isl_space_match(multi1->space, isl_dim_param,
+			    multi2->space, isl_dim_param))
+		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)
+		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_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;
+}
+
+#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..cdb578a
--- /dev/null
+++ b/final/lib/External/isl/isl_options.c
@@ -0,0 +1,327 @@
+/*
+ * 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_split_scaled, 0,
+	"schedule-split-scaled", 1,
+	"split non-tilable bands with scaled schedules")
+ISL_ARG_BOOL(struct isl_options, schedule_separate_components, 0,
+	"schedule-separate-components", 1,
+	"separate components in dependence graph")
+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_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_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_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,
+	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_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_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_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_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_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_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..0907d21
--- /dev/null
+++ b/final/lib/External/isl/isl_options_private.h
@@ -0,0 +1,67 @@
+#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_split_scaled;
+	int			schedule_separate_components;
+	unsigned		schedule_algorithm;
+	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_build_atomic_upper_bound;
+	int			ast_build_prefer_pdiv;
+	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..8ebe10e
--- /dev/null
+++ b/final/lib/External/isl/isl_output.c
@@ -0,0 +1,2791 @@
+/*
+ * 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/ast_build.h>
+#include <isl_sort.h>
+
+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((struct isl_basic_map *)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((struct isl_basic_map *)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((struct isl_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;
+}
+
+static __isl_give isl_printer *print_name(__isl_keep isl_space *dim,
+	__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(dim, 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(dim) || 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(dim, 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;
+}
+
+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 *dim,
+	__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(dim, &pos);
+	print_div_def = type == isl_dim_div && div &&
+			!isl_int_is_zero(div->row[pos][0]);
+
+	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(dim, div, pos, p);
+	else
+		p = print_name(dim, 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;
+}
+
+static __isl_give isl_printer *print_affine(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __isl_take isl_printer *p, isl_int *c)
+{
+	unsigned len = 1 + isl_basic_map_total_dim(bmap);
+	return print_affine_of_len(dim, NULL, p, c, len);
+}
+
+/* Internal data structure for 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;
+};
+
+/* 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;
+}
+
+static __isl_give isl_printer *print_space(__isl_keep isl_space *dim,
+	__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(dim))
+		;
+	else if (isl_space_is_set(dim))
+		p = print_tuple(dim, p, isl_dim_set, data);
+	else {
+		p = print_tuple(dim, p, isl_dim_in, data);
+		p = isl_printer_print_str(p, s_to[data->latex]);
+		p = print_tuple(dim, 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;
+}
+
+static __isl_give isl_printer *print_constraint(struct isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __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(dim, NULL, 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, dim, p, c);
+
+	return p;
+}
+
+static __isl_give isl_printer *print_constraints(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __isl_take isl_printer *p, int latex)
+{
+	int i;
+	struct isl_vec *c;
+	unsigned total = isl_basic_map_total_dim(bmap);
+
+	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, dim, p, c->el, l,
+				    "=", i == bmap->n_eq - 1, latex);
+	}
+	for (i = 0; i < bmap->n_ineq; ++i) {
+		int l = isl_seq_last_non_zero(bmap->ineq[i], 1 + total);
+		int s;
+		const char *op;
+		if (l < 0)
+			continue;
+		s = isl_int_sgn(bmap->ineq[i][l]);
+		if (s < 0)
+			isl_seq_cpy(c->el, bmap->ineq[i], 1 + total);
+		else
+			isl_seq_neg(c->el, bmap->ineq[i], 1 + total);
+		op = s < 0 ? s_le[latex] : s_ge[latex];
+		p = print_constraint(bmap, dim, p, c->el, l,
+					op, !bmap->n_eq && !i, latex);
+	}
+
+	isl_vec_free(c);
+
+	return p;
+error:
+	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 = 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, with their definitions
+ * (provided that they have a definition and we are printing in isl format).
+ */
+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 i;
+	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 (i)
+			p = isl_printer_print_str(p, ", ");
+		p = print_name(space, p, isl_dim_div, i, latex);
+		if (p->output_format != ISL_FORMAT_ISL ||
+		    isl_int_is_zero(div->row[i][0]))
+			continue;
+		p = isl_printer_print_str(p, " = ");
+		p = print_div(space, div, i, p);
+	}
+
+	return p;
+}
+
+static __isl_give isl_printer *print_disjunct(__isl_keep isl_basic_map *bmap,
+	__isl_keep isl_space *dim, __isl_take isl_printer *p, int latex)
+{
+	if (bmap->n_div > 0) {
+		isl_space *space;
+		isl_mat *div;
+
+		space = isl_basic_map_get_space(bmap);
+		div = isl_basic_map_get_divs(bmap);
+		p = isl_printer_print_str(p, s_open_exists[latex]);
+		p = print_div_list(p, space, div, latex);
+		isl_space_free(space);
+		isl_mat_free(div);
+		p = isl_printer_print_str(p, ": ");
+	}
+
+	p = print_constraints(bmap, dim, p, latex);
+
+	if (bmap->n_div > 0)
+		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_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;
+}
+
+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);
+
+	if (isl_basic_map_dim(bmap, isl_dim_param) > 0) {
+		p = print_tuple(bmap->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	p = 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;
+}
+
+static __isl_give isl_printer *print_disjuncts(__isl_keep isl_map *map,
+	__isl_take isl_printer *p, int latex)
+{
+	int i;
+
+	if (isl_map_plain_is_universe(map))
+		return p;
+
+	p = isl_printer_print_str(p, s_such_that[latex]);
+	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], map->dim, 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).
+ * 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_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, 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.  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) {
+		pos += 1 + isl_space_offset(data->space, data->type);
+		p = print_affine_of_len(eq->dim, 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)
+{
+	struct isl_print_space_data data = { 0 };
+	int i;
+	int rational;
+
+	data.print_dim = &print_dim_eq;
+	for (i = 0; i < n; ++i) {
+		isl_space *dim;
+
+		if (!split[i].map)
+			break;
+		dim = split[i].map->dim;
+		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 = print_space(dim, p, rational, &data);
+		p = print_disjuncts_map(split[i].map, 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 (map->n > 0)
+		split = split_aff(map);
+	if (split) {
+		p = print_split_map(p, split, map->n);
+	} else {
+		rational = map->n > 0 &&
+		    ISL_F_ISSET(map->p[0], ISL_BASIC_MAP_RATIONAL);
+		p = print_space(map->dim, p, rational, &data);
+		p = print_disjuncts_map(map, 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 };
+
+	if (isl_map_dim(map, isl_dim_param) > 0) {
+		p = print_tuple(map->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+	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;
+	if (isl_map_dim(map, isl_dim_param) > 0) {
+		p = print_tuple(map->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, s_to[1]);
+	}
+	p = isl_printer_print_str(p, s_open_set[1]);
+	data.print_dim = &print_dim_eq;
+	data.user = aff;
+	p = print_space(map->dim, p, 0, &data);
+	p = print_disjuncts_map(map, 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((isl_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((isl_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 *dim;
+
+	dim = isl_union_map_get_space(umap);
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+	isl_space_free(dim);
+	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;
+}
+
+static __isl_give isl_printer *upoly_print(__isl_keep struct isl_upoly *up,
+	__isl_keep isl_space *dim, __isl_keep isl_mat *div,
+	__isl_take isl_printer *p, int outer)
+{
+	int i, n, first, print_parens;
+	struct isl_upoly_rec *rec;
+
+	if (!p || !up || !dim || !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 ||
+		    (outer && rec->up.var >= isl_space_dim(dim, isl_dim_all));
+	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], dim, div, p, 0);
+		}
+		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, dim, 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, 1);
+	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;
+
+	if (isl_space_dim(qp->dim, isl_dim_param) > 0) {
+		p = print_tuple(qp->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	if (!isl_space_is_params(qp->dim)) {
+		p = 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;
+}
+
+static __isl_give isl_printer *print_qpolynomial_c(__isl_take isl_printer *p,
+	__isl_keep isl_space *dim, __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, dim, qp->div, p, 0);
+	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) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		if (!isl_space_is_params(pwqp->p[i].set->dim)) {
+			p = print_space(pwqp->p[i].set->dim, p, 0, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = print_qpolynomial(p, pwqp->p[i].qp);
+		p = print_disjuncts((isl_map *)pwqp->p[i].set, p, 0);
+	}
+
+	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;
+
+	if (isl_space_dim(pwqp->dim, isl_dim_param) > 0) {
+		p = print_tuple(pwqp->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	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) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		if (!isl_space_is_params(pwf->p[i].set->dim)) {
+			p = print_space(pwf->p[i].set->dim, p, 0, &data);
+			p = isl_printer_print_str(p, " -> ");
+		}
+		p = qpolynomial_fold_print(pwf->p[i].fold, p);
+		p = print_disjuncts((isl_map *)pwf->p[i].set, p, 0);
+	}
+
+	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 };
+
+	if (isl_space_dim(pwf->dim, isl_dim_param) > 0) {
+		p = print_tuple(pwf->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	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_basic_set_is_div_constraint(bset, c, 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;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial *pwqp)
+{
+	int i;
+
+	if (pwqp->n == 1 && isl_set_plain_is_universe(pwqp->p[0].set))
+		return print_qpolynomial_c(p, pwqp->dim, pwqp->p[0].qp);
+
+	for (i = 0; i < pwqp->n; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, pwqp->dim, pwqp->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_qpolynomial_c(p, pwqp->dim, pwqp->p[i].qp);
+		p = isl_printer_print_str(p, ") : ");
+	}
+
+	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 *dim;
+
+	dim = isl_union_pw_qpolynomial_get_space(upwqp);
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	isl_space_free(dim);
+	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;
+}
+
+static __isl_give isl_printer *print_qpolynomial_fold_c(
+	__isl_take isl_printer *p, __isl_keep isl_space *dim,
+	__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, dim, 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;
+}
+
+static __isl_give isl_printer *print_pw_qpolynomial_fold_c(
+	__isl_take isl_printer *p, __isl_keep isl_pw_qpolynomial_fold *pwf)
+{
+	int i;
+
+	if (pwf->n == 1 && isl_set_plain_is_universe(pwf->p[0].set))
+		return print_qpolynomial_fold_c(p, pwf->dim, pwf->p[0].fold);
+
+	for (i = 0; i < pwf->n; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, pwf->dim, pwf->p[i].set);
+		p = isl_printer_print_str(p, ") ? (");
+		p = print_qpolynomial_fold_c(p, pwf->dim, pwf->p[i].fold);
+		p = isl_printer_print_str(p, ") : ");
+	}
+
+	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 *dim;
+
+	dim = isl_union_pw_qpolynomial_fold_get_space(upwf);
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	isl_space_free(dim);
+	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;
+}
+
+__isl_give isl_printer *isl_printer_print_constraint(__isl_take isl_printer *p,
+	__isl_keep isl_constraint *c)
+{
+	isl_basic_map *bmap;
+
+	if (!p || !c)
+		goto error;
+
+	bmap = isl_basic_map_from_constraint(isl_constraint_copy(c));
+	p = isl_printer_print_basic_map(p, bmap);
+	isl_basic_map_free(bmap);
+	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 *dim)
+{
+	struct isl_print_space_data data = { 0 };
+
+	if (!dim)
+		goto error;
+
+	if (isl_space_dim(dim, isl_dim_param) > 0) {
+		p = print_tuple(dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+
+	p = isl_printer_print_str(p, "{ ");
+	if (isl_space_is_params(dim))
+		p = isl_printer_print_str(p, s_such_that[0]);
+	else
+		p = print_space(dim, 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;
+
+	if (isl_local_space_dim(ls, isl_dim_param) > 0) {
+		p = print_tuple(ls->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	p = 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);
+	} 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;
+
+	if (isl_local_space_dim(aff->ls, isl_dim_param) > 0) {
+		p = print_tuple(aff->ls->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	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) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_aff(p, pa->p[i].aff);
+		p = print_disjuncts((isl_map *)pa->p[i].set, p, 0);
+	}
+
+	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;
+
+	if (isl_space_dim(pwaff->dim, isl_dim_param) > 0) {
+		p = print_tuple(pwaff->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	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);
+	if (isl_space_dim(space, isl_dim_param) > 0) {
+		p = print_tuple(space, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+	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 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;
+
+	if (isl_space_dim(maff->space, isl_dim_param) > 0) {
+		p = print_tuple(maff->space, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	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) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_multi_aff(p, pma->p[i].maff);
+		p = print_disjuncts((isl_map *)pma->p[i].set, p, 0);
+	}
+	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;
+
+	if (isl_space_dim(pma->dim, isl_dim_param) > 0) {
+		p = print_tuple(pma->dim, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	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;
+}
+
+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;
+
+	for (i = 0; i < pma->n - 1; ++i) {
+		p = isl_printer_print_str(p, "(");
+		p = print_set_c(p, pma->dim, 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, ") : ");
+	}
+
+	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);
+	if (isl_space_dim(space, isl_dim_param) > 0) {
+		p = print_tuple(space, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+	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) {
+		if (i)
+			p = isl_printer_print_str(p, "; ");
+		p = print_aff_body(p, pa->p[i].aff);
+		p = print_disjuncts(pa->p[i].set, p, 0);
+	}
+	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);
+
+	if (isl_space_dim(mpa->space, isl_dim_param) > 0) {
+		p = print_tuple(mpa->space, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	data.print_dim = &print_dim_mpa;
+	data.user = mpa;
+	p = 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);
+
+	if (isl_space_dim(mv->space, isl_dim_param) > 0) {
+		p = print_tuple(mv->space, p, isl_dim_param, &data);
+		p = isl_printer_print_str(p, " -> ");
+	}
+	p = isl_printer_print_str(p, "{ ");
+	data.print_dim = &print_dim_mv;
+	data.user = mv;
+	p = 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);
+	if (isl_space_dim(space, isl_dim_param) > 0) {
+		struct isl_print_space_data space_data = { 0 };
+		p = print_tuple(space, p, isl_dim_param, &space_data);
+		p = isl_printer_print_str(p, s_to[0]);
+	}
+
+	data.print_dim = &print_union_pw_aff_dim;
+	data.user = mupa;
+
+	p = 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_point.c b/final/lib/External/isl/isl_point.c
new file mode 100644
index 0000000..a78662f
--- /dev/null
+++ b/final/lib/External/isl/isl_point.c
@@ -0,0 +1,588 @@
+#include <isl_map_private.h>
+#include <isl_point_private.h>
+#include <isl/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/deprecated/point_int.h>
+
+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;
+}
+
+void isl_point_free(__isl_take isl_point *pnt)
+{
+	if (!pnt)
+		return;
+
+	if (--pnt->ref > 0)
+		return;
+
+	isl_space_free(pnt->dim);
+	isl_vec_free(pnt->vec);
+	free(pnt);
+}
+
+__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;
+}
+
+int isl_map_contains_point(__isl_keep isl_map *map, __isl_keep isl_point *point)
+{
+	int i;
+	int found = 0;
+
+	if (!map || !point)
+		return -1;
+
+	map = isl_map_copy(map);
+	map = isl_map_compute_divs(map);
+	if (!map)
+		return -1;
+
+	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 -1;
+}
+
+isl_bool isl_set_contains_point(__isl_keep isl_set *set,
+	__isl_keep isl_point *point)
+{
+	return isl_map_contains_point((isl_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);
+}
+
+__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;
+	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);
+	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);
+}
+
+__isl_give isl_printer *isl_printer_print_point(
+	__isl_take isl_printer *p, __isl_keep isl_point *pnt)
+{
+	int i;
+	unsigned nparam;
+	unsigned dim;
+
+	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);
+	dim = isl_space_dim(pnt->dim, isl_dim_set);
+	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, " -> ");
+	}
+	p = isl_printer_print_str(p, "[");
+	for (i = 0; i < dim; ++i) {
+		if (i)
+			p = isl_printer_print_str(p, ", ");
+		p = isl_printer_print_isl_int(p, pnt->vec->el[1 + nparam + 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, "]");
+	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..414e7c0
--- /dev/null
+++ b/final/lib/External/isl/isl_polynomial.c
@@ -0,0 +1,4848 @@
+/*
+ * 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_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;
+}
+
+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;
+}
+
+/* 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_space_dim(qp->dim, type);
+}
+
+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);
+}
+
+void isl_upoly_free(__isl_take struct isl_upoly *up)
+{
+	if (!up)
+		return;
+
+	if (--up->ref > 0)
+		return;
+
+	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);
+}
+
+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 int compatible_divs(__isl_keep isl_mat *div1, __isl_keep isl_mat *div2)
+{
+	int n_row, n_col;
+	int equal;
+
+	isl_assert(div1->ctx, div1->n_row >= div2->n_row &&
+				div1->n_col >= div2->n_col, return -1);
+
+	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)
+{
+	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);
+	if (!compatible_divs(qp1->div, qp2->div))
+		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)
+{
+	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);
+	if (!compatible_divs(qp1->div, qp2->div))
+		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;
+}
+
+/* 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 expression "aff"
+ * (if it too depends on "div").
+ */
+static void reduce_div(__isl_keep isl_qpolynomial *qp, int div,
+	__isl_keep isl_vec *aff)
+{
+	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]);
+		if (!isl_int_is_zero(aff->el[1 + total + div]))
+			isl_int_addmul(aff->el[i], v, aff->el[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 "aff").  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_vec *aff)
+{
+	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]);
+	if (!isl_int_is_zero(aff->el[1 + total + div]))
+		isl_int_neg(aff->el[1 + total + div], aff->el[1 + total + div]);
+	isl_mat_col_mul(qp->div, 2 + total + div,
+			qp->div->ctx->negone, 2 + total + div);
+}
+
+/* Assuming "qp" is a monomial, reduce all its divs 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.
+ *
+ * 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_vec *aff = NULL;
+	struct isl_upoly *s;
+	unsigned n_div;
+
+	if (!qp)
+		return NULL;
+
+	aff = isl_vec_alloc(qp->div->ctx, qp->div->n_col - 1);
+	aff = isl_vec_clr(aff);
+	if (!aff)
+		goto error;
+
+	isl_int_set_si(aff->el[1 + qp->upoly->var], 1);
+
+	for (i = 0; i < qp->div->n_row; ++i) {
+		normalize_div(qp, i);
+		reduce_div(qp, i, aff);
+		if (needs_invert(qp->div, i)) {
+			invert_div(qp, i, aff);
+			reduce_div(qp, i, aff);
+		}
+	}
+
+	s = isl_upoly_from_affine(qp->div->ctx, aff->el,
+				  qp->div->ctx->one, aff->size);
+	qp->upoly = isl_upoly_subs(qp->upoly, qp->upoly->var, 1, &s);
+	isl_upoly_free(s);
+	if (!qp->upoly)
+		goto error;
+
+	isl_vec_free(aff);
+
+	n_div = qp->div->n_row;
+	qp = substitute_non_divs(qp);
+	qp = sort_divs(qp);
+	if (qp && qp->div->n_row < n_div)
+		return reduce_divs(qp);
+
+	return qp;
+error:
+	isl_qpolynomial_free(qp);
+	isl_vec_free(aff);
+	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;
+	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);
+}
+
+#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_templ.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;
+}
+
+__isl_give isl_val *isl_qpolynomial_eval(__isl_take isl_qpolynomial *qp,
+	__isl_take isl_point *pnt)
+{
+	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);
+
+	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 (n == 0)
+		return qp;
+
+	qp = isl_qpolynomial_cow(qp);
+	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;
+
+	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.
+ */
+int isl_qpolynomial_as_polynomial_on_domain(__isl_keep isl_qpolynomial *qp,
+	__isl_keep isl_basic_set *bset,
+	int (*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)
+		goto 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);
+error:
+	return -1;
+}
+
+/* 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)
+{
+	if (!qp || !model)
+		goto error;
+
+	if (!isl_space_match(qp->dim, isl_dim_param, model, isl_dim_param)) {
+		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
+ */
+static __isl_give isl_pw_qpolynomial *constant_on_domain(
+	__isl_take isl_basic_set *bset, int cst)
+{
+	isl_space *dim;
+	isl_qpolynomial *qp;
+
+	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 *dim;
+	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);
+
+	dim = isl_basic_set_get_space(bset);
+	dim = isl_space_domain(dim);
+	set = isl_set_universe(isl_space_copy(dim));
+	qp = isl_qpolynomial_one_on_domain(dim);
+	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))
+{
+	int 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 int 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 0;
+}
+
+/* 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_stat poly_entry(void **entry, void *user)
+{
+	int *sign = user;
+	isl_pw_qpolynomial **pwqp = (isl_pw_qpolynomial **)entry;
+
+	*pwqp = isl_pw_qpolynomial_to_polynomial(*pwqp, *sign);
+
+	return *pwqp ? isl_stat_ok : isl_stat_error;
+}
+
+__isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_to_polynomial(
+	__isl_take isl_union_pw_qpolynomial *upwqp, int sign)
+{
+	upwqp = isl_union_pw_qpolynomial_cow(upwqp);
+	if (!upwqp)
+		return NULL;
+
+	if (isl_hash_table_foreach(upwqp->space->ctx, &upwqp->table,
+				   &poly_entry, &sign) < 0)
+		goto error;
+
+	return upwqp;
+error:
+	isl_union_pw_qpolynomial_free(upwqp);
+	return NULL;
+}
+
+__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..7b7ef19
--- /dev/null
+++ b/final/lib/External/isl/isl_polynomial_private.h
@@ -0,0 +1,253 @@
+#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);
+void 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);
+
+__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_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);
+
+__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..a0b3823
--- /dev/null
+++ b/final/lib/External/isl/isl_printer.c
@@ -0,0 +1,764 @@
+#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_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;
+}
+
+/* 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);
+}
+
+char *isl_printer_get_str(__isl_keep isl_printer *printer)
+{
+	if (!printer || !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;
+
+	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)
+{
+	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..29f3db5
--- /dev/null
+++ b/final/lib/External/isl/isl_printer_private.h
@@ -0,0 +1,34 @@
+#include <isl/printer.h>
+#include <isl_yaml.h>
+
+struct isl_printer_ops;
+
+/* A printer to a file or a string.
+ *
+ * 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.
+ */
+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;
+	char		*indent_prefix;
+	char		*prefix;
+	char		*suffix;
+	int		width;
+
+	int			yaml_style;
+	int			yaml_depth;
+	int			yaml_size;
+	enum isl_yaml_state	*yaml_state;
+};
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..f7106cf
--- /dev/null
+++ b/final/lib/External/isl/isl_pw_templ.c
@@ -0,0 +1,2136 @@
+/*
+ * 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_val_private.h>
+
+#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)
+
+#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;
+
+	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);
+	if (!isl_space_match(pw->dim, isl_dim_param, model, isl_dim_param)) {
+		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;
+
+	if (!pw1 || !pw2)
+		goto error;
+	if (isl_space_match(pw1->dim, isl_dim_param, pw2->dim, isl_dim_param))
+		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;
+
+	if (!pw || !set)
+		goto error;
+	if (isl_space_match(pw->dim, isl_dim_param, set->dim, isl_dim_param))
+		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_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;
+	}
+
+	if (!isl_space_match(pw->dim, isl_dim_param,
+				context->dim, isl_dim_param)) {
+		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));
+}
+
+__isl_give PW *FN(PW,coalesce)(__isl_take PW *pw)
+{
+	int i, j;
+
+	if (!pw)
+		return NULL;
+	if (pw->n == 0)
+		return pw;
+
+	for (i = pw->n - 1; i >= 0; --i) {
+		for (j = i - 1; j >= 0; --j) {
+			if (!FN(EL,plain_is_equal)(pw->p[i].FIELD,
+							pw->p[j].FIELD))
+				continue;
+			pw->p[j].set = isl_set_union(pw->p[j].set,
+							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--;
+			break;
+		}
+		if (j >= 0)
+			continue;
+		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);
+}
+
+int FN(PW,has_equal_space)(__isl_keep PW *pw1, __isl_keep PW *pw2)
+{
+	if (!pw1 || !pw2)
+		return -1;
+
+	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 int any_divs(__isl_keep isl_set *set)
+{
+	int i;
+
+	if (!set)
+		return -1;
+
+	for (i = 0; i < set->n; ++i)
+		if (set->p[i]->n_div > 0)
+			return 1;
+
+	return 0;
+}
+
+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_set *set;
+		EL *el;
+
+		set = isl_set_copy(pw->p[i].set);
+		el = FN(EL,copy)(pw->p[i].FIELD);
+		if (!any_divs(set)) {
+			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);
+}
+
+static int FN(PW,qsort_set_cmp)(const void *p1, const void *p2)
+{
+	isl_set *set1 = *(isl_set * const *)p1;
+	isl_set *set2 = *(isl_set * const *)p2;
+
+	return isl_set_plain_cmp(set1, set2);
+}
+
+/* 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 PW *FN(PW,normalize)(__isl_take PW *pw)
+{
+	int i, j;
+	isl_set *set;
+
+	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;
+	}
+	qsort(pw->p, pw->n, sizeof(pw->p[0]), &FN(PW,qsort_set_cmp));
+	for (i = pw->n - 1; i >= 1; --i) {
+		if (!isl_set_plain_is_equal(pw->p[i - 1].set, pw->p[i].set))
+			continue;
+		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;
+}
+
+/* Is pw1 obviously equal to pw2?
+ * That is, do they have obviously identical cells and obviously identical
+ * elements on each cell?
+ */
+isl_bool FN(PW,plain_is_equal)(__isl_keep PW *pw1, __isl_keep PW *pw2)
+{
+	int i;
+	isl_bool equal;
+
+	if (!pw1 || !pw2)
+		return isl_bool_error;
+
+	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;
+}
+
+#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_space *ma_space;
+
+	ma_space = isl_multi_aff_get_space(ma);
+	if (!pw || !ma || !ma_space)
+		goto error;
+	if (isl_space_match(pw->dim, isl_dim_param, ma_space, isl_dim_param)) {
+		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_space *pma_space;
+
+	pma_space = isl_pw_multi_aff_get_space(pma);
+	if (!pw || !pma || !pma_space)
+		goto error;
+	if (isl_space_match(pw->dim, isl_dim_param, pma_space, isl_dim_param)) {
+		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_range.c b/final/lib/External/isl/isl_range.c
new file mode 100644
index 0000000..a23a633
--- /dev/null
+++ b/final/lib/External/isl/isl_range.c
@@ -0,0 +1,539 @@
+#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 int 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 0;
+error:
+	isl_set_free(set);
+	isl_qpolynomial_free(poly);
+	return -1;
+}
+
+int 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;
+	int 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..c097079
--- /dev/null
+++ b/final/lib/External/isl/isl_range.h
@@ -0,0 +1,6 @@
+#include <isl_bound.h>
+
+int 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..71dec42
--- /dev/null
+++ b/final/lib/External/isl/isl_sample.c
@@ -0,0 +1,1295 @@
+/*
+ * 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>
+
+static struct isl_vec *empty_sample(struct 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 struct isl_vec *zero_sample(struct 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 struct isl_vec *interval_sample(struct 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 struct isl_vec *sample_eq(struct isl_basic_set *bset,
+	struct isl_vec *(*recurse)(struct 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".
+ */
+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".
+ */
+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 struct isl_vec *sample_bounded(struct 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 struct isl_vec *sample_bounded(struct 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 struct isl_basic_set *plug_in(struct isl_basic_set *bset,
+	struct 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 struct isl_vec *rational_sample(struct 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 struct isl_basic_set *shift_cone(struct isl_basic_set *cone,
+	struct 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 struct isl_vec *round_up_in_cone(struct isl_vec *vec,
+	struct isl_basic_set *cone, struct 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 struct isl_vec *vec_concat(struct isl_vec *vec1, struct 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 struct isl_vec *gbr_sample(struct 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 struct isl_vec *basic_set_sample(struct 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.
+ */
+struct isl_vec *isl_basic_set_sample_bounded(struct 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);
+	}
+	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 (isl_basic_set *) isl_map_sample((isl_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..57898b2
--- /dev/null
+++ b/final/lib/External/isl/isl_sample.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_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);
+struct isl_vec *isl_basic_set_sample_bounded(struct 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..e8cd0c0
--- /dev/null
+++ b/final/lib/External/isl/isl_scan.c
@@ -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
+ */
+
+#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 int scan_0D(struct 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 -1;
+
+	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.
+ */
+int isl_basic_set_scan(struct 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 -1;
+
+	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 0;
+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 -1;
+}
+
+int 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 0;
+error:
+	isl_set_free(set);
+	return -1;
+}
+
+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..5d31d1b
--- /dev/null
+++ b/final/lib/External/isl/isl_scan.h
@@ -0,0 +1,25 @@
+/*
+ * 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);
+};
+
+int isl_basic_set_scan(struct isl_basic_set *bset,
+	struct isl_scan_callback *callback);
+int 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..62b4583
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule.c
@@ -0,0 +1,1104 @@
+/*
+ * 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.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->leaf.ctx = ctx;
+	isl_ctx_ref(ctx);
+	schedule->ref = 1;
+	schedule->root = tree;
+	schedule->leaf.ref = -1;
+	schedule->leaf.type = isl_schedule_node_leaf;
+
+	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_ctx_deref(sched->leaf.ctx);
+	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 ? schedule->leaf.ctx : NULL;
+}
+
+/* Return a pointer to the leaf of "schedule".
+ *
+ * Even though these leaves are not reference counted, we still
+ * indicate that this function does not return a copy.
+ */
+__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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+void isl_schedule_dump(__isl_keep isl_schedule *schedule)
+{
+	isl_printer *printer;
+
+	if (!schedule)
+		return;
+
+	printer = isl_printer_to_file(isl_schedule_get_ctx(schedule), stderr);
+	printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK);
+	printer = isl_printer_print_schedule(printer, schedule);
+
+	isl_printer_free(printer);
+}
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..c25d773
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_band.c
@@ -0,0 +1,1244 @@
+/*
+ * 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",
+			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",
+			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",
+			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;
+	isl_ctx *ctx;
+
+	if (!type)
+		return options;
+	if (!options)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(options);
+	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;
+}
+
+/* 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 loop AST generation types for the isolated part become
+ * meaningless after dropping dimensions, so we remove them.
+ */
+__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];
+	free(band->isolate_loop_type);
+	band->isolate_loop_type = NULL;
+
+	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..bc58fbf
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_band.h
@@ -0,0 +1,120 @@
+#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);
+
+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_node.c b/final/lib/External/isl/isl_schedule_node.c
new file mode 100644
index 0000000..281d94d
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_node.c
@@ -0,0 +1,4405 @@
+/*
+ * 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 <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.
+ *
+ * Even though these leaves are not reference counted, we still
+ * indicate that this function does not return a copy.
+ */
+__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 pointer to the leaf of the schedule into which "node" points.
+ *
+ * Even though these leaves are not reference counted, we still
+ * return a "copy" of the leaf here such that it can still be "freed"
+ * by the user.
+ */
+__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.
+ *
+ * Since the node may point to a leaf of its schedule, which
+ * point to a field inside the schedule, we need to make sure
+ * we free the tree before freeing the schedule.
+ */
+__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 functions intersected 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;
+}
+
+/* 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.
+ * The original node is then replaced by the result of this operation.
+ *
+ * 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;
+	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", 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",
+			isl_schedule_node_free(node));
+	if (isl_schedule_tree_n_children(node->tree) == 0)
+		return 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_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.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_band_split(
+	__isl_take isl_schedule_node *node, int pos)
+{
+	isl_schedule_tree *tree;
+
+	tree = isl_schedule_node_get_tree(node);
+	tree = isl_schedule_tree_band_split(tree, pos);
+	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;
+}
+
+/* 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;
+}
+
+/* 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_ctx *ctx;
+	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);
+
+	ctx = isl_schedule_node_get_ctx(node);
+	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.
+ */
+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_tree *tree;
+		isl_union_set *filter;
+
+		tree = isl_schedule_node_get_tree(node);
+		filter = isl_union_set_list_get_union_set(filters, 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",
+			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;
+}
+
+/* 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.
+ *
+ * If the current node is an expansion, then we decrement
+ * the number of outer expansions and remove the element
+ * in data->filters that was added by gist_enter_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:
+		data->n_expansion--;
+	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;
+}
+
+/* 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 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.
+ * 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.
+ */
+__isl_give isl_schedule_node *isl_schedule_node_order_after(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *filter)
+{
+	enum isl_schedule_node_type ancestors[] =
+		{ isl_schedule_node_filter, isl_schedule_node_sequence };
+	isl_union_set *node_domain, *node_filter = NULL;
+	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;
+	if (in_seq)
+		node = isl_schedule_node_parent(node);
+	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;
+	}
+
+	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);
+	isl_schedule_node_free(node2);
+	tree1 = isl_schedule_tree_insert_filter(tree1, node_filter);
+	tree2 = isl_schedule_tree_insert_filter(tree2, filter);
+	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;
+}
+
+/* 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;
+}
+
+/* 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);
+}
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..e89bcac
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_node_private.h
@@ -0,0 +1,56 @@
+#ifndef ISL_SCHEDLUE_NODE_PRIVATE_H
+#define ISL_SCHEDLUE_NODE_PRIVATE_H
+
+#include <isl/schedule_node.h>
+#include <isl_schedule_band.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_domain_intersect_domain(
+	__isl_take isl_schedule_node *node, __isl_take isl_union_set *domain);
+
+__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..fd5c979
--- /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.
+ *
+ * A pointer to "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 point to "leaf" 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..5409a49
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_read.c
@@ -0,0 +1,820 @@
+#include <string.h>
+
+#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
+};
+
+/* Extract a mapping key from the token "tok".
+ * Return isl_schedule_key_error on error, i.e., if "tok" does not
+ * correspond to any known key.
+ */
+static enum isl_schedule_key extract_key(__isl_keep isl_stream *s,
+	struct isl_token *tok)
+{
+	int type;
+	char *name;
+	enum isl_schedule_key key;
+	isl_ctx *ctx;
+
+	ctx = isl_stream_get_ctx(s);
+	type = isl_token_get_type(tok);
+	if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) {
+		isl_stream_error(s, tok, "expecting key");
+		return isl_schedule_key_error;
+	}
+	name = isl_token_get_str(ctx, tok);
+	if (!strcmp(name, "child"))
+		key = isl_schedule_key_child;
+	else if (!strcmp(name, "coincident"))
+		key = isl_schedule_key_coincident;
+	else if (!strcmp(name, "context"))
+		key = isl_schedule_key_context;
+	else if (!strcmp(name, "contraction"))
+		key = isl_schedule_key_contraction;
+	else if (!strcmp(name, "domain"))
+		key = isl_schedule_key_domain;
+	else if (!strcmp(name, "expansion"))
+		key = isl_schedule_key_expansion;
+	else if (!strcmp(name, "extension"))
+		key = isl_schedule_key_extension;
+	else if (!strcmp(name, "filter"))
+		key = isl_schedule_key_filter;
+	else if (!strcmp(name, "guard"))
+		key = isl_schedule_key_guard;
+	else if (!strcmp(name, "leaf"))
+		key = isl_schedule_key_leaf;
+	else if (!strcmp(name, "mark"))
+		key = isl_schedule_key_mark;
+	else if (!strcmp(name, "options"))
+		key = isl_schedule_key_options;
+	else if (!strcmp(name, "schedule"))
+		key = isl_schedule_key_schedule;
+	else if (!strcmp(name, "sequence"))
+		key = isl_schedule_key_sequence;
+	else if (!strcmp(name, "set"))
+		key = isl_schedule_key_set;
+	else if (!strcmp(name, "permutable"))
+		key = isl_schedule_key_permutable;
+	else
+		isl_die(ctx, isl_error_invalid, "unknown key",
+			key = isl_schedule_key_error);
+	free(name);
+	return key;
+}
+
+/* Read a key from "s" and return the corresponding enum.
+ * Return isl_schedule_key_error on error, i.e., if the first token
+ * on the stream does not correspond to any known key.
+ */
+static enum isl_schedule_key get_key(__isl_keep isl_stream *s)
+{
+	struct isl_token *tok;
+	enum isl_schedule_key key;
+
+	tok = isl_stream_next_token(s);
+	key = extract_key(s, tok);
+	isl_token_free(tok);
+
+	return key;
+}
+
+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:
+			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_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..b6214fd
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_tree.c
@@ -0,0 +1,2753 @@
+/*
+ * 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 <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",
+			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.
+ *
+ * This function is called before a tree is modified.
+ * A static tree (with negative reference count) should never be modified,
+ * so it is not allowed to call this function on a static tree.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_cow(
+	__isl_take isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->ref < 0)
+		isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal,
+			"static trees cannot be modified",
+			return isl_schedule_tree_free(tree));
+
+	if (tree->ref == 1)
+		return tree;
+	tree->ref--;
+	return isl_schedule_tree_dup(tree);
+}
+
+/* Return a new reference to "tree".
+ *
+ * A static tree (with negative reference count) does not keep track
+ * of the number of references and should not be modified.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_copy(
+	__isl_keep isl_schedule_tree *tree)
+{
+	if (!tree)
+		return NULL;
+
+	if (tree->ref < 0)
+		return tree;
+
+	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;
+	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);
+}
+
+/* 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 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;
+}
+
+/* Split the band root node of "tree" into two nested band nodes,
+ * one with the first "pos" dimensions and
+ * one with the remaining dimensions.
+ */
+__isl_give isl_schedule_tree *isl_schedule_tree_band_split(
+	__isl_take isl_schedule_tree *tree, int pos)
+{
+	int n;
+	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;
+
+	child->band = isl_schedule_band_drop(child->band, 0, pos);
+	tree->band = isl_schedule_band_drop(tree->band, pos, n - pos);
+	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..2ae2f0f
--- /dev/null
+++ b/final/lib/External/isl/isl_schedule_tree.h
@@ -0,0 +1,265 @@
+#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.  If a tree consists of only a leaf,
+ * then it is equal to the static object isl_schedule_tree_empty.
+ *
+ * ctx may be NULL if type is isl_schedule_node_leaf.
+ * In this case, ref has a negative value.
+ *
+ * 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_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_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);
+__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..156eb41
--- /dev/null
+++ b/final/lib/External/isl/isl_scheduler.c
@@ -0,0 +1,4364 @@
+/*
+ * Copyright 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_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_node.h>
+#include <isl_mat_private.h>
+#include <isl_vec_private.h>
+#include <isl/set.h>
+#include <isl/union_set.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>
+
+/*
+ * 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".
+ */
+
+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
+};
+
+/* 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 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_space *space;
+	isl_schedule_constraints *sc;
+	isl_union_map *empty;
+	enum isl_edge_type i;
+
+	if (!domain)
+		return NULL;
+
+	ctx = isl_union_set_get_ctx(domain);
+	sc = isl_calloc_type(ctx, struct isl_schedule_constraints);
+	if (!sc)
+		goto error;
+
+	space = isl_union_set_get_space(domain);
+	sc->domain = domain;
+	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) {
+		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;
+error:
+	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 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)
+{
+	if (!sc || !validity)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_validity]);
+	sc->constraint[isl_edge_validity] = validity;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(validity);
+	return NULL;
+}
+
+/* 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)
+{
+	if (!sc || !coincidence)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_coincidence]);
+	sc->constraint[isl_edge_coincidence] = coincidence;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(coincidence);
+	return NULL;
+}
+
+/* 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)
+{
+	if (!sc || !proximity)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_proximity]);
+	sc->constraint[isl_edge_proximity] = proximity;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(proximity);
+	return NULL;
+}
+
+/* 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)
+{
+	if (!sc || !condition || !validity)
+		goto error;
+
+	isl_union_map_free(sc->constraint[isl_edge_condition]);
+	sc->constraint[isl_edge_condition] = condition;
+	isl_union_map_free(sc->constraint[isl_edge_conditional_validity]);
+	sc->constraint[isl_edge_conditional_validity] = validity;
+
+	return sc;
+error:
+	isl_schedule_constraints_free(sc);
+	isl_union_map_free(condition);
+	isl_union_map_free(validity);
+	return NULL;
+}
+
+__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 validity constraints of "sc".
+ */
+__isl_give isl_union_map *isl_schedule_constraints_get_validity(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	if (!sc)
+		return NULL;
+
+	return isl_union_map_copy(sc->constraint[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)
+{
+	if (!sc)
+		return NULL;
+
+	return isl_union_map_copy(sc->constraint[isl_edge_coincidence]);
+}
+
+/* Return the conditional validity constraints of "sc".
+ */
+__isl_give isl_union_map *isl_schedule_constraints_get_conditional_validity(
+	__isl_keep isl_schedule_constraints *sc)
+{
+	if (!sc)
+		return NULL;
+
+	return
+	    isl_union_map_copy(sc->constraint[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)
+{
+	if (!sc)
+		return NULL;
+
+	return isl_union_map_copy(sc->constraint[isl_edge_condition]);
+}
+
+void isl_schedule_constraints_dump(__isl_keep isl_schedule_constraints *sc)
+{
+	if (!sc)
+		return;
+
+	fprintf(stderr, "domain: ");
+	isl_union_set_dump(sc->domain);
+	fprintf(stderr, "context: ");
+	isl_set_dump(sc->context);
+	fprintf(stderr, "validity: ");
+	isl_union_map_dump(sc->constraint[isl_edge_validity]);
+	fprintf(stderr, "proximity: ");
+	isl_union_map_dump(sc->constraint[isl_edge_proximity]);
+	fprintf(stderr, "coincidence: ");
+	isl_union_map_dump(sc->constraint[isl_edge_coincidence]);
+	fprintf(stderr, "condition: ");
+	isl_union_map_dump(sc->constraint[isl_edge_condition]);
+	fprintf(stderr, "conditional_validity: ");
+	isl_union_map_dump(sc->constraint[isl_edge_conditional_validity]);
+}
+
+/* Align the parameters of the fields of "sc".
+ */
+static __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;
+}
+
+/* Return the total number of isl_maps in the constraints of "sc".
+ */
+static __isl_give 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;
+}
+
+/* Internal information about a node that is used during the construction
+ * of a schedule.
+ * space represents the space in which the domain lives
+ * 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 columns of cmap represent a change of basis for the schedule
+ *	coefficients; the first rank columns span the linear part of
+ *	the schedule rows
+ * cinv is the inverse of cmap.
+ * 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
+ *
+ * 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.
+ */
+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 *cmap;
+	isl_mat *cinv;
+	int	 start;
+	int	 nvar;
+	int	 nparam;
+
+	int	 scc;
+
+	int	*coincident;
+};
+
+static int node_has_space(const void *entry, const void *val)
+{
+	struct isl_sched_node *node = (struct isl_sched_node *)entry;
+	isl_space *dim = (isl_space *)val;
+
+	return isl_space_is_equal(node->space, dim);
+}
+
+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
+ * 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.
+ */
+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 validity : 1;
+	unsigned coincidence : 1;
+	unsigned proximity : 1;
+	unsigned local : 1;
+	unsigned condition : 1;
+	unsigned conditional_validity : 1;
+
+	int start;
+	int end;
+};
+
+/* 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
+ * 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
+ * it 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 if this graph is the original dependence graph,
+ *	without any splitting
+ *
+ * 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
+ *
+ * node_table contains pointers into the node array, hashed on the space
+ *
+ * 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
+ */
+struct isl_sched_graph {
+	isl_map_to_basic_set *intra_hmap;
+	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;
+
+	int 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_region *region;
+
+	isl_basic_set *lp;
+
+	int src_scc;
+	int dst_scc;
+
+	int scc;
+	int weak;
+};
+
+/* 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_hash(graph->node[i].space);
+		entry = isl_hash_table_find(ctx, graph->node_table, hash,
+					    &node_has_space,
+					    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 *dim)
+{
+	struct isl_hash_table_entry *entry;
+	uint32_t hash;
+
+	hash = isl_space_get_hash(dim);
+	entry = isl_hash_table_find(ctx, graph->node_table, hash,
+				    &node_has_space, dim, 0);
+
+	return entry ? entry->data : NULL;
+}
+
+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_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->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->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].cmap);
+			isl_mat_free(graph->node[i].cinv);
+			if (graph->root)
+				free(graph->node[i].coincident);
+		}
+	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;
+}
+
+/* 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;
+}
+
+/* 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 int compute_max_row(struct isl_sched_graph *graph,
+	__isl_keep isl_schedule_constraints *sc)
+{
+	enum isl_edge_type i;
+	int n_edge;
+
+	graph->n = 0;
+	graph->maxvar = 0;
+	if (isl_union_set_foreach_set(sc->domain, &init_n_maxvar, graph) < 0)
+		return -1;
+	n_edge = 0;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		if (isl_union_map_foreach_map(sc->constraint[i],
+						&add_n_basic_map, &n_edge) < 0)
+			return -1;
+	graph->max_row = n_edge + graph->maxvar;
+
+	return 0;
+}
+
+/* Does "bset" have any defining equalities for its set variables?
+ */
+static int has_any_defining_equality(__isl_keep isl_basic_set *bset)
+{
+	int i, n;
+
+	if (!bset)
+		return -1;
+
+	n = isl_basic_set_dim(bset, isl_dim_set);
+	for (i = 0; i < n; ++i) {
+		int has;
+
+		has = isl_basic_set_has_defining_equality(bset, isl_dim_set, i,
+							NULL);
+		if (has < 0 || has)
+			return has;
+	}
+
+	return 0;
+}
+
+/* Add a new node to the graph representing the given space.
+ * "nvar" is the (possibly compressed) number of variables and
+ * may be smaller than then number of set variables in "space"
+ * 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.
+ */
+static isl_stat add_node(struct isl_sched_graph *graph,
+	__isl_take isl_space *space, 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;
+	int *coincident;
+
+	if (!space)
+		return isl_stat_error;
+
+	ctx = isl_space_get_ctx(space);
+	nparam = isl_space_dim(space, isl_dim_param);
+	if (!ctx->opt->schedule_parametric)
+		nparam = 0;
+	sched = isl_mat_alloc(ctx, 0, 1 + nparam + nvar);
+	graph->node[graph->n].space = space;
+	graph->node[graph->n].nvar = nvar;
+	graph->node[graph->n].nparam = nparam;
+	graph->node[graph->n].sched = sched;
+	graph->node[graph->n].sched_map = NULL;
+	coincident = isl_calloc_array(ctx, int, graph->max_row);
+	graph->node[graph->n].coincident = coincident;
+	graph->node[graph->n].compressed = compressed;
+	graph->node[graph->n].hull = hull;
+	graph->node[graph->n].compress = compress;
+	graph->node[graph->n].decompress = decompress;
+	graph->n++;
+
+	if (!space || !sched || (graph->max_row && !coincident))
+		return isl_stat_error;
+	if (compressed && (!hull || !compress || !decompress))
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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.
+ */
+static isl_stat extract_node(__isl_take isl_set *set, void *user)
+{
+	int nvar;
+	int has_equality;
+	isl_space *space;
+	isl_basic_set *hull;
+	isl_set *hull_set;
+	isl_morph *morph;
+	isl_multi_aff *compress, *decompress;
+	struct isl_sched_graph *graph = user;
+
+	space = isl_set_get_space(set);
+	hull = isl_set_affine_hull(set);
+	hull = isl_basic_set_remove_divs(hull);
+	nvar = isl_space_dim(space, 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, space, nvar, 0, NULL, NULL, NULL);
+	}
+
+	morph = isl_basic_set_variable_compression(hull, isl_dim_set);
+	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, space, nvar, 1, hull_set, compress, decompress);
+error:
+	isl_basic_set_free(hull);
+	isl_space_free(space);
+	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.
+ * "type" is the type of the schedule constraint from which edge2 was
+ * extracted.
+ * 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(enum isl_edge_type type, struct isl_sched_edge *edge1,
+	struct isl_sched_edge *edge2)
+{
+	edge1->validity |= edge2->validity;
+	edge1->coincidence |= edge2->coincidence;
+	edge1->proximity |= edge2->proximity;
+	edge1->condition |= edge2->condition;
+	edge1->conditional_validity |= edge2->conditional_validity;
+	isl_map_free(edge2->map);
+
+	if (type == isl_edge_condition) {
+		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 (type == isl_edge_conditional_validity) {
+		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 (type == isl_edge_condition && !edge1->tagged_condition)
+		return -1;
+	if (type == isl_edge_conditional_validity && !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;
+}
+
+/* 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;
+	isl_space *dim;
+	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));
+		}
+	}
+
+	dim = isl_space_domain(isl_map_get_space(map));
+	src = graph_find_node(ctx, graph, dim);
+	isl_space_free(dim);
+	dim = isl_space_range(isl_map_get_space(map));
+	dst = graph_find_node(ctx, graph, dim);
+	isl_space_free(dim);
+
+	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].validity = 0;
+	graph->edge[graph->n_edge].coincidence = 0;
+	graph->edge[graph->n_edge].proximity = 0;
+	graph->edge[graph->n_edge].condition = 0;
+	graph->edge[graph->n_edge].local = 0;
+	graph->edge[graph->n_edge].conditional_validity = 0;
+	graph->edge[graph->n_edge].tagged_condition = NULL;
+	graph->edge[graph->n_edge].tagged_validity = NULL;
+	if (data->type == isl_edge_validity)
+		graph->edge[graph->n_edge].validity = 1;
+	if (data->type == isl_edge_coincidence)
+		graph->edge[graph->n_edge].coincidence = 1;
+	if (data->type == isl_edge_proximity)
+		graph->edge[graph->n_edge].proximity = 1;
+	if (data->type == isl_edge_condition) {
+		graph->edge[graph->n_edge].condition = 1;
+		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].conditional_validity = 1;
+		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(data->type, edge, &graph->edge[graph->n_edge]) < 0)
+		return -1;
+
+	return graph_edge_table_add(ctx, graph, data->type, edge);
+}
+
+/* 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 validity edges).
+ * If weak is set, we consider the graph to be undirected and
+ * we effectively compute the (weakly) connected components.
+ * Additionally, we also consider other edges when weak is set.
+ */
+static int detect_ccs(isl_ctx *ctx, struct isl_sched_graph *graph, int weak)
+{
+	int i, n;
+	struct isl_tarjan_graph *g = NULL;
+
+	g = isl_tarjan_graph_init(ctx, graph->n,
+		weak ? &node_follows_weak : &node_follows_strong, graph);
+	if (!g)
+		return -1;
+
+	graph->weak = weak;
+	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.
+ */
+static int detect_sccs(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	return detect_ccs(ctx, graph, 0);
+}
+
+/* Apply Tarjan's algorithm to detect the (weakly) connected components
+ * in the dependence graph.
+ */
+static int detect_wccs(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	return detect_ccs(ctx, graph, 1);
+}
+
+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);
+}
+
+/* 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 "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)
+{
+	isl_set *delta;
+	isl_map *key;
+	isl_basic_set *coef;
+
+	if (isl_map_to_basic_set_has(graph->intra_hmap, map))
+		return isl_map_to_basic_set_get(graph->intra_hmap, map);
+
+	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_set_remove_divs(isl_map_deltas(map));
+	coef = isl_set_coefficients(delta);
+	graph->intra_hmap = isl_map_to_basic_set_set(graph->intra_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;
+
+	if (isl_map_to_basic_set_has(graph->inter_hmap, map))
+		return isl_map_to_basic_set_get(graph->inter_hmap, map);
+
+	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;
+}
+
+/* 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_n, c_x)
+ * of valid constraints for (y - x) and then plug in (0, 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.
+ *
+ * Actually, we do not construct constraints for the c_i_x themselves,
+ * but for the coefficients of c_i_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_intra_validity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	unsigned total;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(node->cmap));
+	if (!coef)
+		goto error;
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, -1);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, 1);
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* 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_j_n^- - (c_i_n^+ - c_i_n^-),
+ *  c_j_x^+ - c_j_x^- - (c_i_x^+ - c_i_x^-)),
+ * where c_* = c_*^+ - c_*^-, with c_*^+ and c_*^- non-negative.
+ * In graph->lp, the c_*^- appear before their c_*^+ counterpart.
+ *
+ * Actually, we do not construct constraints for the c_*_x themselves,
+ * but for the coefficients of c_*_x written as a linear combination
+ * of the columns in node->cmap.
+ */
+static int add_inter_validity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge)
+{
+	unsigned total;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	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);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(src->cmap));
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set) + src->nvar,
+		    isl_mat_copy(dst->cmap));
+	if (!coef)
+		goto error;
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
+	isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
+	isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, -1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, 1);
+
+	isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
+	isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
+	isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, 1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, -1);
+
+	edge->start = graph->lp->n_ineq;
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	if (!graph->lp)
+		goto error;
+	isl_space_free(dim);
+	edge->end = graph->lp->n_ineq;
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* 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.
+ *
+ * Actually, we do not construct constraints for the c_i_x themselves,
+ * but for the coefficients of c_i_x written as a linear combination
+ * of the columns in node->cmap.
+ *
+ *
+ * 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),
+ * 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 int add_intra_proximity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, int s, int local)
+{
+	unsigned total;
+	unsigned nparam;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(node->cmap));
+	if (!coef)
+		goto error;
+
+	nparam = isl_space_dim(node->space, isl_dim_param);
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	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);
+	}
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, s);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, -s);
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* 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_j_x+s*c_i_x)
+ * with each coefficient (except m_0, c_j_0 and c_i_0)
+ * represented as a pair of non-negative coefficients.
+ *
+ * Actually, we do not construct constraints for the c_*_x themselves,
+ * but for the coefficients of c_*_x written as a linear combination
+ * of the columns in node->cmap.
+ *
+ *
+ * If "local" is set, 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_j_x+s*c_i_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 int add_inter_proximity_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, int s, int local)
+{
+	unsigned total;
+	unsigned nparam;
+	isl_map *map = isl_map_copy(edge->map);
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	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);
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set), isl_mat_copy(src->cmap));
+	coef = isl_basic_set_transform_dims(coef, isl_dim_set,
+		    isl_space_dim(dim, isl_dim_set) + src->nvar,
+		    isl_mat_copy(dst->cmap));
+	if (!coef)
+		goto error;
+
+	nparam = isl_space_dim(src->space, isl_dim_param);
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	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);
+	}
+
+	isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, -s);
+	isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, s);
+	isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, -s);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, s);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, -s);
+
+	isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, s);
+	isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, -s);
+	isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, s);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, -s);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, s);
+
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+error:
+	isl_space_free(dim);
+	return -1;
+}
+
+/* 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 local;
+
+		local = edge->local || (edge->coincidence && use_coincidence);
+		if (!edge->validity && !local)
+			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 local;
+
+		local = edge->local || (edge->coincidence && use_coincidence);
+		if (!edge->validity && !local)
+			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 local;
+
+		local = edge->local || (edge->coincidence && use_coincidence);
+		if (!edge->proximity && !local)
+			continue;
+		if (edge->src == edge->dst &&
+		    add_intra_proximity_constraints(graph, edge, 1, local) < 0)
+			return -1;
+		if (edge->src != edge->dst &&
+		    add_inter_proximity_constraints(graph, edge, 1, local) < 0)
+			return -1;
+		if (edge->validity || local)
+			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;
+}
+
+/* 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 is then transposed because we will write the
+ * coefficients of the next schedule row as a column vector s
+ * and express this s as a linear combination s = Q c of the
+ * computed basis.
+ * Similarly, the matrix U is transposed such that we can
+ * compute the coefficients c = U s from a schedule row s.
+ */
+static int node_update_cmap(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->cmap);
+	isl_mat_free(node->cinv);
+	node->cmap = isl_mat_transpose(Q);
+	node->cinv = isl_mat_transpose(U);
+	node->rank = isl_mat_initial_non_zero_cols(H);
+	isl_mat_free(H);
+
+	if (!node->cmap || !node->cinv || node->rank < 0)
+		return -1;
+	return 0;
+}
+
+/* How many times should we count the constraints in "edge"?
+ *
+ * If carry is set, then we are counting the number of
+ * (validity or conditional validity) constraints that will be added
+ * in setup_carry_lp and we count each edge exactly once.
+ *
+ * Otherwise, 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 carry,
+	int use_coincidence)
+{
+	if (carry && !edge->validity && !edge->conditional_validity)
+		return 0;
+	if (carry)
+		return 1;
+	if (edge->proximity || edge->local)
+		return 2;
+	if (use_coincidence && edge->coincidence)
+		return 2;
+	if (edge->validity)
+		return 1;
+	return 0;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added for the given map.
+ *
+ * "use_coincidence" is set if we should take into account coincidence edges.
+ */
+static int 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 carry, int use_coincidence)
+{
+	isl_basic_set *coef;
+	int f = edge_multiplicity(edge, carry, use_coincidence);
+
+	if (f == 0) {
+		isl_map_free(map);
+		return 0;
+	}
+
+	if (edge->src == edge->dst)
+		coef = intra_coefficients(graph, edge->src, map);
+	else
+		coef = inter_coefficients(graph, edge, map);
+	if (!coef)
+		return -1;
+	*n_eq += f * coef->n_eq;
+	*n_ineq += f * coef->n_ineq;
+	isl_basic_set_free(coef);
+
+	return 0;
+}
+
+/* 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,
+					    0, use_coincidence) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/* 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 (ctx->opt->schedule_max_coefficient == -1)
+		return 0;
+
+	for (i = 0; i < graph->n; ++i)
+		*n_ineq += 2 * graph->node[i].nparam + 2 * graph->node[i].nvar;
+
+	return 0;
+}
+
+/* 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'.
+ */
+static int add_bound_coefficient_constraints(isl_ctx *ctx,
+	struct isl_sched_graph *graph)
+{
+	int i, j, k;
+	int max_coefficient;
+	int total;
+
+	max_coefficient = ctx->opt->schedule_max_coefficient;
+
+	if (max_coefficient == -1)
+		return 0;
+
+	total = isl_basic_set_total_dim(graph->lp);
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		for (j = 0; j < 2 * node->nparam + 2 * node->nvar; ++j) {
+			int dim;
+			k = isl_basic_set_alloc_inequality(graph->lp);
+			if (k < 0)
+				return -1;
+			dim = 1 + node->start + 1 + 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_coefficient);
+		}
+	}
+
+	return 0;
+}
+
+/* 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 positive and negative parts 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
+ *		- c_i_0
+ *		- positive and negative parts of c_i_n (if parametric)
+ *		- positive and negative parts of c_i_x
+ *
+ * The c_i_x are not represented directly, but through the columns of
+ * node->cmap.  That is, the computed values are for variable t_i_x
+ * such that c_i_x = Q t_i_x with Q equal to node->cmap.
+ *
+ * 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 int setup_lp(isl_ctx *ctx, struct isl_sched_graph *graph,
+	int use_coincidence)
+{
+	int i, j;
+	int k;
+	unsigned nparam;
+	unsigned total;
+	isl_space *dim;
+	int parametric;
+	int param_pos;
+	int n_eq, n_ineq;
+	int max_constant_term;
+
+	max_constant_term = ctx->opt->schedule_max_constant_term;
+
+	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_cmap(node) < 0)
+			return -1;
+		node->start = total;
+		total += 1 + 2 * (node->nparam + node->nvar);
+	}
+
+	if (count_constraints(graph, &n_eq, &n_ineq, use_coincidence) < 0)
+		return -1;
+	if (count_bound_coefficient_constraints(ctx, graph, &n_eq, &n_ineq) < 0)
+		return -1;
+
+	dim = isl_space_set_alloc(ctx, 0, total);
+	isl_basic_set_free(graph->lp);
+	n_eq += 2 + parametric;
+	if (max_constant_term != -1)
+		n_ineq += graph->n;
+
+	graph->lp = isl_basic_set_alloc_space(dim, 0, n_eq, n_ineq);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][1], -1);
+	for (i = 0; i < 2 * nparam; ++i)
+		isl_int_set_si(graph->lp->eq[k][1 + param_pos + i], 1);
+
+	if (parametric) {
+		k = isl_basic_set_alloc_equality(graph->lp);
+		if (k < 0)
+			return -1;
+		isl_seq_clr(graph->lp->eq[k], 1 +  total);
+		isl_int_set_si(graph->lp->eq[k][3], -1);
+		for (i = 0; i < graph->n; ++i) {
+			int pos = 1 + graph->node[i].start + 1;
+
+			for (j = 0; j < 2 * graph->node[i].nparam; ++j)
+				isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+		}
+	}
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][4], -1);
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos = 1 + node->start + 1 + 2 * node->nparam;
+
+		for (j = 0; j < 2 * node->nvar; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	if (max_constant_term != -1)
+		for (i = 0; i < graph->n; ++i) {
+			struct isl_sched_node *node = &graph->node[i];
+			k = isl_basic_set_alloc_inequality(graph->lp);
+			if (k < 0)
+				return -1;
+			isl_seq_clr(graph->lp->ineq[k], 1 +  total);
+			isl_int_set_si(graph->lp->ineq[k][1 + node->start], -1);
+			isl_int_set_si(graph->lp->ineq[k][0], max_constant_term);
+		}
+
+	if (add_bound_coefficient_constraints(ctx, graph) < 0)
+		return -1;
+	if (add_all_validity_constraints(graph, use_coincidence) < 0)
+		return -1;
+	if (add_all_proximity_constraints(graph, use_coincidence) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* 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 (!graph->edge[i].validity)
+			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;
+}
+
+/* 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 coefficients c_i_x are represented by t_i_x
+ * variables with c_i_x = Q t_i_x and Q a unimodular matrix such that
+ * its first columns span the rows of the previously computed part
+ * of the schedule.  The non-triviality region enforces that at least
+ * one of the remaining components of t_i_x is non-zero, i.e.,
+ * that the new schedule row depends on at least one of the remaining
+ * columns of Q.
+ */
+static __isl_give isl_vec *solve_lp(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];
+		int skip = node->rank;
+		graph->region[i].pos = node->start + 1 + 2*(node->nparam+skip);
+		if (needs_row(graph, node))
+			graph->region[i].len = 2 * (node->nvar - skip);
+		else
+			graph->region[i].len = 0;
+	}
+	lp = isl_basic_set_copy(graph->lp);
+	sol = isl_tab_basic_set_non_trivial_lexmin(lp, 2, graph->n,
+				       graph->region, &check_conflict, graph);
+	return sol;
+}
+
+/* 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.  Moreover, if use_cmap is set, then the solution does
+ * not refer to the actual coefficients c_i_x, but instead to variables
+ * t_i_x such that c_i_x = Q t_i_x and Q is equal to node->cmap.
+ * In this case, we then also need to perform this multiplication
+ * to obtain the values of c_i_x.
+ *
+ * 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 use_cmap, 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 = node->start;
+		int row = isl_mat_rows(node->sched);
+
+		isl_vec_free(csol);
+		csol = isl_vec_alloc(sol->ctx, node->nvar);
+		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;
+		node->sched = isl_mat_set_element(node->sched, row, 0,
+						  sol->el[1 + pos]);
+		for (j = 0; j < node->nparam + node->nvar; ++j)
+			isl_int_sub(sol->el[1 + pos + 1 + 2 * j + 1],
+				    sol->el[1 + pos + 1 + 2 * j + 1],
+				    sol->el[1 + pos + 1 + 2 * j]);
+		for (j = 0; j < node->nparam; ++j)
+			node->sched = isl_mat_set_element(node->sched,
+					row, 1 + j, sol->el[1+pos+1+2*j+1]);
+		for (j = 0; j < node->nvar; ++j)
+			isl_int_set(csol->el[j],
+				    sol->el[1+pos+1+2*(node->nparam+j)+1]);
+		if (use_cmap)
+			csol = isl_mat_vec_product(isl_mat_copy(node->cmap),
+						   csol);
+		if (!csol)
+			goto error;
+		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;
+
+	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 (!graph->edge[i].conditional_validity)
+			continue;
+		if (graph->edge[i].validity)
+			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;
+
+		graph->edge[i].validity = 1;
+	}
+
+	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 (!graph->edge[i].condition)
+			continue;
+		if (graph->edge[i].local)
+			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->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 (edge->validity || edge->conditional_validity)
+				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].validity = edge->validity;
+		dst->edge[dst->n_edge].proximity = edge->proximity;
+		dst->edge[dst->n_edge].coincidence = edge->coincidence;
+		dst->edge[dst->n_edge].condition = edge->condition;
+		dst->edge[dst->n_edge].conditional_validity =
+						edge->conditional_validity;
+		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_cmap(node) < 0)
+			return -1;
+		nvar = node->nvar + graph->n_row - node->rank;
+		if (nvar > graph->maxvar)
+			graph->maxvar = nvar;
+	}
+
+	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.  The caller should precompute the number
+ * of nodes and edges that satisfy these predicates and pass them along
+ * as "n" and "n_edge".
+ * 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 n, int n_edge,
+	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 };
+	int t;
+
+	if (graph_alloc(ctx, &split, n, n_edge) < 0)
+		goto error;
+	if (copy_nodes(&split, graph, node_pred, data) < 0)
+		goto error;
+	if (graph_init_table(ctx, &split) < 0)
+		goto error;
+	for (t = 0; t <= isl_edge_last; ++t)
+		split.max_edge[t] = graph->max_edge[t];
+	if (graph_init_edge_tables(ctx, &split) < 0)
+		goto error;
+	if (copy_edges(ctx, &split, graph, edge_pred, data) < 0)
+		goto error;
+	split.n_row = graph->n_row;
+	split.max_row = graph->max_row;
+	split.n_total_row = graph->n_total_row;
+	split.band_start = graph->band_start;
+
+	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.
+ *
+ * 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 i, n, e1, e2;
+	isl_ctx *ctx;
+	isl_union_set_list *filters;
+
+	if (!node)
+		return NULL;
+
+	if (reset_band(graph) < 0)
+		return isl_schedule_node_free(node);
+
+	n = 0;
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int before = node->scc <= graph->src_scc;
+
+		if (before)
+			n++;
+	}
+
+	e1 = e2 = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		if (graph->edge[i].dst->scc <= graph->src_scc)
+			e1++;
+		if (graph->edge[i].src->scc > graph->src_scc)
+			e2++;
+	}
+
+	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, 0);
+	node = isl_schedule_node_child(node, 0);
+
+	node = compute_sub_schedule(node, ctx, graph, n, e1,
+				&node_scc_at_most, &edge_dst_scc_at_most,
+				graph->src_scc, 0);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_next_sibling(node);
+	node = isl_schedule_node_child(node, 0);
+	node = compute_sub_schedule(node, ctx, graph, graph->n - n, e2,
+				&node_scc_at_least, &edge_src_scc_at_least,
+				graph->src_scc + 1, 0);
+	node = isl_schedule_node_parent(node);
+	node = isl_schedule_node_parent(node);
+
+	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 constraints to graph->lp that force the dependence "map" (which
+ * is part of the dependence relation of "edge")
+ * to be respected and attempt to carry it, where the edge is one from
+ * a node j to itself.  "pos" is the sequence number of the given map.
+ * That is, add constraints that enforce
+ *
+ *	(c_j_0 + c_j_n n + c_j_x y) - (c_j_0 + c_j_n n + c_j_x x)
+ *	= c_j_x (y - x) >= e_i
+ *
+ * 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 (-e_i, 0, c_j_x),
+ * with each coefficient in c_j_x represented as a pair of non-negative
+ * coefficients.
+ */
+static int add_intra_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, __isl_take isl_map *map, int pos)
+{
+	unsigned total;
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	isl_dim_map *dim_map;
+	isl_basic_set *coef;
+	struct isl_sched_node *node = edge->src;
+
+	coef = intra_coefficients(graph, node, map);
+	if (!coef)
+		return -1;
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+	isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, -1);
+	isl_dim_map_range(dim_map, node->start + 2 * node->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  node->nvar, 1);
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+}
+
+/* Add constraints to graph->lp that force the dependence "map" (which
+ * is part of the dependence relation of "edge")
+ * to be respected and attempt to carry it, where the edge is one from
+ * node j to node k.  "pos" is the sequence number of the given map.
+ * That is, add constraints that 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 R.
+ * We obtain general constraints on coefficients (c_0, c_n, c_x)
+ * of valid constraints for R and then plug in
+ * (-e_i + c_k_0 - c_j_0, c_k_n - c_j_n, c_k_x - c_j_x)
+ * with each coefficient (except e_i, c_k_0 and c_j_0)
+ * represented as a pair of non-negative coefficients.
+ */
+static int add_inter_constraints(struct isl_sched_graph *graph,
+	struct isl_sched_edge *edge, __isl_take isl_map *map, int pos)
+{
+	unsigned total;
+	isl_ctx *ctx = isl_map_get_ctx(map);
+	isl_space *dim;
+	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);
+	if (!coef)
+		return -1;
+
+	dim = isl_space_domain(isl_space_unwrap(isl_basic_set_get_space(coef)));
+
+	total = isl_basic_set_total_dim(graph->lp);
+	dim_map = isl_dim_map_alloc(ctx, total);
+
+	isl_dim_map_range(dim_map, 3 + pos, 0, 0, 0, 1, -1);
+
+	isl_dim_map_range(dim_map, dst->start, 0, 0, 0, 1, 1);
+	isl_dim_map_range(dim_map, dst->start + 1, 2, 1, 1, dst->nparam, -1);
+	isl_dim_map_range(dim_map, dst->start + 2, 2, 1, 1, dst->nparam, 1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, -1);
+	isl_dim_map_range(dim_map, dst->start + 2 * dst->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set) + src->nvar, 1,
+			  dst->nvar, 1);
+
+	isl_dim_map_range(dim_map, src->start, 0, 0, 0, 1, -1);
+	isl_dim_map_range(dim_map, src->start + 1, 2, 1, 1, src->nparam, 1);
+	isl_dim_map_range(dim_map, src->start + 2, 2, 1, 1, src->nparam, -1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 1, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, 1);
+	isl_dim_map_range(dim_map, src->start + 2 * src->nparam + 2, 2,
+			  isl_space_dim(dim, isl_dim_set), 1,
+			  src->nvar, -1);
+
+	graph->lp = isl_basic_set_extend_constraints(graph->lp,
+			coef->n_eq, coef->n_ineq);
+	graph->lp = isl_basic_set_add_constraints_dim_map(graph->lp,
+							   coef, dim_map);
+	isl_space_free(dim);
+
+	return 0;
+}
+
+/* Add constraints to graph->lp that force all (conditional) validity
+ * dependences to be respected and attempt to carry them.
+ */
+static int add_all_constraints(struct isl_sched_graph *graph)
+{
+	int i, j;
+	int pos;
+
+	pos = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge= &graph->edge[i];
+
+		if (!edge->validity && !edge->conditional_validity)
+			continue;
+
+		for (j = 0; j < edge->map->n; ++j) {
+			isl_basic_map *bmap;
+			isl_map *map;
+
+			bmap = isl_basic_map_copy(edge->map->p[j]);
+			map = isl_map_from_basic_map(bmap);
+
+			if (edge->src == edge->dst &&
+			    add_intra_constraints(graph, edge, map, pos) < 0)
+				return -1;
+			if (edge->src != edge->dst &&
+			    add_inter_constraints(graph, edge, map, pos) < 0)
+				return -1;
+			++pos;
+		}
+	}
+
+	return 0;
+}
+
+/* Count the number of equality and inequality constraints
+ * that will be added to the carry_lp problem.
+ * We count each edge exactly once.
+ */
+static int count_all_constraints(struct isl_sched_graph *graph,
+	int *n_eq, int *n_ineq)
+{
+	int i, j;
+
+	*n_eq = *n_ineq = 0;
+	for (i = 0; i < graph->n_edge; ++i) {
+		struct isl_sched_edge *edge= &graph->edge[i];
+		for (j = 0; j < edge->map->n; ++j) {
+			isl_basic_map *bmap;
+			isl_map *map;
+
+			bmap = isl_basic_map_copy(edge->map->p[j]);
+			map = isl_map_from_basic_map(bmap);
+
+			if (count_map_constraints(graph, edge, map,
+						  n_eq, n_ineq, 1, 0) < 0)
+				    return -1;
+		}
+	}
+
+	return 0;
+}
+
+/* Construct an LP problem for finding schedule coefficients
+ * such that the schedule carries as many 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.
+ * Note that if the dependence relation is a union of basic maps,
+ * then we have to consider each basic map individually as it may only
+ * be possible to carry the dependences expressed by some of those
+ * basic maps and not all of them.
+ * Below, we consider each of those basic maps as a separate "edge".
+ *
+ * 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 positive and negative parts 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
+ *		- c_i_0
+ *		- positive and negative parts of c_i_n (if parametric)
+ *		- positive and negative parts of c_i_x
+ *
+ * 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 int setup_carry_lp(isl_ctx *ctx, struct isl_sched_graph *graph)
+{
+	int i, j;
+	int k;
+	isl_space *dim;
+	unsigned total;
+	int n_eq, n_ineq;
+	int n_edge;
+
+	n_edge = 0;
+	for (i = 0; i < graph->n_edge; ++i)
+		n_edge += graph->edge[i].map->n;
+
+	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 + 2 * (node->nparam + node->nvar);
+	}
+
+	if (count_all_constraints(graph, &n_eq, &n_ineq) < 0)
+		return -1;
+
+	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 -1;
+	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);
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][2], -1);
+	for (i = 0; i < graph->n; ++i) {
+		int pos = 1 + graph->node[i].start + 1;
+
+		for (j = 0; j < 2 * graph->node[i].nparam; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	k = isl_basic_set_alloc_equality(graph->lp);
+	if (k < 0)
+		return -1;
+	isl_seq_clr(graph->lp->eq[k], 1 +  total);
+	isl_int_set_si(graph->lp->eq[k][3], -1);
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+		int pos = 1 + node->start + 1 + 2 * node->nparam;
+
+		for (j = 0; j < 2 * node->nvar; ++j)
+			isl_int_set_si(graph->lp->eq[k][pos + j], 1);
+	}
+
+	for (i = 0; i < n_edge; ++i) {
+		k = isl_basic_set_alloc_inequality(graph->lp);
+		if (k < 0)
+			return -1;
+		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(graph) < 0)
+		return -1;
+
+	return 0;
+}
+
+static __isl_give isl_schedule_node *compute_component_schedule(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph,
+	int wcc);
+
+/* Comparison function for sorting the statements based on
+ * the corresponding value in "r".
+ */
+static int smaller_value(const void *a, const void *b, void *data)
+{
+	isl_vec *r = data;
+	const int *i1 = a;
+	const int *i2 = b;
+
+	return isl_int_cmp(r->el[*i1], r->el[*i2]);
+}
+
+/* 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 split off the remainder of the
+ * constant term modulo 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 enforced
+ * by a sequence node with the children placed in the order
+ * of this remainder.
+ * In particular, we assign an scc index based on the remainder and
+ * then rely on compute_component_schedule to insert the sequence and
+ * to continue the schedule construction on each part.
+ */
+static __isl_give isl_schedule_node *split_scaled(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	int i;
+	int row;
+	int scc;
+	isl_ctx *ctx;
+	isl_int gcd, gcd_i;
+	isl_vec *r;
+	int *order;
+
+	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);
+	}
+
+	r = isl_vec_alloc(ctx, graph->n);
+	order = isl_calloc_array(ctx, int, graph->n);
+	if (!r || !order)
+		goto error;
+
+	for (i = 0; i < graph->n; ++i) {
+		struct isl_sched_node *node = &graph->node[i];
+
+		order[i] = i;
+		isl_int_fdiv_r(r->el[i], node->sched->row[row][0], gcd);
+		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;
+	}
+
+	if (isl_sort(order, graph->n, sizeof(order[0]), &smaller_value, r) < 0)
+		goto error;
+
+	scc = 0;
+	for (i = 0; i < graph->n; ++i) {
+		if (i > 0 && isl_int_ne(r->el[order[i - 1]], r->el[order[i]]))
+			++scc;
+		graph->node[order[i]].scc = scc;
+	}
+	graph->scc = ++scc;
+	graph->weak = 0;
+
+	isl_int_clear(gcd);
+	isl_vec_free(r);
+	free(order);
+
+	if (update_edges(ctx, graph) < 0)
+		return isl_schedule_node_free(node);
+	node = insert_current_band(node, graph, 0);
+	next_band(graph);
+
+	node = isl_schedule_node_child(node, 0);
+	node = compute_component_schedule(node, graph, 0);
+	node = isl_schedule_node_parent(node);
+
+	return node;
+error:
+	isl_vec_free(r);
+	free(order);
+	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 orthogonal to
+ * 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".  "sol" has been computed
+ * in terms of the original iterators (i.e., without use of cmap).
+ * We construct the schedule row s and write it as a linear
+ * combination of (linear combinations of) previously computed schedule rows.
+ * s = Q c or c = U s.
+ * If the final entries of c are all zero, then the solution is trivial.
+ */
+static int is_trivial(struct isl_sched_node *node, __isl_keep isl_vec *sol)
+{
+	int i;
+	int pos;
+	int trivial;
+	isl_ctx *ctx;
+	isl_vec *node_sol;
+
+	if (!sol)
+		return -1;
+	if (node->nvar == node->rank)
+		return 0;
+
+	ctx = isl_vec_get_ctx(sol);
+	node_sol = isl_vec_alloc(ctx, node->nvar);
+	if (!node_sol)
+		return -1;
+
+	pos = 1 + node->start + 1 + 2 * node->nparam;
+
+	for (i = 0; i < node->nvar; ++i)
+		isl_int_sub(node_sol->el[i],
+			    sol->el[pos + 2 * i + 1], sol->el[pos + 2 * i]);
+
+	node_sol = isl_mat_vec_product(isl_mat_copy(node->cinv), node_sol);
+
+	if (!node_sol)
+		return -1;
+
+	trivial = isl_seq_first_non_zero(node_sol->el + node->rank,
+					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?
+ * "sol" has been computed in terms of the original iterators
+ * (i.e., without use of cmap).
+ * 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;
+}
+
+/* Construct a schedule row for each node such that as many dependences
+ * as possible are carried and then continue with the next band.
+ *
+ * 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_dependences(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	int i;
+	int n_edge;
+	int trivial;
+	isl_ctx *ctx;
+	isl_vec *sol;
+	isl_basic_set *lp;
+
+	if (!node)
+		return NULL;
+
+	n_edge = 0;
+	for (i = 0; i < graph->n_edge; ++i)
+		n_edge += graph->edge[i].map->n;
+
+	ctx = isl_schedule_node_get_ctx(node);
+	if (setup_carry_lp(ctx, graph) < 0)
+		return isl_schedule_node_free(node);
+
+	lp = isl_basic_set_copy(graph->lp);
+	sol = isl_tab_basic_set_non_neg_lexmin(lp);
+	if (!sol)
+		return isl_schedule_node_free(node);
+
+	if (sol->size == 0) {
+		isl_vec_free(sol);
+		isl_die(ctx, isl_error_internal,
+			"error in schedule construction",
+			return isl_schedule_node_free(node));
+	}
+
+	isl_int_divexact(sol->el[1], sol->el[1], sol->el[0]);
+	if (isl_int_cmp_si(sol->el[1], n_edge) >= 0) {
+		isl_vec_free(sol);
+		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) < 0)
+		return isl_schedule_node_free(node);
+	if (trivial)
+		graph->n_row--;
+
+	return split_scaled(node, graph);
+}
+
+/* Topologically sort statements mapped to the same schedule iteration
+ * and add insert a sequence node in front of "node"
+ * corresponding to this order.
+ *
+ * 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)
+{
+	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)
+		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 (graph->edge[i].validity ||
+		    graph->edge[i].conditional_validity)
+			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_dependences(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 (graph->edge[i].condition)
+			graph->edge[i].local = 0;
+}
+
+/* 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 (graph->edge[i].condition)
+			any_condition = 1;
+		if (graph->edge[i].conditional_validity)
+			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 (graph->edge[i].coincidence)
+			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_local_space *ls;
+	isl_aff *aff;
+	int row;
+
+	row = isl_mat_rows(node->sched) - 1;
+	ls = isl_local_space_from_space(isl_space_copy(node->space));
+	aff = extract_schedule_row(ls, node, row);
+	return isl_map_from_aff(aff);
+}
+
+/* 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 (!graph->edge[i].condition)
+			continue;
+		if (graph->edge[i].local)
+			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;
+
+		graph->edge[i].local = 1;
+
+		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 (!graph->edge[i].conditional_validity)
+			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;
+}
+
+/* Compute a schedule for a connected dependence graph and return
+ * the updated schedule node.
+ *
+ * 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.
+ * If we can't find any more rows 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)
+ * - try to carry as many 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 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.
+ *
+ * If we manage 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.
+ *
+ * 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_give isl_schedule_node *compute_schedule_wcc(
+	__isl_take isl_schedule_node *node, struct isl_sched_graph *graph)
+{
+	int has_coincidence;
+	int use_coincidence;
+	int force_coincidence = 0;
+	int check_conditional;
+	int insert;
+	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 (sort_sccs(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);
+
+	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_schedule_node_free(node);
+		sol = solve_lp(graph);
+		if (!sol)
+			return isl_schedule_node_free(node);
+		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;
+			}
+			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);
+			return carry_dependences(node, graph);
+		}
+		coincident = !has_coincidence || use_coincidence;
+		if (update_schedule(graph, sol, 1, coincident) < 0)
+			return isl_schedule_node_free(node);
+
+		if (!check_conditional)
+			continue;
+		violated = has_violated_conditional_constraint(ctx, graph);
+		if (violated < 0)
+			return isl_schedule_node_free(node);
+		if (!violated)
+			continue;
+		if (reset_band(graph) < 0)
+			return isl_schedule_node_free(node);
+		use_coincidence = has_coincidence;
+	}
+
+	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);
+	if (insert)
+		node = isl_schedule_node_parent(node);
+
+	return node;
+}
+
+/* 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, i;
+	int n, n_edge;
+	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) {
+		n = 0;
+		for (i = 0; i < graph->n; ++i)
+			if (graph->node[i].scc == component)
+				n++;
+		n_edge = 0;
+		for (i = 0; i < graph->n_edge; ++i)
+			if (graph->edge[i].src->scc == component &&
+			    graph->edge[i].dst->scc == component)
+				n_edge++;
+
+		node = isl_schedule_node_child(node, component);
+		node = isl_schedule_node_child(node, 0);
+		node = compute_sub_schedule(node, ctx, graph, n, n_edge,
+				    &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.
+ *
+ * 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.
+ * However, the returned schedule contains the original domain
+ * (before this intersection).
+ */
+__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;
+	struct isl_extract_edge_data data;
+	enum isl_edge_type i;
+	int r;
+
+	sc = isl_schedule_constraints_align_params(sc);
+	if (!sc)
+		return NULL;
+
+	graph.n = isl_union_set_n_set(sc->domain);
+	if (graph.n == 0) {
+		isl_union_set *domain = isl_union_set_copy(sc->domain);
+		sched = isl_schedule_from_domain(domain);
+		goto done;
+	}
+	if (graph_alloc(ctx, &graph, graph.n,
+	    isl_schedule_constraints_n_map(sc)) < 0)
+		goto error;
+	if (compute_max_row(&graph, sc) < 0)
+		goto error;
+	graph.root = 1;
+	graph.n = 0;
+	domain = isl_union_set_copy(sc->domain);
+	domain = isl_union_set_intersect_params(domain,
+						isl_set_copy(sc->context));
+	r = isl_union_set_foreach_set(domain, &extract_node, &graph);
+	isl_union_set_free(domain);
+	if (r < 0)
+		goto error;
+	if (graph_init_table(ctx, &graph) < 0)
+		goto error;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i)
+		graph.max_edge[i] = isl_union_map_n_map(sc->constraint[i]);
+	if (graph_init_edge_tables(ctx, &graph) < 0)
+		goto error;
+	graph.n_edge = 0;
+	data.graph = &graph;
+	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
+		data.type = i;
+		if (isl_union_map_foreach_map(sc->constraint[i],
+						&extract_edge, &data) < 0)
+			goto error;
+	}
+
+	node = isl_schedule_node_from_domain(isl_union_set_copy(sc->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);
+
+done:
+	graph_free(ctx, &graph);
+	isl_schedule_constraints_free(sc);
+
+	return sched;
+error:
+	graph_free(ctx, &graph);
+	isl_schedule_constraints_free(sc);
+	return NULL;
+}
+
+/* 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..2159464
--- /dev/null
+++ b/final/lib/External/isl/isl_seq.c
@@ -0,0 +1,329 @@
+/*
+ * 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_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;
+}
+
+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..05825f2
--- /dev/null
+++ b/final/lib/External/isl/isl_seq.h
@@ -0,0 +1,60 @@
+/*
+ * 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);
+
+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..8bc1d87
--- /dev/null
+++ b/final/lib/External/isl/isl_space.c
@@ -0,0 +1,2419 @@
+/*
+ * 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;
+}
+
+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)
+		if (space->ids[offset + i]->name &&
+		    !strcmp(space->ids[offset + i]->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?
+ */
+static int isl_space_has_equal_tuples(__isl_keep isl_space *space1,
+	__isl_keep isl_space *space2)
+{
+	if (!space1 || !space2)
+		return -1;
+	if (space1 == space2)
+		return 1;
+	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 int match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
+	__isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
+{
+	int i;
+
+	if (dim1 == dim2 && dim1_type == dim2_type)
+		return 1;
+
+	if (!isl_space_tuple_is_equal(dim1, dim1_type, dim2, dim2_type))
+		return 0;
+
+	if (!dim1->ids && !dim2->ids)
+		return 1;
+
+	for (i = 0; i < n(dim1, dim1_type); ++i) {
+		if (get_id(dim1, dim1_type, i) != get_id(dim2, dim2_type, i))
+			return 0;
+	}
+	return 1;
+}
+
+int isl_space_match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
+	__isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
+{
+	if (!dim1 || !dim2)
+		return -1;
+
+	return match(dim1, dim1_type, dim2, dim2_type);
+}
+
+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);
+}
+
+__isl_give isl_space *isl_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_add_dims(__isl_take isl_space *dim,
+	enum isl_dim_type type, unsigned n)
+{
+	dim = isl_space_reset(dim, type);
+	if (!dim)
+		return NULL;
+	switch (type) {
+	case isl_dim_param:
+		dim = isl_space_extend(dim,
+					dim->nparam + n, dim->n_in, dim->n_out);
+		if (dim && dim->nested[0] &&
+		    !(dim->nested[0] = isl_space_add_dims(dim->nested[0],
+						    isl_dim_param, n)))
+			goto error;
+		if (dim && dim->nested[1] &&
+		    !(dim->nested[1] = isl_space_add_dims(dim->nested[1],
+						    isl_dim_param, n)))
+			goto error;
+		return dim;
+	case isl_dim_in:
+		return isl_space_extend(dim,
+					dim->nparam, dim->n_in + n, dim->n_out);
+	case isl_dim_out:
+		return isl_space_extend(dim,
+					dim->nparam, dim->n_in, dim->n_out + n);
+	default:
+		isl_die(dim->ctx, isl_error_invalid,
+			"cannot add dimensions of specified type", goto error);
+	}
+error:
+	isl_space_free(dim);
+	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 *dim,
+	enum isl_dim_type dst_type, unsigned dst_pos,
+	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
+{
+	int i;
+
+	if (!dim)
+		return NULL;
+	if (n == 0) {
+		dim = isl_space_reset(dim, src_type);
+		return isl_space_reset(dim, dst_type);
+	}
+
+	isl_assert(dim->ctx, src_pos + n <= isl_space_dim(dim, src_type),
+		goto error);
+
+	if (dst_type == src_type && dst_pos == src_pos)
+		return dim;
+
+	isl_assert(dim->ctx, dst_type != src_type, goto error);
+
+	dim = isl_space_reset(dim, src_type);
+	dim = isl_space_reset(dim, dst_type);
+
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	if (dim->ids) {
+		isl_id **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);
+		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 == dst_type) {
+				get_ids(dim, t, 0, dst_pos, ids + off);
+				off += dst_pos;
+				get_ids(dim, src_type, src_pos, n, ids + off);
+				off += n;
+				get_ids(dim, t, dst_pos, s[t - o] - dst_pos,
+						ids + off);
+				off += s[t - o] - dst_pos;
+			} else if (t == src_type) {
+				get_ids(dim, t, 0, src_pos, ids + off);
+				off += src_pos;
+				get_ids(dim, t, src_pos + n,
+					    s[t - o] - src_pos - n, ids + off);
+				off += s[t - o] - src_pos - n;
+			} else {
+				get_ids(dim, t, 0, s[t - o], ids + off);
+				off += s[t - o];
+			}
+		}
+		free(dim->ids);
+		dim->ids = ids;
+		dim->n_id = dim->nparam + dim->n_in + dim->n_out;
+	}
+
+	switch (dst_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:		;
+	}
+
+	switch (src_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:		;
+	}
+
+	if (dst_type != isl_dim_param && src_type != isl_dim_param)
+		return dim;
+
+	for (i = 0; i < 2; ++i) {
+		if (!dim->nested[i])
+			continue;
+		dim->nested[i] = isl_space_replace(dim->nested[i],
+						 isl_dim_param, dim);
+		if (!dim->nested[i])
+			goto error;
+	}
+
+	return dim;
+error:
+	isl_space_free(dim);
+	return NULL;
+}
+
+__isl_give isl_space *isl_space_join(__isl_take isl_space *left,
+	__isl_take isl_space *right)
+{
+	isl_space *dim;
+
+	if (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
+			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);
+
+	isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
+			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 (!left || !right)
+		goto error;
+
+	if (!match(left, isl_dim_param, right, isl_dim_param))
+		isl_die(left->ctx, isl_error_invalid,
+			"parameters need to match", 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 (!left || !right)
+		goto error;
+
+	isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
+			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 *dim)
+{
+	isl_ctx *ctx;
+	isl_id **ids = NULL;
+
+	if (!dim)
+		return NULL;
+	ctx = isl_space_get_ctx(dim);
+	if (!isl_space_is_set(dim))
+		isl_die(ctx, isl_error_invalid, "not a set space", goto error);
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+	if (dim->ids) {
+		ids = isl_calloc_array(dim->ctx, isl_id *,
+					dim->nparam + dim->n_out + dim->n_out);
+		if (!ids)
+			goto error;
+		get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
+		get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->nparam);
+	}
+	dim->n_in = dim->n_out;
+	if (ids) {
+		free(dim->ids);
+		dim->ids = ids;
+		dim->n_id = dim->nparam + dim->n_out + dim->n_out;
+		dim = copy_ids(dim, isl_dim_out, 0, dim, isl_dim_in);
+	}
+	isl_id_free(dim->tuple_id[0]);
+	dim->tuple_id[0] = isl_id_copy(dim->tuple_id[1]);
+	isl_space_free(dim->nested[0]);
+	dim->nested[0] = isl_space_copy(dim->nested[1]);
+	return dim;
+error:
+	isl_space_free(dim);
+	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 *dim)
+{
+	if (!dim)
+		return NULL;
+	dim = isl_space_drop_outputs(dim, 0, dim->n_out);
+	dim = isl_space_reverse(dim);
+	dim = mark_as_set(dim);
+	return dim;
+}
+
+__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 *dim)
+{
+	if (!dim)
+		return NULL;
+	dim = isl_space_drop_inputs(dim, 0, dim->n_in);
+	dim = mark_as_set(dim);
+	return dim;
+}
+
+__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_as_set_space(__isl_take isl_space *dim)
+{
+	dim = isl_space_cow(dim);
+	if (!dim)
+		return NULL;
+
+	dim->n_out += dim->n_in;
+	dim->n_in = 0;
+	dim = isl_space_reset(dim, isl_dim_in);
+	dim = isl_space_reset(dim, isl_dim_out);
+
+	return dim;
+}
+
+__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 *dim1,
+	__isl_keep isl_space *dim2)
+{
+	if (!dim1 || !dim2)
+		return isl_bool_error;
+	if (dim1 == dim2)
+		return isl_bool_true;
+	return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
+	       isl_space_tuple_is_equal(dim1, isl_dim_in, dim2, isl_dim_in) &&
+	       isl_space_tuple_is_equal(dim1, isl_dim_out, dim2, isl_dim_out);
+}
+
+/* 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)
+{
+	if (!space1 || !space2)
+		return isl_bool_error;
+	if (!isl_space_is_set(space1))
+		return isl_bool_false;
+	return match(space1, isl_dim_param, space2, isl_dim_param) &&
+	       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)
+{
+	if (!space1 || !space2)
+		return isl_bool_error;
+	if (!isl_space_is_set(space1))
+		return isl_bool_false;
+	return match(space1, isl_dim_param, space2, isl_dim_param) &&
+	       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);
+}
+
+int isl_space_compatible(__isl_keep isl_space *dim1,
+	__isl_keep isl_space *dim2)
+{
+	return dim1->nparam == dim2->nparam &&
+	       dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
+}
+
+static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_space *dim)
+{
+	int i;
+	isl_id *id;
+
+	if (!dim)
+		return hash;
+
+	isl_hash_byte(hash, dim->nparam % 256);
+	isl_hash_byte(hash, dim->n_in % 256);
+	isl_hash_byte(hash, dim->n_out % 256);
+
+	for (i = 0; i < dim->nparam; ++i) {
+		id = get_id(dim, isl_dim_param, i);
+		hash = isl_hash_id(hash, id);
+	}
+
+	id = tuple_id(dim, isl_dim_in);
+	hash = isl_hash_id(hash, id);
+	id = tuple_id(dim, isl_dim_out);
+	hash = isl_hash_id(hash, id);
+
+	hash = isl_hash_dim(hash, dim->nested[0]);
+	hash = isl_hash_dim(hash, dim->nested[1]);
+
+	return hash;
+}
+
+uint32_t isl_space_get_hash(__isl_keep isl_space *dim)
+{
+	uint32_t hash;
+
+	if (!dim)
+		return 0;
+
+	hash = isl_hash_init();
+	hash = isl_hash_dim(hash, dim);
+
+	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;
+}
+
+__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;
+}
+
+int isl_space_is_named_or_nested(__isl_keep isl_space *dim, enum isl_dim_type type)
+{
+	if (type != isl_dim_in && type != isl_dim_out)
+		return 0;
+	if (!dim)
+		return -1;
+	if (dim->tuple_id[type - isl_dim_in])
+		return 1;
+	if (dim->nested[type - isl_dim_in])
+		return 1;
+	return 0;
+}
+
+int isl_space_may_be_set(__isl_keep isl_space *dim)
+{
+	if (!dim)
+		return -1;
+	if (isl_space_is_set(dim))
+		return 1;
+	if (isl_space_dim(dim, isl_dim_in) != 0)
+		return 0;
+	if (isl_space_is_named_or_nested(dim, isl_dim_in))
+		return 0;
+	return 1;
+}
+
+__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 *dim)
+{
+	if (!dim)
+		return isl_bool_error;
+
+	return dim->nested[0] && dim->nested[1];
+}
+
+__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 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));
+}
+
+int isl_space_has_named_params(__isl_keep isl_space *dim)
+{
+	int i;
+	unsigned off;
+
+	if (!dim)
+		return -1;
+	if (dim->nparam == 0)
+		return 1;
+	off = isl_space_offset(dim, isl_dim_param);
+	if (off + dim->nparam > dim->n_id)
+		return 0;
+	for (i = 0; i < dim->nparam; ++i)
+		if (!dim->ids[off + i])
+			return 0;
+	return 1;
+}
+
+/* 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..a07acea
--- /dev/null
+++ b/final/lib/External/isl/isl_space_private.h
@@ -0,0 +1,60 @@
+#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_hash(__isl_keep isl_space *dim);
+
+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);
+
+__isl_give isl_space *isl_space_as_set_space(__isl_take isl_space *dim);
+
+unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type);
+
+int isl_space_may_be_set(__isl_keep isl_space *dim);
+int isl_space_is_named_or_nested(__isl_keep isl_space *dim, enum isl_dim_type type);
+int isl_space_has_named_params(__isl_keep isl_space *dim);
+__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_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..3d9bd92
--- /dev/null
+++ b/final/lib/External/isl/isl_tab.c
@@ -0,0 +1,3668 @@
+/*
+ * Copyright 2008-2009 Katholieke Universiteit Leuven
+ * Copyright 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 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>
+
+/*
+ * 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;
+}
+
+int isl_tab_mark_empty(struct isl_tab *tab)
+{
+	if (!tab)
+		return -1;
+	if (!tab->empty && tab->need_undo)
+		if (isl_tab_push(tab, isl_tab_undo_empty) < 0)
+			return -1;
+	tab->empty = 1;
+	return 0;
+}
+
+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.
+ */
+static int close_row(struct isl_tab *tab, struct isl_tab_var *var) WARN_UNUSED;
+static int close_row(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	int j;
+	struct isl_mat *mat = tab->mat;
+	unsigned off = 2 + tab->M;
+
+	isl_assert(tab->mat->ctx, var->is_nonneg, return -1);
+	var->is_zero = 1;
+	if (tab->need_undo)
+		if (isl_tab_push_var(tab, isl_tab_undo_zero, var) < 0)
+			return -1;
+	for (j = tab->n_dead; j < tab->n_col; ++j) {
+		int recheck;
+		if (isl_int_is_zero(mat->row[var->index][off + j]))
+			continue;
+		isl_assert(tab->mat->ctx,
+		    isl_int_is_neg(mat->row[var->index][off + j]), return -1);
+		recheck = isl_tab_kill_col(tab, j);
+		if (recheck < 0)
+			return -1;
+		if (recheck)
+			--j;
+	}
+	if (isl_tab_mark_redundant(tab, var->index) < 0)
+		return -1;
+	if (tab_is_manifestly_empty(tab) && isl_tab_mark_empty(tab) < 0)
+		return -1;
+	return 0;
+}
+
+/* Add a constraint to the tableau and allocate a row for it.
+ * Return the index into the constraint array "con".
+ */
+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.
+ *
+ * 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 int drop_row(struct isl_tab *tab, int row)
+{
+	isl_assert(tab->mat->ctx, ~tab->row_var[row] == tab->n_con - 1, return -1);
+	if (row != tab->n_row - 1)
+		swap_rows(tab, row, tab->n_row - 1);
+	tab->n_row--;
+	tab->n_con--;
+	return 0;
+}
+
+/* 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 int 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 -1;
+	return 0;
+}
+
+/* Add inequality "ineq" and check if it conflicts with the
+ * previously added constraints or if it is obviously redundant.
+ */
+int isl_tab_add_ineq(struct isl_tab *tab, isl_int *ineq)
+{
+	int r;
+	int sgn;
+	isl_int cst;
+
+	if (!tab)
+		return -1;
+	if (tab->bmap) {
+		struct isl_basic_map *bmap = tab->bmap;
+
+		isl_assert(tab->mat->ctx, tab->n_eq == bmap->n_eq, return -1);
+		isl_assert(tab->mat->ctx,
+			    tab->n_con == bmap->n_eq + bmap->n_ineq, return -1);
+		tab->bmap = isl_basic_map_add_ineq(tab->bmap, ineq);
+		if (isl_tab_push(tab, isl_tab_undo_bmap_ineq) < 0)
+			return -1;
+		if (!tab->bmap)
+			return -1;
+	}
+	if (tab->cone) {
+		isl_int_init(cst);
+		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 -1;
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		return -1;
+	if (isl_tab_row_is_redundant(tab, tab->con[r].index)) {
+		if (isl_tab_mark_redundant(tab, tab->con[r].index) < 0)
+			return -1;
+		return 0;
+	}
+
+	sgn = restore_row(tab, &tab->con[r]);
+	if (sgn < -1)
+		return -1;
+	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 -1;
+	return 0;
+}
+
+/* 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.
+ */
+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;
+}
+
+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 (tab->M && !isl_int_is_zero(tab->mat->row[row][2]))
+		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.
+ */
+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;
+}
+
+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.
+ */
+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_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.
+ */
+static int add_div_constraints(struct isl_tab *tab, unsigned div,
+	int (*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;
+}
+
+/* Add an extra div, prescribed by "div" to the tableau and
+ * the associated bmap (which is assumed to be non-NULL).
+ *
+ * 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_add_div(struct isl_tab *tab, __isl_keep isl_vec *div,
+	int (*add_ineq)(void *user, isl_int *), void *user)
+{
+	int r;
+	int k;
+	int nonneg;
+
+	if (!tab || !div)
+		return -1;
+
+	isl_assert(tab->mat->ctx, tab->bmap, 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_allocate_var(tab);
+	if (r < 0)
+		return -1;
+
+	if (nonneg)
+		tab->var[r].is_nonneg = 1;
+
+	tab->bmap = isl_basic_map_extend_space(tab->bmap,
+		isl_basic_map_get_space(tab->bmap), 1, 0, 2);
+	k = isl_basic_map_alloc_div(tab->bmap);
+	if (k < 0)
+		return -1;
+	isl_seq_cpy(tab->bmap->div[k], div->el, div->size);
+	if (isl_tab_push(tab, isl_tab_undo_bmap_div) < 0)
+		return -1;
+
+	if (add_div_constraints(tab, k, add_ineq, user) < 0)
+		return -1;
+
+	return r;
+}
+
+/* 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);
+	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.
+ */
+int isl_tab_cone_is_bounded(struct isl_tab *tab)
+{
+	int i;
+
+	if (!tab)
+		return -1;
+	if (tab->empty)
+		return 1;
+	if (tab->n_dead == tab->n_col)
+		return 1;
+
+	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 -1;
+			if (sgn != 0)
+				return 0;
+			if (close_row(tab, var) < 0)
+				return -1;
+			break;
+		}
+		if (tab->n_dead == tab->n_col)
+			return 1;
+		if (i == tab->n_row)
+			return 0;
+	}
+}
+
+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;
+}
+
+/* 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)
+		isl_basic_map_gauss(bmap, NULL);
+	if (!tab->rational &&
+	    !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 (struct isl_basic_set *)isl_basic_map_update_from_tab(
+		(struct isl_basic_map *)bset, tab);
+}
+
+/* Given a non-negative variable "var", add a new non-negative variable
+ * that is the opposite of "var", ensuring that var can only attain the
+ * value zero.
+ * 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 int 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 0;
+	isl_assert(tab->mat->ctx, !var->is_redundant, return -1);
+	isl_assert(tab->mat->ctx, var->is_nonneg, return -1);
+
+	if (isl_tab_extend_cons(tab, 1) < 0)
+		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;
+	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++;
+	if (isl_tab_push_var(tab, isl_tab_undo_allocate, &tab->con[r]) < 0)
+		return -1;
+
+	sgn = sign_of_max(tab, &tab->con[r]);
+	if (sgn < -1)
+		return -1;
+	if (sgn < 0) {
+		if (isl_tab_mark_empty(tab) < 0)
+			return -1;
+		return 0;
+	}
+	tab->con[r].is_nonneg = 1;
+	if (isl_tab_push_var(tab, isl_tab_undo_nonneg, &tab->con[r]) < 0)
+		return -1;
+	/* sgn == 0 */
+	if (close_row(tab, &tab->con[r]) < 0)
+		return -1;
+
+	return 0;
+}
+
+/* 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]);
+}
+
+/* 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.
+ */
+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;
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			var = isl_tab_var_from_row(tab, i);
+			if (var->marked)
+				break;
+		}
+		if (i == tab->n_row) {
+			for (i = tab->n_dead; i < tab->n_col; ++i) {
+				var = var_from_col(tab, i);
+				if (var->marked)
+					break;
+			}
+			if (i == tab->n_col)
+				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)
+				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;
+		for (i = tab->n_redundant; i < tab->n_row; ++i) {
+			var = isl_tab_var_from_row(tab, i);
+			if (var->marked)
+				break;
+		}
+		if (i == tab->n_row) {
+			for (i = tab->n_dead; i < tab->n_col; ++i) {
+				var = var_from_col(tab, i);
+				if (var->marked)
+					break;
+			}
+			if (i == tab->n_col)
+				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]) &&
+		(!tab->M || isl_int_is_zero(tab->mat->row[row][2])) &&
+		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).
+ */
+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
+			isl_int_cdiv_q(*opt, tab->mat->row[var->index][1],
+					     tab->mat->row[var->index][0]);
+	}
+	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;
+}
+
+/* Take a snapshot of the tableau that can be restored by s 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;
+}
+
+/* Undo the operation performed by isl_tab_relax.
+ */
+static int unrelax(struct isl_tab *tab, struct isl_tab_var *var) WARN_UNUSED;
+static int 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 -1;
+
+	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 -1);
+		}
+	} 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 0;
+}
+
+/* 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 int ununrestrict(struct isl_tab *tab, struct isl_tab_var *var)
+{
+	var->is_nonneg = 1;
+
+	if (var->is_row && restore_row(tab, var) < -1)
+		return -1;
+
+	return 0;
+}
+
+static int perform_undo_var(struct isl_tab *tab, struct isl_tab_undo *undo) WARN_UNUSED;
+static int 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:
+		var->is_redundant = 0;
+		tab->n_redundant--;
+		restore_row(tab, isl_tab_var_from_row(tab, tab->n_redundant));
+		break;
+	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 -1);
+			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 -1;
+			} else if (!min_is_manifestly_unbounded(tab, var)) {
+				if (to_row(tab, var, -1) < 0)
+					return -1;
+			} else
+				if (to_row(tab, var, 0) < 0)
+					return -1;
+		}
+		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 -1);
+	}
+
+	return 0;
+}
+
+/* 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 int perform_undo(struct isl_tab *tab, struct isl_tab_undo *undo) WARN_UNUSED;
+static int 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:
+		if (isl_basic_map_free_div(tab->bmap, 1) < 0)
+			return -1;
+		if (tab->samples)
+			tab->samples->n_col--;
+		break;
+	case isl_tab_undo_saved_basis:
+		if (restore_basis(tab, undo->u.col_var) < 0)
+			return -1;
+		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 -1);
+	}
+	return 0;
+}
+
+/* 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;
+}
+
+int 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 0;
+	}
+
+	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 0;
+error:
+	isl_basic_map_free(bmap);
+	return -1;
+}
+
+int isl_tab_track_bset(struct isl_tab *tab, __isl_take isl_basic_set *bset)
+{
+	return isl_tab_track_bmap(tab, (isl_basic_map *)bset);
+}
+
+__isl_keep isl_basic_set *isl_tab_peek_bset(struct isl_tab *tab)
+{
+	if (!tab)
+		return NULL;
+
+	return (isl_basic_set *)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..0b1ee4a
--- /dev/null
+++ b/final/lib/External/isl/isl_tab.h
@@ -0,0 +1,309 @@
+/*
+ * 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 {
+	int (*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 and 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);
+int 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;
+#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;
+
+int 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;
+
+int isl_tab_track_bmap(struct isl_tab *tab, __isl_take isl_basic_map *bmap) WARN_UNUSED;
+int 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;
+
+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);
+
+struct isl_map *isl_tab_basic_map_partial_lexopt(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty, int max);
+__isl_give isl_pw_multi_aff *isl_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);
+
+/* An isl_region represents a sequence of consecutive variables.
+ * pos is the location (starting at 0) of the first variable in the sequence.
+ */
+struct isl_region {
+	int pos;
+	int len;
+};
+
+__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_region *region,
+	int (*conflict)(int con, void *user), void *user);
+__isl_give isl_vec *isl_tab_basic_set_non_neg_lexmin(
+	__isl_take isl_basic_set *bset);
+
+/* 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;
+int 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;
+
+int isl_tab_push_callback(struct isl_tab *tab,
+	struct isl_tab_callback *callback) WARN_UNUSED;
+
+int isl_tab_add_div(struct isl_tab *tab, __isl_keep isl_vec *div,
+	int (*add_ineq)(void *user, isl_int *), void *user);
+
+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_pip.c b/final/lib/External/isl/isl_tab_pip.c
new file mode 100644
index 0000000..84e85ff
--- /dev/null
+++ b/final/lib/External/isl/isl_tab_pip.c
@@ -0,0 +1,5669 @@
+/*
+ * 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_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_options_private.h>
+#include <isl_config.h>
+
+/*
+ * 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);
+	/* add div "div" to context and return non-negativity */
+	int (*add_div)(struct isl_context *context, struct 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 */
+	void (*free)(struct isl_context *context);
+};
+
+struct isl_context {
+	struct isl_context_op *op;
+};
+
+struct isl_context_lex {
+	struct isl_context context;
+	struct isl_tab *tab;
+};
+
+/* A stack (linked list) of solutions of subtrees of the search space.
+ *
+ * "M" describes the solution in terms of the dimensions of "dom".
+ * The number of columns of "M" is one more than the total number
+ * of dimensions of "dom".
+ *
+ * If "M" is NULL, then there is no solution on "dom".
+ */
+struct isl_partial_sol {
+	int level;
+	struct isl_basic_set *dom;
+	struct isl_mat *M;
+
+	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 (including cases where the tableau
+ * is empty), the function "add" is called on the isl_sol passed
+ * to find_solutions_main.
+ *
+ * The context tableau is owned by isl_sol and is updated incrementally.
+ *
+ * There are currently two 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, 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;
+	struct isl_context *context;
+	struct isl_partial_sol *partial;
+	void (*add)(struct isl_sol *sol,
+			    struct isl_basic_set *dom, struct isl_mat *M);
+	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_mat_free(partial->M);
+		free(partial);
+	}
+	sol->free(sol);
+}
+
+/* Push a partial solution represented by a domain and mapping M
+ * onto the stack of partial solutions.
+ */
+static void sol_push_sol(struct isl_sol *sol,
+	struct isl_basic_set *dom, struct isl_mat *M)
+{
+	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->M = M;
+	partial->next = sol->partial;
+
+	sol->partial = partial;
+
+	return;
+error:
+	isl_basic_set_free(dom);
+	isl_mat_free(M);
+	sol->error = 1;
+}
+
+/* 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->M)
+		sol->add(sol, partial->dom, partial->M);
+	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 mapping, where n_div
+ * is the number of divs that the two partial solutions have in common.
+ */
+static int same_solution(struct isl_partial_sol *s1, struct isl_partial_sol *s2,
+	unsigned n_div)
+{
+	int i;
+	unsigned dim;
+
+	if (!s1->M != !s2->M)
+		return 0;
+	if (!s1->M)
+		return 1;
+
+	dim = isl_basic_set_total_dim(s1->dom) - s1->dom->n_div;
+
+	for (i = 0; i < s1->M->n_row; ++i) {
+		if (isl_seq_first_non_zero(s1->M->row[i]+1+dim+n_div,
+					    s1->M->n_col-1-dim-n_div) != -1)
+			return 0;
+		if (isl_seq_first_non_zero(s2->M->row[i]+1+dim+n_div,
+					    s2->M->n_col-1-dim-n_div) != -1)
+			return 0;
+		if (!isl_seq_eq(s1->M->row[i], s2->M->row[i], 1+dim+n_div))
+			return 0;
+	}
+	return 1;
+}
+
+/* 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.
+ */
+static void sol_pop(struct isl_sol *sol)
+{
+	struct isl_partial_sol *partial;
+	unsigned n_div;
+
+	if (sol->error)
+		return;
+
+	if (sol->level == 0) {
+		for (partial = sol->partial; partial; partial = sol->partial)
+			sol_pop_one(sol);
+		return;
+	}
+
+	partial = sol->partial;
+	if (!partial)
+		return;
+
+	if (partial->level <= sol->level)
+		return;
+
+	if (partial->next && partial->next->level == partial->level) {
+		n_div = isl_basic_set_dim(
+				sol->context->op->peek_basic_set(sol->context),
+				isl_dim_div);
+
+		if (!same_solution(partial, partial->next, n_div)) {
+			sol_pop_one(sol);
+			sol_pop_one(sol);
+		} else {
+			struct isl_basic_set *bset;
+			isl_mat *M;
+			unsigned n;
+
+			n = isl_basic_set_dim(partial->next->dom, isl_dim_div);
+			n -= n_div;
+			bset = sol_domain(sol);
+			isl_basic_set_free(partial->next->dom);
+			partial->next->dom = bset;
+			M = partial->next->M;
+			if (M) {
+				M = isl_mat_drop_cols(M, M->n_col - n, n);
+				partial->next->M = M;
+				if (!M)
+					goto error;
+			}
+			partial->next->level = sol->level;
+
+			if (!bset)
+				goto error;
+
+			sol->partial = partial->next;
+			isl_basic_set_free(partial->dom);
+			isl_mat_free(partial->M);
+			free(partial);
+		}
+	} else
+		sol_pop_one(sol);
+
+	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 int 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 ? -1 : 0;
+}
+
+/* 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(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_map *sol_map)
+{
+	if (!sol_map)
+		return;
+	if (sol_map->sol.context)
+		sol_map->sol.context->op->free(sol_map->sol.context);
+	isl_map_free(sol_map->map);
+	isl_set_free(sol_map->empty);
+	free(sol_map);
+}
+
+static void sol_map_free_wrap(struct isl_sol *sol)
+{
+	sol_map_free((struct isl_sol_map *)sol);
+}
+
+/* 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 map "dom" that represents the context and an affine
+ * matrix "M" that maps the dimensions of the context to the
+ * output variables, construct a basic map with the same parameters
+ * and divs as the context, the dimensions of the context as input
+ * dimensions and a number of output dimensions that is equal to
+ * the number of output dimensions in the input map.
+ *
+ * The constraints and divs of the context are simply copied
+ * from "dom".  For each row
+ *	x = c + e(y)
+ * an equality
+ *	c + e(y) - d x = 0
+ * is added, with d the common denominator of M.
+ */
+static void sol_map_add(struct isl_sol_map *sol,
+	struct isl_basic_set *dom, struct isl_mat *M)
+{
+	int i;
+	struct isl_basic_map *bmap = NULL;
+	unsigned n_eq;
+	unsigned n_ineq;
+	unsigned nparam;
+	unsigned total;
+	unsigned n_div;
+	unsigned n_out;
+
+	if (sol->sol.error || !dom || !M)
+		goto error;
+
+	n_out = sol->sol.n_out;
+	n_eq = dom->n_eq + n_out;
+	n_ineq = dom->n_ineq;
+	n_div = dom->n_div;
+	nparam = isl_basic_set_total_dim(dom) - n_div;
+	total = isl_map_dim(sol->map, isl_dim_all);
+	bmap = isl_basic_map_alloc_space(isl_map_get_space(sol->map),
+					n_div, n_eq, 2 * n_div + n_ineq);
+	if (!bmap)
+		goto error;
+	if (sol->sol.rational)
+		ISL_F_SET(bmap, ISL_BASIC_MAP_RATIONAL);
+	for (i = 0; i < dom->n_div; ++i) {
+		int k = isl_basic_map_alloc_div(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->div[k], dom->div[i], 1 + 1 + nparam);
+		isl_seq_clr(bmap->div[k] + 1 + 1 + nparam, total - nparam);
+		isl_seq_cpy(bmap->div[k] + 1 + 1 + total,
+			    dom->div[i] + 1 + 1 + nparam, i);
+	}
+	for (i = 0; i < dom->n_eq; ++i) {
+		int k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->eq[k], dom->eq[i], 1 + nparam);
+		isl_seq_clr(bmap->eq[k] + 1 + nparam, total - nparam);
+		isl_seq_cpy(bmap->eq[k] + 1 + total,
+			    dom->eq[i] + 1 + nparam, n_div);
+	}
+	for (i = 0; i < dom->n_ineq; ++i) {
+		int k = isl_basic_map_alloc_inequality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->ineq[k], dom->ineq[i], 1 + nparam);
+		isl_seq_clr(bmap->ineq[k] + 1 + nparam, total - nparam);
+		isl_seq_cpy(bmap->ineq[k] + 1 + total,
+			dom->ineq[i] + 1 + nparam, n_div);
+	}
+	for (i = 0; i < M->n_row - 1; ++i) {
+		int k = isl_basic_map_alloc_equality(bmap);
+		if (k < 0)
+			goto error;
+		isl_seq_cpy(bmap->eq[k], M->row[1 + i], 1 + nparam);
+		isl_seq_clr(bmap->eq[k] + 1 + nparam, n_out);
+		isl_int_neg(bmap->eq[k][1 + nparam + i], M->row[0][0]);
+		isl_seq_cpy(bmap->eq[k] + 1 + nparam + n_out,
+			    M->row[1 + i] + 1 + nparam, n_div);
+	}
+	bmap = isl_basic_map_simplify(bmap);
+	bmap = isl_basic_map_finalize(bmap);
+	sol->map = isl_map_grow(sol->map, 1);
+	sol->map = isl_map_add_basic_map(sol->map, bmap);
+	isl_basic_set_free(dom);
+	isl_mat_free(M);
+	if (!sol->map)
+		sol->sol.error = 1;
+	return;
+error:
+	isl_basic_set_free(dom);
+	isl_mat_free(M);
+	isl_basic_map_free(bmap);
+	sol->sol.error = 1;
+}
+
+static void sol_map_add_wrap(struct isl_sol *sol,
+	struct isl_basic_set *dom, struct isl_mat *M)
+{
+	sol_map_add((struct isl_sol_map *)sol, dom, M);
+}
+
+
+/* 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 a 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 a 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 struct isl_vec *ineq_for_div(struct 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.
+ */
+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.
+ */
+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.
+ */
+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;
+}
+
+/* Add a div specified by "div" to the tableau "tab" and return
+ * 1 if the div is obviously non-negative.
+ */
+static int context_tab_add_div(struct isl_tab *tab, struct isl_vec *div,
+	int (*add_ineq)(void *user, isl_int *), void *user)
+{
+	int i;
+	int r;
+	struct isl_mat *samples;
+	int nonneg;
+
+	r = isl_tab_add_div(tab, div, add_ineq, user);
+	if (r < 0)
+		return -1;
+	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 -1;
+	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]);
+	}
+
+	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.
+ */
+static int add_div(struct isl_tab *tab, struct isl_context *context,
+	struct isl_vec *div)
+{
+	int r;
+	int nonneg;
+
+	if ((nonneg = context->op->add_div(context, div)) < 0)
+		goto error;
+
+	if (!context->op->is_ok(context))
+		goto error;
+
+	if (isl_tab_extend_vars(tab, 1) < 0)
+		goto error;
+	r = isl_tab_allocate_var(tab);
+	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;
+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;
+	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 struct isl_tab *tab_for_lexmin(struct isl_basic_map *bmap,
+	struct 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 row 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 int 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) ? 0 : -1;
+}
+
+/* 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);
+}
+
+/* Add a div specified by "div" to the context tableau and return
+ * 1 if the div is obviously non-negative.
+ * context_tab_add_div will always return 1, 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 int context_lex_add_div(struct isl_context *context, struct isl_vec *div)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	int nonneg;
+	nonneg = context_tab_add_div(clex->tab, div,
+					context_lex_add_ineq_wrap, context);
+	if (nonneg < 0)
+		return -1;
+	if (clex->tab->M)
+		return 0;
+	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 void context_lex_free(struct isl_context *context)
+{
+	struct isl_context_lex *clex = (struct isl_context_lex *)context;
+	isl_tab_free(clex->tab);
+	free(clex);
+}
+
+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_add_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(struct isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+
+	if (!bset)
+		return NULL;
+	tab = tab_for_lexmin((struct isl_basic_map *)bset, NULL, 1, 0);
+	if (!tab)
+		goto error;
+	if (isl_tab_track_bset(tab, bset) < 0)
+		goto error;
+	tab = isl_tab_init_samples(tab);
+	return tab;
+error:
+	isl_basic_set_free(bset);
+	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 struct isl_basic_set *drop_constant_terms(struct 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 int 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) ? 0 : -1;
+}
+
+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.
+ *
+ * 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;
+
+	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;
+	}
+
+	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 int context_gbr_add_div(struct isl_context *context, struct isl_vec *div)
+{
+	struct isl_context_gbr *cgbr = (struct isl_context_gbr *)context;
+	if (cgbr->cone) {
+		int k;
+
+		if (isl_tab_extend_cons(cgbr->cone, 3) < 0)
+			return -1;
+		if (isl_tab_extend_vars(cgbr->cone, 1) < 0)
+			return -1;
+		if (isl_tab_allocate_var(cgbr->cone) <0)
+			return -1;
+
+		cgbr->cone->bmap = isl_basic_map_extend_space(cgbr->cone->bmap,
+			isl_basic_map_get_space(cgbr->cone->bmap), 1, 0, 2);
+		k = isl_basic_map_alloc_div(cgbr->cone->bmap);
+		if (k < 0)
+			return -1;
+		isl_seq_cpy(cgbr->cone->bmap->div[k], div->el, div->size);
+		if (isl_tab_push(cgbr->cone, isl_tab_undo_bmap_div) < 0)
+			return -1;
+	}
+	return context_tab_add_div(cgbr->tab, 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 void 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);
+}
+
+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_add_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(struct 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;
+}
+
+static struct isl_context *isl_context_alloc(struct isl_basic_set *dom)
+{
+	if (!dom)
+		return NULL;
+
+	if (dom->ctx->opt->context == ISL_CONTEXT_LEXMIN)
+		return isl_context_lex_alloc(dom);
+	else
+		return isl_context_gbr_alloc(dom);
+}
+
+/* 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(struct isl_basic_map *bmap,
+	struct isl_basic_set *dom, int track_empty, int max)
+{
+	struct isl_sol_map *sol_map = NULL;
+
+	if (!bmap)
+		goto error;
+
+	sol_map = isl_calloc_type(bmap->ctx, struct isl_sol_map);
+	if (!sol_map)
+		goto error;
+
+	sol_map->sol.rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	sol_map->sol.dec_level.callback.run = &sol_dec_level_wrap;
+	sol_map->sol.dec_level.sol = &sol_map->sol;
+	sol_map->sol.max = max;
+	sol_map->sol.n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	sol_map->sol.add = &sol_map_add_wrap;
+	sol_map->sol.add_empty = track_empty ? &sol_map_add_empty_wrap : NULL;
+	sol_map->sol.free = &sol_map_free_wrap;
+	sol_map->map = isl_map_alloc_space(isl_basic_map_get_space(bmap), 1,
+					    ISL_MAP_DISJOINT);
+	if (!sol_map->map)
+		goto error;
+
+	sol_map->sol.context = isl_context_alloc(dom);
+	if (!sol_map->sol.context)
+		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_map_free(sol_map);
+	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;
+}
+
+/* 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);
+			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;
+			}
+			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 struct isl_basic_map *align_context_divs(struct isl_basic_map *bmap,
+	struct 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.
+ */
+static struct isl_sol *basic_map_partial_lexopt_base(
+	__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_order_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 and extract the results.
+ */
+static __isl_give isl_map *basic_map_partial_lexopt_base_map(
+	__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(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;
+}
+
+/* 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 {
+	isl_basic_map *bmap;
+	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.
+ * the isl_dim_out and isl_dim_div dimensions.
+ * If so, return 1 and return the row indices of the two constraints
+ * in *first and *second.
+ */
+static int parallel_constraints(__isl_keep isl_basic_map *bmap,
+	int *first, int *second)
+{
+	int i;
+	isl_ctx *ctx;
+	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);
+	info.bmap = bmap;
+	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;
+		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);
+
+	return i < bmap->n_ineq;
+error:
+	isl_hash_table_free(ctx, table);
+	return -1;
+}
+
+/* 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 int 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 1;
+
+	for (i = 0; i < bmap->n_eq; ++i)
+		if (!isl_int_is_zero(bmap->eq[i][1 + pos]))
+			return 1;
+
+	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 1;
+		if (isl_seq_first_non_zero(bmap->ineq[i] + 1 + pos + 1,
+					   total - pos - 1) >= 0)
+			return 1;
+
+		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 1;
+	}
+
+	return 0;
+}
+
+/* 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 int need_split_basic_set(__isl_keep isl_basic_set *bset,
+	__isl_keep isl_mat *cst)
+{
+	return need_split_basic_map((isl_basic_map *)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 int need_split_set(__isl_keep isl_set *set, __isl_keep isl_mat *cst)
+{
+	int i;
+
+	for (i = 0; i < set->n; ++i)
+		if (need_split_basic_set(set->p[i], cst))
+			return 1;
+
+	return 0;
+}
+
+/* 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_set *set;
+
+		set = isl_set_from_basic_set(isl_basic_set_copy(empty->p[i]));
+		if (need_split_basic_set(empty->p[i], cst))
+			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;
+
+		map = isl_map_from_basic_map(isl_basic_map_copy(opt->p[i]));
+		if (need_split_basic_map(opt->p[i], cst))
+			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);
+
+union isl_lex_res {
+	void *p;
+	isl_map *map;
+	isl_pw_multi_aff *pma;
+};
+
+/* 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 union isl_lex_res basic_map_partial_lexopt_symm_map_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;
+	union isl_lex_res res;
+
+	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);
+
+	res.map = opt;
+	return res;
+}
+
+/* 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.
+ *
+ * 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 union isl_lex_res basic_map_partial_lexopt_symm(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max, int first, int second,
+	__isl_give union isl_lex_res (*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))
+{
+	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;
+	union isl_lex_res res;
+
+	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))
+			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 core(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);
+	res.p = NULL;
+	return res;
+}
+
+static __isl_give isl_map *basic_map_partial_lexopt_symm_map(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max, int first, int second)
+{
+	return basic_map_partial_lexopt_symm(bmap, dom, empty, max,
+		    first, second, &basic_map_partial_lexopt_symm_map_core).map;
+}
+
+/* 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 and then call
+ * this function recursively to look for more parallel constraints.
+ */
+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)
+{
+	int par = 0;
+	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 basic_map_partial_lexopt_base_map(bmap, dom, empty, max);
+	
+	return basic_map_partial_lexopt_symm_map(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 "max" is set)
+ * of "bmap" over the domain "dom" and return the result as a map.
+ * If "empty" is not NULL, then *empty is assigned a set that
+ * contains those parts of the domain where there is no solution.
+ * 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.
+ */
+struct isl_map *isl_tab_basic_map_partial_lexopt(
+		struct isl_basic_map *bmap, struct isl_basic_set *dom,
+		struct isl_set **empty, int max)
+{
+	if (empty)
+		*empty = NULL;
+	if (!bmap || !dom)
+		goto error;
+
+	isl_assert(bmap->ctx,
+	    isl_basic_map_compatible_domain(bmap, dom), goto error);
+
+	if (isl_basic_set_dim(dom, isl_dim_all) == 0)
+		return basic_map_partial_lexopt(bmap, dom, empty, max);
+
+	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 basic_map_partial_lexopt(bmap, dom, empty, max);
+error:
+	isl_basic_set_free(dom);
+	isl_basic_map_free(bmap);
+	return NULL;
+}
+
+struct isl_sol_for {
+	struct isl_sol	sol;
+	int		(*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_for *sol_for)
+{
+	if (!sol_for)
+		return;
+	if (sol_for->sol.context)
+		sol_for->sol.context->op->free(sol_for->sol.context);
+	free(sol_for);
+}
+
+static void sol_for_free_wrap(struct isl_sol *sol)
+{
+	sol_for_free((struct isl_sol_for *)sol);
+}
+
+/* Add the solution identified by the tableau and the context tableau.
+ *
+ * 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,
+	struct isl_basic_set *dom, struct isl_mat *M)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_local_space *ls;
+	isl_aff *aff;
+	isl_aff_list *list;
+
+	if (sol->sol.error || !dom || !M)
+		goto error;
+
+	ctx = isl_basic_set_get_ctx(dom);
+	ls = isl_basic_set_get_local_space(dom);
+	list = isl_aff_list_alloc(ctx, M->n_row - 1);
+	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], M->n_col);
+		}
+		aff = isl_aff_normalize(aff);
+		list = isl_aff_list_add(list, aff);
+	}
+	isl_local_space_free(ls);
+
+	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_mat_free(M);
+	return;
+error:
+	isl_basic_set_free(dom);
+	isl_mat_free(M);
+	sol->sol.error = 1;
+}
+
+static void sol_for_add_wrap(struct isl_sol *sol,
+	struct isl_basic_set *dom, struct isl_mat *M)
+{
+	sol_for_add((struct isl_sol_for *)sol, dom, M);
+}
+
+static struct isl_sol_for *sol_for_init(struct isl_basic_map *bmap, int max,
+	int (*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.rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	sol_for->sol.dec_level.callback.run = &sol_dec_level_wrap;
+	sol_for->sol.dec_level.sol = &sol_for->sol;
+	sol_for->fn = fn;
+	sol_for->user = user;
+	sol_for->sol.max = max;
+	sol_for->sol.n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	sol_for->sol.add = &sol_for_add_wrap;
+	sol_for->sol.add_empty = NULL;
+	sol_for->sol.free = &sol_for_free_wrap;
+
+	sol_for->sol.context = isl_context_alloc(dom);
+	if (!sol_for->sol.context)
+		goto error;
+
+	isl_basic_set_free(dom);
+	return sol_for;
+error:
+	isl_basic_set_free(dom);
+	sol_for_free(sol_for);
+	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);
+}
+
+int isl_basic_map_foreach_lexopt(__isl_keep isl_basic_map *bmap, int max,
+	int (*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 -1;
+
+	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 0;
+error:
+	sol_free(&sol_for->sol);
+	isl_basic_map_free(bmap);
+	return -1;
+}
+
+int isl_basic_set_foreach_lexopt(__isl_keep isl_basic_set *bset, int max,
+	int (*fn)(__isl_take isl_basic_set *dom, __isl_take isl_aff_list *list,
+		  void *user),
+	void *user)
+{
+	return isl_basic_map_foreach_lexopt(bset, max, fn, user);
+}
+
+/* Check if the given sequence of len variables starting at pos
+ * represents a trivial (i.e., zero) solution.
+ * The variables are assumed to be non-negative and to come in pairs,
+ * with each pair representing a variable of unrestricted sign.
+ * The solution is trivial if each such pair in the sequence consists
+ * of two identical values, meaning that the variable being represented
+ * has value zero.
+ */
+static int region_is_trivial(struct isl_tab *tab, int pos, int len)
+{
+	int i;
+
+	if (len == 0)
+		return 0;
+
+	for (i = 0; i < len; i +=  2) {
+		int neg_row;
+		int pos_row;
+
+		neg_row = tab->var[pos + i].is_row ?
+				tab->var[pos + i].index : -1;
+		pos_row = tab->var[pos + i + 1].is_row ?
+				tab->var[pos + i + 1].index : -1;
+
+		if ((neg_row < 0 ||
+		     isl_int_is_zero(tab->mat->row[neg_row][1])) &&
+		    (pos_row < 0 ||
+		     isl_int_is_zero(tab->mat->row[pos_row][1])))
+			continue;
+
+		if (neg_row < 0 || pos_row < 0)
+			return 0;
+		if (isl_int_ne(tab->mat->row[neg_row][1],
+			       tab->mat->row[pos_row][1]))
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Return the index of the first trivial region or -1 if all regions
+ * are non-trivial.
+ */
+static int first_trivial_region(struct isl_tab *tab,
+	int n_region, struct isl_region *region)
+{
+	int i;
+
+	for (i = 0; i < n_region; ++i) {
+		if (region_is_trivial(tab, region[i].pos, region[i].len))
+			return i;
+	}
+
+	return -1;
+}
+
+/* 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 that 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.
+ */
+static int force_better_solution(struct isl_tab *tab,
+	__isl_keep isl_vec *sol, int n_op)
+{
+	int i;
+	isl_ctx *ctx;
+	isl_vec *v = NULL;
+
+	if (!sol)
+		return -1;
+
+	for (i = 0; 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 0;
+	}
+
+	ctx = isl_vec_get_ctx(sol);
+	v = isl_vec_alloc(ctx, 1 + tab->n_var);
+	if (!v)
+		return -1;
+
+	for (; i >= 0; --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 0;
+error:
+	isl_vec_free(v);
+	return -1;
+}
+
+struct isl_trivial {
+	int update;
+	int region;
+	int side;
+	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 solution 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 pairs
+ * of variables.  A solution is non-trivial on such a region if
+ * at least one of these pairs consists of different values, i.e.,
+ * such that the non-negative variable represented by the pair is non-zero.
+ *
+ * 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 initially trivial region that is forced
+ * to be non-trivial.
+ * At each level we consider n cases, where n is the length of the region.
+ * In terms of the n/2 variables of unrestricted signs being encoded by
+ * the region, we consider the cases
+ *	x_0 >= 1
+ *	x_0 <= -1
+ *	x_0 = 0 and x_1 >= 1
+ *	x_0 = 0 and x_1 <= -1
+ *	x_0 = 0 and x_1 = 0 and x_2 >= 1
+ *	x_0 = 0 and x_1 = 0 and x_2 <= -1
+ *	...
+ * The cases are considered in this order, assuming that each pair
+ * x_i_a x_i_b represents the value x_i_b - x_i_a.
+ * That is, x_0 >= 1 is enforced by adding the constraint
+ *	x_0_b - x_0_a >= 1
+ */
+__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_region *region,
+	int (*conflict)(int con, void *user), void *user)
+{
+	int i, j;
+	int r;
+	isl_ctx *ctx;
+	isl_vec *v = NULL;
+	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;
+
+	v = isl_vec_alloc(ctx, 1 + tab->n_var);
+	triv = isl_calloc_array(ctx, struct isl_trivial, n_region);
+	if (!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) {
+				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);
+			if (isl_tab_extend_cons(tab,
+					    2 * region[r].len + 2 * n_op) < 0)
+				goto error;
+			triv[level].region = r;
+			triv[level].side = 0;
+		}
+
+		r = triv[level].region;
+		side = triv[level].side;
+		base = 2 * (side/2);
+
+		if (side >= region[r].len) {
+backtrack:
+			level--;
+			init = 0;
+			if (level >= 0)
+				if (isl_tab_rollback(tab, triv[level].snap) < 0)
+					goto error;
+			continue;
+		}
+
+		if (triv[level].update) {
+			if (force_better_solution(tab, sol, n_op) < 0)
+				goto error;
+			triv[level].update = 0;
+		}
+
+		if (side == base && base >= 2) {
+			for (j = base - 2; j < base; ++j) {
+				v = isl_vec_clr(v);
+				isl_int_set_si(v->el[1 + region[r].pos + j], 1);
+				if (add_lexmin_eq(tab, v->el) < 0)
+					goto error;
+			}
+		}
+
+		triv[level].snap = isl_tab_snap(tab);
+		if (isl_tab_push_basis(tab) < 0)
+			goto error;
+
+		v = isl_vec_clr(v);
+		isl_int_set_si(v->el[0], -1);
+		isl_int_set_si(v->el[1 + region[r].pos + side], -1);
+		isl_int_set_si(v->el[1 + region[r].pos + (side ^ 1)], 1);
+		tab = add_lexmin_ineq(tab, v->el);
+
+		triv[level].side++;
+		level++;
+		init = 1;
+	}
+
+	free(triv);
+	isl_vec_free(v);
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+
+	return sol;
+error:
+	free(triv);
+	isl_vec_free(v);
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+	isl_vec_free(sol);
+	return NULL;
+}
+
+/* Return the lexicographically smallest rational point in "bset",
+ * assuming that all variables are non-negative.
+ * If "bset" is empty, then return a zero-length vector.
+ */
+__isl_give isl_vec *isl_tab_basic_set_non_neg_lexmin(
+	__isl_take isl_basic_set *bset)
+{
+	struct isl_tab *tab;
+	isl_ctx *ctx = isl_basic_set_get_ctx(bset);
+	isl_vec *sol;
+
+	if (!bset)
+		return NULL;
+
+	tab = tab_for_lexmin(bset, NULL, 0, 0);
+	if (!tab)
+		goto error;
+	if (tab->empty)
+		sol = isl_vec_alloc(ctx, 0);
+	else
+		sol = isl_tab_get_sample_value(tab);
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+	return sol;
+error:
+	isl_tab_free(tab);
+	isl_basic_set_free(bset);
+	return NULL;
+}
+
+struct isl_sol_pma {
+	struct isl_sol	sol;
+	isl_pw_multi_aff *pma;
+	isl_set *empty;
+};
+
+static void sol_pma_free(struct isl_sol_pma *sol_pma)
+{
+	if (!sol_pma)
+		return;
+	if (sol_pma->sol.context)
+		sol_pma->sol.context->op->free(sol_pma->sol.context);
+	isl_pw_multi_aff_free(sol_pma->pma);
+	isl_set_free(sol_pma->empty);
+	free(sol_pma);
+}
+
+/* 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 map "dom" that represents the context and an affine
+ * matrix "M" that maps the dimensions of the context to the
+ * output variables, construct an isl_pw_multi_aff with a single
+ * cell corresponding to "dom" and affine expressions copied from "M".
+ */
+static void sol_pma_add(struct isl_sol_pma *sol,
+	__isl_take isl_basic_set *dom, __isl_take isl_mat *M)
+{
+	int i;
+	isl_local_space *ls;
+	isl_aff *aff;
+	isl_multi_aff *maff;
+	isl_pw_multi_aff *pma;
+
+	maff = isl_multi_aff_alloc(isl_pw_multi_aff_get_space(sol->pma));
+	ls = isl_basic_set_get_local_space(dom);
+	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], M->n_col);
+		}
+		aff = isl_aff_normalize(aff);
+		maff = isl_multi_aff_set_aff(maff, i - 1, aff);
+	}
+	isl_local_space_free(ls);
+	isl_mat_free(M);
+	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_free_wrap(struct isl_sol *sol)
+{
+	sol_pma_free((struct isl_sol_pma *)sol);
+}
+
+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_mat *M)
+{
+	sol_pma_add((struct isl_sol_pma *)sol, dom, M);
+}
+
+/* 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;
+
+	if (!bmap)
+		goto error;
+
+	sol_pma = isl_calloc_type(bmap->ctx, struct isl_sol_pma);
+	if (!sol_pma)
+		goto error;
+
+	sol_pma->sol.rational = ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL);
+	sol_pma->sol.dec_level.callback.run = &sol_dec_level_wrap;
+	sol_pma->sol.dec_level.sol = &sol_pma->sol;
+	sol_pma->sol.max = max;
+	sol_pma->sol.n_out = isl_basic_map_dim(bmap, isl_dim_out);
+	sol_pma->sol.add = &sol_pma_add_wrap;
+	sol_pma->sol.add_empty = track_empty ? &sol_pma_add_empty_wrap : NULL;
+	sol_pma->sol.free = &sol_pma_free_wrap;
+	sol_pma->pma = isl_pw_multi_aff_empty(isl_basic_map_get_space(bmap));
+	if (!sol_pma->pma)
+		goto error;
+
+	sol_pma->sol.context = isl_context_alloc(dom);
+	if (!sol_pma->sol.context)
+		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_pma_free(sol_pma);
+	return NULL;
+}
+
+/* Base case of isl_tab_basic_map_partial_lexopt, after removing
+ * some obvious symmetries.
+ *
+ * We call basic_map_partial_lexopt_base and extract the results.
+ */
+static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_base_pma(
+	__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(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 if (need_split_set(opt->p[i].set, cst))
+			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_pma(
+	__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 union isl_lex_res basic_map_partial_lexopt_symm_pma_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_pw_multi_aff *opt;
+	isl_pw_aff *min_expr_pa;
+	isl_set *min_expr;
+	union isl_lex_res res;
+
+	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_pma(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);
+
+	res.pma = opt;
+	return res;
+}
+
+static __isl_give isl_pw_multi_aff *basic_map_partial_lexopt_symm_pma(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max, int first, int second)
+{
+	return basic_map_partial_lexopt_symm(bmap, dom, empty, max,
+		    first, second, &basic_map_partial_lexopt_symm_pma_core).pma;
+}
+
+/* Recursive part of isl_basic_map_partial_lexopt_pw_multi_aff, 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 isl_pw_multi_aff *basic_map_partial_lexopt_pma(
+	__isl_take isl_basic_map *bmap, __isl_take isl_basic_set *dom,
+	__isl_give isl_set **empty, int max)
+{
+	int par = 0;
+	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 basic_map_partial_lexopt_base_pma(bmap, dom, empty, max);
+	
+	return basic_map_partial_lexopt_symm_pma(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 "max" is set)
+ * of "bmap" over the domain "dom" and return the result as a piecewise
+ * multi-affine expression.
+ * If "empty" is not NULL, then *empty is assigned a set that
+ * contains those parts of the domain where there is no solution.
+ * 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.
+ */
+__isl_give isl_pw_multi_aff *isl_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)
+{
+	if (empty)
+		*empty = NULL;
+	if (!bmap || !dom)
+		goto error;
+
+	isl_assert(bmap->ctx,
+	    isl_basic_map_compatible_domain(bmap, dom), goto error);
+
+	if (isl_basic_set_dim(dom, isl_dim_all) == 0)
+		return basic_map_partial_lexopt_pma(bmap, dom, empty, max);
+
+	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 basic_map_partial_lexopt_pma(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_tarjan.c b/final/lib/External/isl/isl_tarjan.c
new file mode 100644
index 0000000..414a2e0
--- /dev/null
+++ b/final/lib/External/isl/isl_tarjan.c
@@ -0,0 +1,138 @@
+/*
+ * 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>
+
+void isl_tarjan_graph_free(struct isl_tarjan_graph *g)
+{
+	if (!g)
+		return;
+	free(g->node);
+	free(g->stack);
+	free(g->order);
+	free(g);
+}
+
+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)
+			goto error;
+	}
+
+	return g;
+error:
+	isl_tarjan_graph_free(g);
+	return NULL;
+}
diff --git a/final/lib/External/isl/isl_tarjan.h b/final/lib/External/isl/isl_tarjan.h
new file mode 100644
index 0000000..1f8f02e
--- /dev/null
+++ b/final/lib/External/isl/isl_tarjan.h
@@ -0,0 +1,40 @@
+#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);
+void 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..5eed5d2
--- /dev/null
+++ b/final/lib/External/isl/isl_test.c
@@ -0,0 +1,5979 @@
+/*
+ * 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/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.h>
+#include <isl/ast_build.h>
+#include <isl/val.h>
+#include <isl/ilp.h>
+#include <isl_ast_build_expr.h>
+#include <isl/options.h>
+
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
+
+static char *srcdir;
+
+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;
+}
+
+int test_parse(struct isl_ctx *ctx)
+{
+	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) }");
+
+	str = "{ [x,y]  : [([x/2]+y)/3] >= 1 }";
+	str2 = "{ [x, y] : 2y >= 6 - x }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	if (test_parse_map_equal(ctx, "{ [x,y] : x <= min(y, 2*y+3) }",
+				      "{ [x,y] : x <= y, 2*y + 3 }") < 0)
+		return -1;
+	str = "{ [x, y] : (y <= x and y >= -3) or (2y <= -3 + x and y <= -4) }";
+	if (test_parse_map_equal(ctx, "{ [x,y] : x >= min(y, 2*y+3) }",
+					str) < 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);
+
+	str = "[n] -> { [c1] : c1>=0 and c1<=floord(n-4,3) }";
+	str2 = "[n] -> { [c1] : c1 >= 0 and 3c1 <= -4 + n }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "{ [i,j] -> [i] : i < j; [i,j] -> [j] : j <= i }";
+	str2 = "{ [i,j] -> [min(i,j)] }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "{ [i,j] : i != j }";
+	str2 = "{ [i,j] : i < j or i > j }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "{ [i,j] : (i+1)*2 >= j }";
+	str2 = "{ [i, j] : j <= 2 + 2i }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "{ [i] -> [i > 0 ? 4 : 5] }";
+	str2 = "{ [i] -> [5] : i <= 0; [i] -> [4] : i >= 1 }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "[N=2,M] -> { [i=[(M+N)/4]] }";
+	str2 = "[N, M] -> { [i] : N = 2 and 4i <= 2 + M and 4i >= -1 + M }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "{ [x] : x >= 0 }";
+	str2 = "{ [x] : x-0 >= 0 }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "{ [i] : ((i > 10)) }";
+	str2 = "{ [i] : i >= 11 }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	str = "{ [i] -> [0] }";
+	str2 = "{ [i] -> [0 * i] }";
+	if (test_parse_map_equal(ctx, str, str2) < 0)
+		return -1;
+
+	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]) }");
+
+	if (test_parse_map_equal(ctx, "{ [a] -> [b] : (not false) }",
+				      "{ [a] -> [b] : true }") < 0)
+		return -1;
+
+	if (test_parse_map_equal(ctx, "{ [i] : i/2 <= 5 }",
+				      "{ [i] : i <= 10 }") < 0)
+		return -1;
+
+	if (test_parse_map_equal(ctx, "{Sym=[n] [i] : i <= n }",
+				      "[n] -> { [i] : i <= n }") < 0)
+		return -1;
+
+	if (test_parse_map_equal(ctx, "{ [*] }", "{ [a] }") < 0)
+		return -1;
+
+	if (test_parse_map_equal(ctx, "{ [i] : 2*floor(i/2) = i }",
+				      "{ [i] : exists a : i = 2 a }") < 0)
+		return -1;
+
+	if (test_parse_map_equal(ctx, "{ [a] -> [b] : a = 5 implies b = 5 }",
+				      "{ [a] -> [b] : a != 5 or b = 5 }") < 0)
+		return -1;
+
+	if (test_parse_map_equal(ctx, "{ [a] -> [a - 1 : a > 0] }",
+				      "{ [a] -> [a - 1] : a > 0 }") < 0)
+		return -1;
+	if (test_parse_map_equal(ctx,
+	    "{ [a] -> [a - 1 : a > 0; a : a <= 0] }",
+	    "{ [a] -> [a - 1] : a > 0; [a] -> [a] : a <= 0 }") < 0)
+		return -1;
+	if (test_parse_map_equal(ctx,
+	    "{ [a] -> [(a) * 2 : a >= 0; 0 : a < 0] }",
+	    "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }") < 0)
+		return -1;
+	if (test_parse_map_equal(ctx,
+	    "{ [a] -> [(a * 2) : a >= 0; 0 : a < 0] }",
+	    "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }") < 0)
+		return -1;
+	if (test_parse_map_equal(ctx,
+	    "{ [a] -> [(a * 2 : a >= 0); 0 : a < 0] }",
+	    "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }") < 0)
+		return -1;
+	if (test_parse_map_equal(ctx,
+	    "{ [a] -> [(a * 2 : a >= 0; 0 : a < 0)] }",
+	    "{ [a] -> [2a] : a >= 0; [a] -> [0] : a < 0 }") < 0)
+		return -1;
+
+	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;
+	int 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(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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 1);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -5);
+	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;
+}
+
+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;
+}
+
+static int test_div(isl_ctx *ctx)
+{
+	unsigned n;
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 4);
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, -1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	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);
+	isl_constraint_set_constant(c, v);
+	isl_int_set_si(v, 1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 6);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 6);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	isl_int_set_si(v, -3);
+	isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	isl_int_set_si(v, 6);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -3);
+	isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	isl_int_set_si(v, -3);
+	isl_constraint_set_coefficient(c, isl_dim_set, 3, v);
+	isl_int_set_si(v, 6);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 2, v);
+	isl_int_set_si(v, 1);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -1);
+	isl_constraint_set_coefficient(c, isl_dim_set, 1, v);
+	isl_int_set_si(v, -2);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, 3);
+	isl_constraint_set_coefficient(c, isl_dim_set, 3, v);
+	isl_int_set_si(v, 2);
+	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);
+	isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
+	isl_int_set_si(v, -2);
+	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;
+
+	str = "{ [i,j] : 2*[i/2] + 3 * [j/4] <= 10 and 2 i = j }";
+	bset = isl_basic_set_read_from_str(ctx, str);
+	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);
+
+	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;
+}
+
+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 }" },
+};
+
+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);
+}
+
+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] }" },
+};
+
+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;
+		isl_set *set1, *set2, *copy;
+
+		set1 = isl_set_read_from_str(ctx, gist_tests[i].set);
+		set2 = isl_set_read_from_str(ctx, gist_tests[i].context);
+		copy = isl_set_copy(set1);
+		set1 = isl_set_gist(set1, set2);
+		set2 = isl_set_read_from_str(ctx, gist_tests[i].gist);
+		equal = isl_set_is_equal(set1, set2);
+		isl_set_free(set1);
+		isl_set_free(set2);
+		set1 = isl_set_read_from_str(ctx, gist_tests[i].set);
+		equal_input = isl_set_is_equal(set1, copy);
+		isl_set_free(set1);
+		isl_set_free(copy);
+		if (equal < 0 || equal_input < 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);
+	}
+
+	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);
+
+	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 }" },
+};
+
+/* 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(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(map2);
+	map2 = isl_map_coalesce(map2);
+	isl_map_free(map2);
+	if (!map2)
+		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;
+
+	return 0;
+}
+
+static int test_closure(isl_ctx *ctx)
+{
+	const char *str;
+	isl_set *dom;
+	isl_map *up, *right;
+	isl_map *map, *map2;
+	int exact;
+
+	/* 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);
+
+	/* COCOA Fig.1 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);
+	map = isl_map_union(up, right);
+	map = isl_map_transitive_closure(map, &exact);
+	assert(exact);
+	map2 = isl_map_read_from_str(ctx,
+		"{ [0,0] -> [0,1]; [0,0] -> [1,1]; [0,1] -> [1,1]; "
+		"  [2,2] -> [3,2]; [2,2] -> [3,3]; [3,2] -> [3,3] }");
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map2);
+	isl_map_free(map);
+
+	/* 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;
+}
+
+static int test_lexmin(struct isl_ctx *ctx)
+{
+	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);
+
+	str = "{ [x] -> [y] : x <= y <= 10; [x] -> [5] : -8 <= x <= 8 }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_lexmin(map);
+	str = "{ [x] -> [5] : 6 <= x <= 8; "
+		"[x] -> [x] : x <= 5 or (9 <= x <= 10) }";
+	map2 = isl_map_read_from_str(ctx, str);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	str = "{ [x] -> [y] : 4y = x or 4y = -1 + x or 4y = -2 + x }";
+	map = isl_map_read_from_str(ctx, str);
+	map2 = isl_map_copy(map);
+	map = isl_map_lexmin(map);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	str = "{ [x] -> [y] : x = 4y; [x] -> [y] : x = 2y }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_lexmin(map);
+	str = "{ [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)) }";
+	map2 = isl_map_read_from_str(ctx, str);
+	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 }";
+	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 = "{ T[a] -> S[b, c] : a = 4b-2c and c >= b }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_lexmin(map);
+	str = "{ T[a] -> S[b, c] : 2b = a and 2c = a }";
+	map2 = isl_map_read_from_str(ctx, str);
+	assert(isl_map_is_equal(map, map2));
+	isl_map_free(map);
+	isl_map_free(map2);
+
+	/* Check that empty pieces are properly combined. */
+	str = "[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 }";
+	map = isl_map_read_from_str(ctx, str);
+	map = isl_map_lexmin(map);
+	str = "[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 }";
+	map2 = isl_map_read_from_str(ctx, str);
+	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;
+}
+
+/* Check that isl_set_min_val and isl_set_max_val compute the correct
+ * result on non-convex inputs.
+ */
+static int test_min(struct isl_ctx *ctx)
+{
+	isl_set *set;
+	isl_aff *aff;
+	isl_val *val;
+	int min_ok, max_ok;
+
+	set = isl_set_read_from_str(ctx, "{ [-1]; [1] }");
+	aff = isl_aff_read_from_str(ctx, "{ [x] -> [x] }");
+	val = isl_set_min_val(set, aff);
+	min_ok = isl_val_is_negone(val);
+	isl_val_free(val);
+	val = isl_set_max_val(set, aff);
+	max_ok = isl_val_is_one(val);
+	isl_val_free(val);
+	isl_aff_free(aff);
+	isl_set_free(set);
+
+	if (min_ok < 0 || max_ok < 0)
+		return -1;
+	if (!min_ok)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected minimum", return -1);
+	if (!max_ok)
+		isl_die(ctx, isl_error_unknown,
+			"unexpected maximum", 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 },
+};
+
+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;
+}
+
+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;
+}
+
+/* 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;
+
+	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.
+ */
+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;
+
+	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);
+	isl_schedule_free(schedule);
+
+	if (!schedule)
+		return -1;
+
+	return 0;
+}
+
+int test_schedule(isl_ctx *ctx)
+{
+	const char *D, *W, *R, *V, *P, *S;
+
+	/* 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] }";
+	if (test_one_schedule(ctx, D, W, R, S, 2, 0) < 0)
+		return -1;
+
+	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;
+	S = "{ Stmt_for_body24[i0, i1, i2, i3] -> "
+		"[i0, 5i0 + i1, 6i0 + i1 + i2, 1 + 6i0 + i1 + i2 + i3, 1];"
+	    "Stmt_for_body7[i0, i1, i2] -> [0, 5i0, 6i0 + i1, 6i0 + i2, 0] }";
+
+	if (test_special_schedule(ctx, D, V, P, S) < 0)
+		return -1;
+
+	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, 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;
+
+	/* 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;
+
+	return 0;
+}
+
+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_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 }" },
+};
+
+/* 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;
+}
+
+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_upma(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;
+}
+
+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;
+
+	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;
+}
+
+int test_equal(isl_ctx *ctx)
+{
+	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);
+
+	return 0;
+}
+
+static int test_plain_fixed(isl_ctx *ctx, __isl_take isl_map *map,
+	enum isl_dim_type type, unsigned pos, int fixed)
+{
+	int 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[2];
+} 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] }" } },
+};
+
+/* 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;
+}
+
+int test_output(isl_ctx *ctx)
+{
+	char *s;
+	const char *str;
+	isl_pw_aff *pa;
+	isl_printer *p;
+	int equal;
+
+	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;
+	int 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 = -1);
+	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, a);
+	list = isl_id_list_add(list, b);
+	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)] }",
+};
+
+/* 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;
+}
+
+/* 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)
+{
+	const char *str;
+	isl_map *map1, *map2;
+	isl_pw_multi_aff *pma;
+	int equal;
+
+	str = "{ [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) }";
+	map1 = isl_map_read_from_str(ctx, str);
+	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] }" },
+};
+
+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_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_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;
+}
+
+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;
+	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(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;
+}
+
+/* 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;
+}
+
+struct {
+	const char *name;
+	int (*fn)(isl_ctx *ctx);
+} tests [] = {
+	{ "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 },
+	{ "fixed", &test_fixed },
+	{ "equal", &test_equal },
+	{ "disjoint", &test_disjoint },
+	{ "product", &test_product },
+	{ "dim_max", &test_dim_max },
+	{ "affine", &test_aff },
+	{ "injective", &test_injective },
+	{ "schedule", &test_schedule },
+	{ "schedule tree grouping", &test_schedule_tree_group },
+	{ "tile", &test_tile },
+	{ "union_pw", &test_union_pw },
+	{ "parse", &test_parse },
+	{ "single-valued", &test_sv },
+	{ "affine hull", &test_affine_hull },
+	{ "coalesce", &test_coalesce },
+	{ "factorize", &test_factorize },
+	{ "subset", &test_subset },
+	{ "subtract", &test_subtract },
+	{ "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;
+
+	srcdir = getenv("srcdir");
+	assert(srcdir);
+
+	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..e28f6a2
--- /dev/null
+++ b/final/lib/External/isl/isl_test_int.c
@@ -0,0 +1,623 @@
+/*
+ * 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);
+}
+
+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_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)
+{
+	isl_int result;
+	isl_int_init(result);
+
+	isl_int_cdiv_q(result, lhs, rhs);
+	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)));
+}
+
+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_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" },
+};
+
+/* 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..f031f67
--- /dev/null
+++ b/final/lib/External/isl/isl_transitive_closure.c
@@ -0,0 +1,2993 @@
+/*
+ * 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 int 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;
+	int 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 -1;
+}
+
+/* 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;
+	int 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);
+	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) {
+			int 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 int isl_set_overlaps(__isl_keep isl_set *set1, __isl_keep isl_set *set2)
+{
+	isl_set *i;
+	int no_overlap;
+
+	if (!set1 || !set2)
+		return -1;
+
+	if (!isl_space_tuple_is_equal(set1->dim, isl_dim_set,
+					set2->dim, isl_dim_set))
+		return 0;
+
+	i = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
+	no_overlap = isl_set_is_empty(i);
+	isl_set_free(i);
+
+	return no_overlap < 0 ? -1 : !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;
+	int 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) {
+		int 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) {
+		int 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(map));
+
+	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;
+}
+
+/* Check whether equality i of bset is a pure stride constraint
+ * on a single dimensions, i.e., of the form
+ *
+ *	v = k e
+ *
+ * with k a constant and e an existentially quantified variable.
+ */
+static int is_eq_stride(__isl_keep isl_basic_set *bset, int i)
+{
+	unsigned nparam;
+	unsigned d;
+	unsigned n_div;
+	int pos1;
+	int pos2;
+
+	if (!bset)
+		return -1;
+
+	if (!isl_int_is_zero(bset->eq[i][0]))
+		return 0;
+
+	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 0;
+	pos1 = isl_seq_first_non_zero(bset->eq[i] + 1 + nparam, d);
+	if (pos1 == -1)
+		return 0;
+	if (isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + pos1 + 1, 
+					d - pos1 - 1) != -1)
+		return 0;
+
+	pos2 = isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + d, n_div);
+	if (pos2 == -1)
+		return 0;
+	if (isl_seq_first_non_zero(bset->eq[i] + 1 + nparam + d  + pos2 + 1,
+				   n_div - pos2 - 1) != -1)
+		return 0;
+	if (!isl_int_is_one(bset->eq[i][1 + nparam + pos1]) &&
+	    !isl_int_is_negone(bset->eq[i][1 + nparam + pos1]))
+		return 0;
+
+	return 1;
+}
+
+/* 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 (!is_eq_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_map.c b/final/lib/External/isl/isl_union_map.c
new file mode 100644
index 0000000..2cae0bc
--- /dev/null
+++ b/final/lib/External/isl/isl_union_map.c
@@ -0,0 +1,3763 @@
+/*
+ * Copyright 2010-2011 INRIA Saclay
+ * Copyright 2013-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 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/deprecated/union_map_int.h>
+
+/* 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;
+}
+
+__isl_give isl_space *isl_union_map_get_space(__isl_keep isl_union_map *umap)
+{
+	if (!umap)
+		return NULL;
+	return isl_space_copy(umap->dim);
+}
+
+/* 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 };
+
+	if (!umap || !model)
+		goto error;
+
+	if (isl_space_match(umap->dim, isl_dim_param, model, isl_dim_param)) {
+		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);
+}
+
+static int has_dim(const void *entry, const void *val)
+{
+	isl_map *map = (isl_map *)entry;
+	isl_space *dim = (isl_space *)val;
+
+	return isl_space_is_equal(map->dim, dim);
+}
+
+__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;
+
+	if (!map || !umap)
+		goto error;
+
+	if (isl_map_plain_is_empty(map)) {
+		isl_map_free(map);
+		return umap;
+	}
+
+	if (!isl_space_match(map->dim, isl_dim_param, umap->dim, isl_dim_param)) {
+		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_dim, 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, (isl_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((isl_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_dim, 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 (isl_set *)isl_union_map_extract_map(uset, dim);
+}
+
+/* Check if umap contains a map in the given space.
+ */
+__isl_give int isl_union_map_contains(__isl_keep isl_union_map *umap,
+	__isl_keep isl_space *dim)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	if (!umap || !dim)
+		return -1;
+
+	hash = isl_space_get_hash(dim);
+	entry = isl_hash_table_find(umap->dim->ctx, &umap->table, hash,
+				    &has_dim, dim, 0);
+	return !!entry;
+}
+
+__isl_give int isl_union_set_contains(__isl_keep isl_union_set *uset,
+	__isl_keep isl_space *dim)
+{
+	return isl_union_map_contains(uset, dim);
+}
+
+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);
+}
+
+struct isl_union_map_gen_bin_data {
+	isl_union_map *umap2;
+	isl_union_map *res;
+};
+
+static isl_stat subtract_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_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_dim, map->dim, 0);
+	map = isl_map_copy(map);
+	if (entry2) {
+		int empty;
+		map = isl_map_subtract(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 *gen_bin_op(__isl_take isl_union_map *umap1,
+	__isl_take isl_union_map *umap2, isl_stat (*fn)(void **, void *))
+{
+	struct isl_union_map_gen_bin_data data = { 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,
+				   fn, &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)
+{
+	return gen_bin_op(umap1, umap2, &subtract_entry);
+}
+
+__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_dim, 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);
+}
+
+static __isl_give isl_map *lex_le_set(__isl_take isl_map *set1,
+	__isl_take isl_map *set2)
+{
+	return isl_set_lex_le_set((isl_set *)set1, (isl_set *)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((isl_set *)set1, (isl_set *)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));
+}
+
+static isl_stat intersect_domain_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *dim;
+	isl_map *map = *entry;
+	isl_bool empty;
+
+	dim = isl_map_get_space(map);
+	dim = isl_space_domain(dim);
+	hash = isl_space_get_hash(dim);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_dim, dim, 0);
+	isl_space_free(dim);
+	if (!entry2)
+		return isl_stat_ok;
+
+	map = isl_map_copy(map);
+	map = isl_map_intersect_domain(map, isl_set_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;
+}
+
+/* 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);
+	return gen_bin_op(umap, uset, &intersect_domain_entry);
+}
+
+/* Remove the elements of data->umap2 from the domain of *entry
+ * and add the result to data->res.
+ */
+static isl_stat subtract_domain_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *dim;
+	isl_map *map = *entry;
+	isl_bool empty;
+
+	dim = isl_map_get_space(map);
+	dim = isl_space_domain(dim);
+	hash = isl_space_get_hash(dim);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_dim, dim, 0);
+	isl_space_free(dim);
+
+	map = isl_map_copy(map);
+
+	if (!entry2) {
+		data->res = isl_union_map_add_map(data->res, map);
+		return isl_stat_ok;
+	}
+
+	map = isl_map_subtract_domain(map, isl_set_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;
+}
+
+/* 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)
+{
+	return gen_bin_op(umap, dom, &subtract_domain_entry);
+}
+
+/* Remove the elements of data->umap2 from the range of *entry
+ * and add the result to data->res.
+ */
+static isl_stat subtract_range_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *space;
+	isl_map *map = *entry;
+	isl_bool empty;
+
+	space = isl_map_get_space(map);
+	space = isl_space_range(space);
+	hash = isl_space_get_hash(space);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_dim, space, 0);
+	isl_space_free(space);
+
+	map = isl_map_copy(map);
+
+	if (!entry2) {
+		data->res = isl_union_map_add_map(data->res, map);
+		return isl_stat_ok;
+	}
+
+	map = isl_map_subtract_range(map, isl_set_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;
+}
+
+/* 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)
+{
+	return gen_bin_op(umap, dom, &subtract_range_entry);
+}
+
+static isl_stat gist_domain_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *dim;
+	isl_map *map = *entry;
+	isl_bool empty;
+
+	dim = isl_map_get_space(map);
+	dim = isl_space_domain(dim);
+	hash = isl_space_get_hash(dim);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_dim, dim, 0);
+	isl_space_free(dim);
+	if (!entry2)
+		return isl_stat_ok;
+
+	map = isl_map_copy(map);
+	map = isl_map_gist_domain(map, isl_set_copy(entry2->data));
+
+	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;
+}
+
+/* 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);
+	return gen_bin_op(umap, uset, &gist_domain_entry);
+}
+
+static isl_stat gist_range_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *space;
+	isl_map *map = *entry;
+	isl_bool empty;
+
+	space = isl_map_get_space(map);
+	space = isl_space_range(space);
+	hash = isl_space_get_hash(space);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_dim, space, 0);
+	isl_space_free(space);
+	if (!entry2)
+		return isl_stat_ok;
+
+	map = isl_map_copy(map);
+	map = isl_map_gist_range(map, isl_set_copy(entry2->data));
+
+	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;
+}
+
+/* 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)
+{
+	return gen_bin_op(umap, uset, &gist_range_entry);
+}
+
+static isl_stat intersect_range_entry(void **entry, void *user)
+{
+	struct isl_union_map_gen_bin_data *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *dim;
+	isl_map *map = *entry;
+	isl_bool empty;
+
+	dim = isl_map_get_space(map);
+	dim = isl_space_range(dim);
+	hash = isl_space_get_hash(dim);
+	entry2 = isl_hash_table_find(data->umap2->dim->ctx, &data->umap2->table,
+				     hash, &has_dim, dim, 0);
+	isl_space_free(dim);
+	if (!entry2)
+		return isl_stat_ok;
+
+	map = isl_map_copy(map);
+	map = isl_map_intersect_range(map, isl_set_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;
+}
+
+__isl_give isl_union_map *isl_union_map_intersect_range(
+	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)
+{
+	return gen_bin_op(umap, uset, &intersect_range_entry);
+}
+
+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);
+}
+
+static __isl_give isl_union_set *cond_un_op(__isl_take isl_union_map *umap,
+	isl_stat (*fn)(void **, void *))
+{
+	isl_union_set *res;
+
+	if (!umap)
+		return NULL;
+
+	res = isl_union_map_alloc(isl_space_copy(umap->dim), umap->table.n);
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, fn, &res) < 0)
+		goto error;
+
+	isl_union_map_free(umap);
+	return res;
+error:
+	isl_union_map_free(umap);
+	isl_union_set_free(res);
+	return NULL;
+}
+
+static isl_stat from_range_entry(void **entry, void *user)
+{
+	isl_map *set = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_map_add_map(*res,
+					isl_map_from_range(isl_set_copy(set)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_from_range(
+	__isl_take isl_union_set *uset)
+{
+	return cond_un_op(uset, &from_range_entry);
+}
+
+__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));
+}
+
+static __isl_give isl_union_map *un_op(__isl_take isl_union_map *umap,
+	isl_stat (*fn)(void **, void *))
+{
+	umap = isl_union_map_cow(umap);
+	if (!umap)
+		return NULL;
+
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table, fn, NULL) < 0)
+		goto error;
+
+	return umap;
+error:
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+static isl_stat affine_entry(void **entry, void *user)
+{
+	isl_map **map = (isl_map **)entry;
+
+	*map = isl_map_from_basic_map(isl_map_affine_hull(*map));
+
+	return *map ? isl_stat_ok : isl_stat_error;
+}
+
+__isl_give isl_union_map *isl_union_map_affine_hull(
+	__isl_take isl_union_map *umap)
+{
+	return un_op(umap, &affine_entry);
+}
+
+__isl_give isl_union_set *isl_union_set_affine_hull(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_affine_hull(uset);
+}
+
+static isl_stat polyhedral_entry(void **entry, void *user)
+{
+	isl_map **map = (isl_map **)entry;
+
+	*map = isl_map_from_basic_map(isl_map_polyhedral_hull(*map));
+
+	return *map ? isl_stat_ok : isl_stat_error;
+}
+
+__isl_give isl_union_map *isl_union_map_polyhedral_hull(
+	__isl_take isl_union_map *umap)
+{
+	return un_op(umap, &polyhedral_entry);
+}
+
+__isl_give isl_union_set *isl_union_set_polyhedral_hull(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_polyhedral_hull(uset);
+}
+
+static isl_stat simple_entry(void **entry, void *user)
+{
+	isl_map **map = (isl_map **)entry;
+
+	*map = isl_map_from_basic_map(isl_map_simple_hull(*map));
+
+	return *map ? isl_stat_ok : isl_stat_error;
+}
+
+__isl_give isl_union_map *isl_union_map_simple_hull(
+	__isl_take isl_union_map *umap)
+{
+	return un_op(umap, &simple_entry);
+}
+
+__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_stat inplace_entry(void **entry, void *user)
+{
+	__isl_give isl_map *(*fn)(__isl_take isl_map *);
+	isl_map **map = (isl_map **)entry;
+	isl_map *copy;
+
+	fn = *(__isl_give isl_map *(**)(__isl_take isl_map *)) user;
+	copy = fn(isl_map_copy(*map));
+	if (!copy)
+		return isl_stat_error;
+
+	isl_map_free(*map);
+	*map = copy;
+
+	return isl_stat_ok;
+}
+
+static __isl_give isl_union_map *inplace(__isl_take isl_union_map *umap,
+	__isl_give isl_map *(*fn)(__isl_take isl_map *))
+{
+	if (!umap)
+		return NULL;
+
+	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,
+				    &inplace_entry, &fn) < 0)
+		goto error;
+
+	return umap;
+error:
+	isl_union_map_free(umap);
+	return NULL;
+}
+
+/* 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);
+}
+
+static isl_stat lexmin_entry(void **entry, void *user)
+{
+	isl_map **map = (isl_map **)entry;
+
+	*map = isl_map_lexmin(*map);
+
+	return *map ? isl_stat_ok : isl_stat_error;
+}
+
+__isl_give isl_union_map *isl_union_map_lexmin(
+	__isl_take isl_union_map *umap)
+{
+	return un_op(umap, &lexmin_entry);
+}
+
+__isl_give isl_union_set *isl_union_set_lexmin(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_lexmin(uset);
+}
+
+static isl_stat lexmax_entry(void **entry, void *user)
+{
+	isl_map **map = (isl_map **)entry;
+
+	*map = isl_map_lexmax(*map);
+
+	return *map ? isl_stat_ok : isl_stat_error;
+}
+
+__isl_give isl_union_map *isl_union_map_lexmax(
+	__isl_take isl_union_map *umap)
+{
+	return un_op(umap, &lexmax_entry);
+}
+
+__isl_give isl_union_set *isl_union_set_lexmax(
+	__isl_take isl_union_set *uset)
+{
+	return isl_union_map_lexmax(uset);
+}
+
+static isl_stat universe_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	map = isl_map_universe(isl_map_get_space(map));
+	*res = isl_union_map_add_map(*res, map);
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_universe(__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &universe_entry);
+}
+
+__isl_give isl_union_set *isl_union_set_universe(__isl_take isl_union_set *uset)
+{
+	return isl_union_map_universe(uset);
+}
+
+static isl_stat reverse_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	*res = isl_union_map_add_map(*res, isl_map_reverse(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_reverse(__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &reverse_entry);
+}
+
+static isl_stat params_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_set_add_set(*res, isl_map_params(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+/* Compute the parameter domain of the given union map.
+ */
+__isl_give isl_set *isl_union_map_params(__isl_take isl_union_map *umap)
+{
+	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(cond_un_op(umap, &params_entry));
+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);
+}
+
+static isl_stat domain_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_set_add_set(*res, isl_map_domain(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &domain_entry);
+}
+
+static isl_stat range_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_set_add_set(*res, isl_map_range(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &range_entry);
+}
+
+static isl_stat domain_map_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_map_add_map(*res,
+					isl_map_domain_map(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_domain_map(
+	__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &domain_map_entry);
+}
+
+/* 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;
+}
+
+static isl_stat range_map_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_map_add_map(*res,
+					isl_map_range_map(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_range_map(
+	__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &range_map_entry);
+}
+
+/* Check if "set" is of the form A[B -> C].
+ * If so, add A[B -> C] -> B to "res".
+ */
+static isl_stat wrapped_domain_map_entry(void **entry, void *user)
+{
+	isl_set *set = *entry;
+	isl_union_set **res = user;
+	int wrapping;
+
+	wrapping = isl_set_is_wrapping(set);
+	if (wrapping < 0)
+		return isl_stat_error;
+	if (!wrapping)
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res,
+				isl_set_wrapped_domain_map(isl_set_copy(set)));
+
+	return isl_stat_ok;
+}
+
+/* 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)
+{
+	return cond_un_op(uset, &wrapped_domain_map_entry);
+}
+
+static isl_stat deltas_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_set **res = user;
+
+	if (!isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					map->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	*res = isl_union_set_add_set(*res, isl_map_deltas(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_map_deltas(__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &deltas_entry);
+}
+
+static isl_stat deltas_map_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_space_tuple_is_equal(map->dim, isl_dim_in,
+					map->dim, isl_dim_out))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res,
+				     isl_map_deltas_map(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_deltas_map(
+	__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &deltas_map_entry);
+}
+
+static isl_stat identity_entry(void **entry, void *user)
+{
+	isl_set *set = *entry;
+	isl_union_map **res = user;
+
+	*res = isl_union_map_add_map(*res, isl_set_identity(isl_set_copy(set)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset)
+{
+	return cond_un_op(uset, &identity_entry);
+}
+
+/* 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;
+}
+
+/* If "map" is of the form [A -> B] -> C, then add A -> C to "res".
+ */
+static isl_stat domain_factor_domain_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_domain_is_wrapping(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res,
+			    isl_map_domain_factor_domain(isl_map_copy(map)));
+
+	return *res ? isl_stat_ok : isl_stat_error;
+}
+
+/* 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)
+{
+	return cond_un_op(umap, &domain_factor_domain_entry);
+}
+
+/* If "map" is of the form [A -> B] -> C, then add B -> C to "res".
+ */
+static isl_stat domain_factor_range_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_domain_is_wrapping(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res,
+				isl_map_domain_factor_range(isl_map_copy(map)));
+
+	return *res ? isl_stat_ok : isl_stat_error;
+}
+
+/* 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)
+{
+	return cond_un_op(umap, &domain_factor_range_entry);
+}
+
+/* If "map" is of the form A -> [B -> C], then add A -> C to "res".
+ */
+static isl_stat range_factor_range_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_range_is_wrapping(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res,
+				isl_map_range_factor_range(isl_map_copy(map)));
+
+	return *res ? isl_stat_ok : isl_stat_error;
+}
+
+/* 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)
+{
+	return cond_un_op(umap, &range_factor_range_entry);
+}
+
+/* If "map" is of the form [A -> B] -> [C -> D], then add A -> C to "res".
+ */
+static isl_stat factor_domain_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_domain_is_wrapping(map) || !isl_map_range_is_wrapping(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res,
+				isl_map_factor_domain(isl_map_copy(map)));
+
+	return *res ? isl_stat_ok : isl_stat_error;
+}
+
+/* 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)
+{
+	return cond_un_op(umap, &factor_domain_entry);
+}
+
+/* If "map" is of the form [A -> B] -> [C -> D], then add B -> D to "res".
+ */
+static isl_stat factor_range_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_domain_is_wrapping(map) || !isl_map_range_is_wrapping(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res,
+				isl_map_factor_range(isl_map_copy(map)));
+
+	return *res ? isl_stat_ok : isl_stat_error;
+}
+
+/* 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)
+{
+	return cond_un_op(umap, &factor_range_entry);
+}
+
+static isl_stat unwrap_entry(void **entry, void *user)
+{
+	isl_set *set = *entry;
+	isl_union_set **res = user;
+
+	if (!isl_set_is_wrapping(set))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res, isl_set_unwrap(isl_set_copy(set)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_set_unwrap(__isl_take isl_union_set *uset)
+{
+	return cond_un_op(uset, &unwrap_entry);
+}
+
+static isl_stat wrap_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_set_add_set(*res, isl_map_wrap(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_map_wrap(__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &wrap_entry);
+}
+
+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_dim, 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_dim, 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 (isl_basic_set *)isl_union_map_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;
+}
+
+/* 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);
+}
+
+static isl_stat zip_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_can_zip(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res, isl_map_zip(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_map *isl_union_map_zip(__isl_take isl_union_map *umap)
+{
+	return cond_un_op(umap, &zip_entry);
+}
+
+static isl_stat uncurry_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_can_uncurry(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res, isl_map_uncurry(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+/* 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)
+{
+	return cond_un_op(umap, &uncurry_entry);
+}
+
+static isl_stat curry_entry(void **entry, void *user)
+{
+	isl_map *map = *entry;
+	isl_union_map **res = user;
+
+	if (!isl_map_can_curry(map))
+		return isl_stat_ok;
+
+	*res = isl_union_map_add_map(*res, isl_map_curry(isl_map_copy(map)));
+
+	return isl_stat_ok;
+}
+
+/* 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)
+{
+	return cond_un_op(umap, &curry_entry);
+}
+
+static isl_stat lift_entry(void **entry, void *user)
+{
+	isl_set *set = *entry;
+	isl_union_set **res = user;
+
+	*res = isl_union_set_add_set(*res, isl_set_lift(isl_set_copy(set)));
+
+	return isl_stat_ok;
+}
+
+__isl_give isl_union_set *isl_union_set_lift(__isl_take isl_union_set *uset)
+{
+	return cond_un_op(uset, &lift_entry);
+}
+
+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 space of *entry.
+ */
+static isl_stat reset_user(void **entry, void *user)
+{
+	isl_map **map = (isl_map **)entry;
+
+	*map = isl_map_reset_user(*map);
+
+	return *map ? isl_stat_ok : isl_stat_error;
+}
+
+/* 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);
+	umap = un_op(umap, &reset_user);
+
+	return umap;
+}
+
+/* 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);
+}
+
+/* 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;
+}
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..5cd2783
--- /dev/null
+++ b/final/lib/External/isl/isl_union_map_private.h
@@ -0,0 +1,14 @@
+#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_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_templ.c b/final/lib/External/isl/isl_union_templ.c
new file mode 100644
index 0000000..f0fb6b3
--- /dev/null
+++ b/final/lib/External/isl/isl_union_templ.c
@@ -0,0 +1,1371 @@
+/*
+ * 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
+ */
+
+#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)
+
+struct UNION {
+	int ref;
+#ifdef HAS_TYPE
+	enum isl_fold type;
+#endif
+	isl_space *space;
+
+	struct isl_hash_table	table;
+};
+
+__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;
+}
+
+/* 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;
+
+	return data->fn(FN(PART,copy)(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 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);
+}
+
+/* This function is not currently used by isl_aff.c.
+ */
+static int FN(UNION,has_domain_space)(const void *entry, const void *val)
+	__attribute__ ((unused));
+
+/* 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);
+}
+
+/* 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);
+}
+
+/* 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)
+{
+	uint32_t hash;
+	struct isl_hash_table_entry *entry;
+
+	if (!u || !space)
+		goto error;
+	if (!isl_space_match(u->space, isl_dim_param, space, isl_dim_param)) {
+		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;
+	}
+
+	hash = isl_space_get_hash(space);
+	entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
+				    &FN(UNION,has_space), space, 0);
+	if (!entry)
+#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 on the same space as "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;
+	uint32_t hash;
+	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;
+
+	hash = isl_space_get_hash(part->dim);
+	entry = isl_hash_table_find(u->space->ctx, &u->table, hash,
+				    &FN(UNION,has_same_domain_space),
+				    part->dim, 1);
+	if (!entry)
+		goto error;
+
+	if (!entry->data)
+		entry->data = part;
+	else {
+		PART *entry_part = entry->data;
+		if (disjoint)
+			isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
+				"additional part should live on separate "
+				"space", goto error);
+		if (!isl_space_tuple_is_equal(entry_part->dim, isl_dim_out,
+						part->dim, isl_dim_out))
+			isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
+				"union expression can only contain a single "
+				"expression over a given domain", 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) {
+			FN(PART,free)(entry->data);
+			isl_hash_table_remove(u->space->ctx, &u->table, 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);
+}
+
+static isl_stat FN(UNION,add_part)(__isl_take PART *part, void *user)
+{
+	UNION **u = (UNION **)user;
+
+	*u = FN(FN(UNION,add),PARTS)(*u, part);
+
+	return isl_stat_ok;
+}
+
+__isl_give UNION *FN(UNION,dup)(__isl_keep UNION *u)
+{
+	UNION *dup;
+
+	if (!u)
+		return NULL;
+
+#ifdef HAS_TYPE
+	dup = FN(UNION,ZERO)(isl_space_copy(u->space), u->type);
+#else
+	dup = FN(UNION,ZERO)(isl_space_copy(u->space));
+#endif
+	if (FN(FN(UNION,foreach),PARTS)(u, &FN(UNION,add_part), &dup) < 0)
+		goto error;
+	return dup;
+error:
+	FN(UNION,free)(dup);
+	return 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);
+}
+
+static isl_stat FN(UNION,free_u_entry)(void **entry, void *user)
+{
+	PART *part = *entry;
+	FN(PART,free)(part);
+	return isl_stat_ok;
+}
+
+__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;
+}
+
+S(UNION,align) {
+	isl_reordering *exp;
+	UNION *res;
+};
+
+static isl_stat FN(UNION,align_entry)(__isl_take PART *part, void *user)
+{
+	isl_reordering *exp;
+	S(UNION,align) *data = user;
+
+	exp = isl_reordering_extend_space(isl_reordering_copy(data->exp),
+				    FN(PART,get_domain_space)(part));
+
+	data->res = FN(FN(UNION,add),PARTS)(data->res,
+					    FN(PART,realign_domain)(part, exp));
+
+	return isl_stat_ok;
+}
+
+/* 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)
+{
+	S(UNION,align) data = { NULL, NULL };
+
+	if (!u || !r)
+		goto error;
+
+#ifdef HAS_TYPE
+	data.res = FN(UNION,alloc)(isl_space_copy(r->dim), u->type, u->table.n);
+#else
+	data.res = FN(UNION,alloc)(isl_space_copy(r->dim), u->table.n);
+#endif
+	data.exp = r;
+	if (FN(FN(UNION,foreach),PARTS)(u, &FN(UNION,align_entry), &data) < 0)
+		data.res = FN(UNION,free)(data.res);
+
+	isl_reordering_free(data.exp);
+	FN(UNION,free)(u);
+	return data.res;
+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_reordering *r;
+
+	if (!u || !model)
+		goto error;
+
+	if (isl_space_match(u->space, isl_dim_param, model, isl_dim_param)) {
+		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 *entry.
+ * If so, call data->fn on the two elements and add the result to
+ * data->res.
+ */
+static isl_stat FN(UNION,match_bin_entry)(void **entry, void *user)
+{
+	S(UNION,match_bin_data) *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	isl_space *space;
+	PART *part = *entry;
+	PART *part2;
+
+	space = FN(PART,get_space)(part);
+	hash = isl_space_get_hash(space);
+	entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table,
+				     hash, &FN(UNION,has_same_domain_space),
+				     space, 0);
+	isl_space_free(space);
+	if (!entry2)
+		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",
+			return isl_stat_error);
+
+	part = FN(PART, copy)(part);
+	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;
+}
+
+/* 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;
+#ifdef HAS_TYPE
+	data.res = FN(UNION,alloc)(isl_space_copy(u1->space), u1->type,
+				    u1->table.n);
+#else
+	data.res = FN(UNION,alloc)(isl_space_copy(u1->space), u1->table.n);
+#endif
+	if (isl_hash_table_foreach(u1->space->ctx, &u1->table,
+				    &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;
+	UNION *res;
+	__isl_give PW *(*fn)(__isl_take PW*, __isl_take isl_set*);
+};
+
+static isl_stat FN(UNION,any_set_entry)(void **entry, void *user)
+{
+	S(UNION,any_set_data) *data = user;
+	PW *pw = *entry;
+
+	pw = FN(PW,copy)(pw);
+	pw = data->fn(pw, isl_set_copy(data->set));
+
+	data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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, 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;
+#ifdef HAS_TYPE
+	data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
+					u->table.n);
+#else
+	data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
+#endif
+	if (isl_hash_table_foreach(u->space->ctx, &u->table,
+				   &FN(UNION,any_set_entry), &data) < 0)
+		goto error;
+
+	FN(UNION,free)(u);
+	isl_set_free(set);
+	return data.res;
+error:
+	FN(UNION,free)(u);
+	isl_set_free(set);
+	FN(UNION,free)(data.res);
+	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 *entry, 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)(void **entry, void *user)
+{
+	S(UNION,match_domain_data) *data = user;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	PW *pw = *entry;
+	isl_space *space;
+
+	space = FN(PW,get_domain_space)(pw);
+	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)
+		return isl_stat_ok;
+
+	pw = FN(PW,copy)(pw);
+	pw = data->fn(pw, isl_set_copy(entry2->data));
+
+	data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
+	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;
+#ifdef HAS_TYPE
+	data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
+					u->table.n);
+#else
+	data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
+#endif
+	if (isl_hash_table_foreach(u->space->ctx, &u->table,
+				   &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));
+}
+
+/* Internal data structure for isl_union_*_subtract_domain.
+ * uset is the set that needs to be removed from the domain.
+ * res collects the results.
+ */
+S(UNION,subtract_domain_data) {
+	isl_union_set *uset;
+	UNION *res;
+};
+
+/* 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 "pw" and add the result to data->res.
+ */
+static isl_stat FN(UNION,subtract_domain_entry)(__isl_take PW *pw, void *user)
+{
+	S(UNION,subtract_domain_data) *data = user;
+	isl_space *space;
+	isl_set *set;
+
+	space = FN(PW,get_domain_space)(pw);
+	set = isl_union_set_extract_set(data->uset, space);
+	pw = FN(PW,subtract_domain)(pw, set);
+	data->res = FN(FN(UNION,add),PARTS)(data->res, pw);
+
+	return isl_stat_ok;
+}
+
+/* Subtract "uset' from the domain of "u".
+ */
+__isl_give UNION *FN(UNION,subtract_domain)(__isl_take UNION *u,
+	__isl_take isl_union_set *uset)
+{
+	S(UNION,subtract_domain_data) data;
+
+	if (!u || !uset)
+		goto error;
+
+	data.uset = uset;
+#ifdef HAS_TYPE
+	data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->type,
+					u->table.n);
+#else
+	data.res = FN(UNION,alloc)(isl_space_copy(u->space), u->table.n);
+#endif
+	if (FN(FN(UNION,foreach),PARTS)(u,
+				&FN(UNION,subtract_domain_entry), &data) < 0)
+		data.res = FN(UNION,free)(data.res);
+
+	FN(UNION,free)(u);
+	isl_union_set_free(uset);
+	return data.res;
+error:
+	FN(UNION,free)(u);
+	isl_union_set_free(uset);
+	return NULL;
+}
+
+__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));
+}
+
+#ifndef NO_EVAL
+__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;
+}
+#endif
+
+static isl_stat FN(UNION,coalesce_entry)(void **entry, void *user)
+{
+	PW **pw = (PW **)entry;
+
+	*pw = FN(PW,coalesce)(*pw);
+	if (!*pw)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+__isl_give UNION *FN(UNION,coalesce)(__isl_take UNION *u)
+{
+	if (!u)
+		return NULL;
+
+	if (isl_hash_table_foreach(u->space->ctx, &u->table,
+				   &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;
+}
+
+static isl_stat FN(UNION,mul_isl_int_entry)(void **entry, void *user)
+{
+	PW **pw = (PW **)entry;
+	isl_int *v = user;
+
+	*pw = FN(PW,mul_isl_int)(*pw, *v);
+	if (!*pw)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+__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,cow)(u);
+	if (!u)
+		return NULL;
+
+#ifdef HAS_TYPE
+	if (isl_int_is_neg(v))
+		u->type = isl_fold_type_negate(u->type);
+#endif
+	if (isl_hash_table_foreach(u->space->ctx, &u->table,
+				    &FN(UNION,mul_isl_int_entry), &v) < 0)
+		goto error;
+
+	return u;
+error:
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+/* Multiply *entry by the isl_val "user".
+ *
+ * Return 0 on success and -1 on error.
+ */
+static isl_stat FN(UNION,scale_val_entry)(void **entry, void *user)
+{
+	PW **pw = (PW **)entry;
+	isl_val *v = user;
+
+	*pw = FN(PW,scale_val)(*pw, isl_val_copy(v));
+	if (!*pw)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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,cow)(u);
+	if (!u)
+		return NULL;
+
+#ifdef HAS_TYPE
+	if (isl_val_is_neg(v))
+		u->type = isl_fold_type_negate(u->type);
+#endif
+	if (isl_hash_table_foreach(u->space->ctx, &u->table,
+				    &FN(UNION,scale_val_entry), v) < 0)
+		goto error;
+
+	isl_val_free(v);
+	return u;
+error:
+	isl_val_free(v);
+	FN(UNION,free)(u);
+	return NULL;
+}
+
+/* Divide *entry by the isl_val "user".
+ *
+ * Return 0 on success and -1 on error.
+ */
+static isl_stat FN(UNION,scale_down_val_entry)(void **entry, void *user)
+{
+	PW **pw = (PW **)entry;
+	isl_val *v = user;
+
+	*pw = FN(PW,scale_down_val)(*pw, isl_val_copy(v));
+	if (!*pw)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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,cow)(u);
+	if (!u)
+		return NULL;
+
+#ifdef HAS_TYPE
+	if (isl_val_is_neg(v))
+		u->type = isl_fold_type_negate(u->type);
+#endif
+	if (isl_hash_table_foreach(FN(UNION,get_ctx)(u), &u->table,
+				    &FN(UNION,scale_down_val_entry), v) < 0)
+		goto error;
+
+	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;
+	uint32_t hash;
+	struct isl_hash_table_entry *entry2;
+	PW *pw = *entry;
+
+	hash = isl_space_get_hash(pw->dim);
+	entry2 = isl_hash_table_find(data->u2->space->ctx, &data->u2->table,
+				     hash, &FN(UNION,has_same_domain_space),
+				     pw->dim, 0);
+	if (!entry2) {
+		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 };
+
+	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;
+
+	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 (isl_hash_table_foreach(u1->space->ctx, &u1->table,
+			       &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;
+}
+
+#ifndef NO_NEG
+/* Replace *entry by its opposite.
+ *
+ * Return 0 on success and -1 on error.
+ */
+static isl_stat FN(UNION,neg_entry)(void **entry, void *user)
+{
+	PW **pw = (PW **) entry;
+
+	*pw = FN(PW,neg)(*pw);
+
+	return *pw ? isl_stat_ok : isl_stat_error;
+}
+
+/* Return the opposite of "u".
+ */
+__isl_give UNION *FN(UNION,neg)(__isl_take UNION *u)
+{
+	u = FN(UNION,cow)(u);
+	if (!u)
+		return NULL;
+
+	if (isl_hash_table_foreach(u->space->ctx, &u->table,
+				   &FN(UNION,neg_entry), NULL) < 0)
+		return FN(UNION,free)(u);
+
+	return u;
+}
+#endif
+
+/* Internal data structure for isl_union_*_drop_dims.
+ * type, first and n are passed to isl_*_drop_dims.
+ * res collects the results.
+ */
+S(UNION,drop_dims_data) {
+	enum isl_dim_type type;
+	unsigned first;
+	unsigned n;
+
+	UNION *res;
+};
+
+/* Drop the parameters specified by "data" from "part" and
+ * add the results to data->res.
+ */
+static isl_stat FN(UNION,drop_dims_entry)(__isl_take PART *part, void *user)
+{
+	S(UNION,drop_dims_data) *data = user;
+
+	part = FN(PART,drop_dims)(part, data->type, data->first, data->n);
+	data->res = FN(FN(UNION,add),PARTS)(data->res, part);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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);
+#ifdef HAS_TYPE
+	data.res = FN(UNION,alloc)(space, u->type, u->table.n);
+#else
+	data.res = FN(UNION,alloc)(space, u->table.n);
+#endif
+	if (FN(FN(UNION,foreach),PARTS)(u,
+					&FN(UNION,drop_dims_entry), &data) < 0)
+		data.res = FN(UNION,free)(data.res);
+
+	FN(UNION,free)(u);
+
+	return data.res;
+}
+
+/* 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.
+ * res collects the results.
+ */
+S(UNION,set_dim_name_data) {
+	unsigned pos;
+	const char *s;
+
+	UNION *res;
+};
+
+/* Change the name of the parameter at position data->pos of "part" to data->s
+ * and add the result to data->res.
+ */
+static isl_stat FN(UNION,set_dim_name_entry)(__isl_take PART *part, void *user)
+{
+	S(UNION,set_dim_name_data) *data = user;
+
+	part = FN(PART,set_dim_name)(part, isl_dim_param, data->pos, data->s);
+	data->res = FN(FN(UNION,add),PARTS)(data->res, part);
+	if (!data->res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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);
+#ifdef HAS_TYPE
+	data.res = FN(UNION,alloc)(space, u->type, u->table.n);
+#else
+	data.res = FN(UNION,alloc)(space, u->table.n);
+#endif
+
+	if (FN(FN(UNION,foreach),PARTS)(u,
+				    &FN(UNION,set_dim_name_entry), &data) < 0)
+		data.res = FN(UNION,free)(data.res);
+
+	FN(UNION,free)(u);
+
+	return data.res;
+}
+
+/* Reset the user pointer on all identifiers of parameters and tuples
+ * of the space of "part" and add the result to *res.
+ */
+static isl_stat FN(UNION,reset_user_entry)(__isl_take PART *part, void *user)
+{
+	UNION **res = user;
+
+	part = FN(PART,reset_user)(part);
+	*res = FN(FN(UNION,add),PARTS)(*res, part);
+	if (!*res)
+		return isl_stat_error;
+
+	return isl_stat_ok;
+}
+
+/* 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;
+	UNION *res;
+
+	if (!u)
+		return NULL;
+
+	space = FN(UNION,get_space)(u);
+	space = isl_space_reset_user(space);
+#ifdef HAS_TYPE
+	res = FN(UNION,alloc)(space, u->type, u->table.n);
+#else
+	res = FN(UNION,alloc)(space, u->table.n);
+#endif
+	if (FN(FN(UNION,foreach),PARTS)(u,
+					&FN(UNION,reset_user_entry), &res) < 0)
+		res = FN(UNION,free)(res);
+
+	FN(UNION,free)(u);
+
+	return res;
+}
diff --git a/final/lib/External/isl/isl_val.c b/final/lib/External/isl/isl_val.c
new file mode 100644
index 0000000..b630761
--- /dev/null
+++ b/final/lib/External/isl/isl_val.c
@@ -0,0 +1,1648 @@
+/*
+ * 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;
+}
+
+/* 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".
+ *
+ * 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;
+
+	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 1, except if "v" or "space" are NULL.
+ */
+int isl_val_matching_params(__isl_keep isl_val *v, __isl_keep isl_space *space)
+{
+	if (!v || !space)
+		return -1;
+	return 1;
+}
+
+/* Check that the domain space of "v" matches "space".
+ *
+ * Return 0 on success and -1 on error.
+ *
+ * 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.
+ */
+int isl_val_check_match_domain_space(__isl_keep isl_val *v,
+	__isl_keep isl_space *space)
+{
+	if (!v || !space)
+		return -1;
+	return 0;
+}
+
+#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..ec1076d
--- /dev/null
+++ b/final/lib/External/isl/isl_val_private.h
@@ -0,0 +1,72 @@
+#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_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);
+
+int isl_val_matching_params(__isl_keep isl_val *v, __isl_keep isl_space *space);
+int 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..008f899
--- /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..0ed6f7d
--- /dev/null
+++ b/final/lib/External/isl/isl_vec.c
@@ -0,0 +1,579 @@
+/*
+ * 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;
+}
+
+struct 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);
+	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;
+}
+
+__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]);
+}
+
+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.
+ */
+struct isl_vec *isl_vec_ceil(struct 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..c3fcd92
--- /dev/null
+++ b/final/lib/External/isl/isl_vec_private.h
@@ -0,0 +1,24 @@
+#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;
+};
+
+__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);
+
+#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..6e74a4f
--- /dev/null
+++ b/final/lib/External/isl/isl_vertices.c
@@ -0,0 +1,1570 @@
+/*
+ * 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;
+}
+
+void isl_vertices_free(__isl_take isl_vertices *vertices)
+{
+	int i;
+
+	if (!vertices)
+		return;
+
+	if (--vertices->ref > 0)
+		return;
+
+	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);
+}
+
+struct isl_vertex_list {
+	struct isl_vertex v;
+	struct isl_vertex_list *next;
+};
+
+static void 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);
+	}
+}
+
+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".
+ */
+static int 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 -1;
+
+	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;
+
+	v->next = *list;
+	*list = v;
+
+	return 0;
+error:
+	free_vertex_list(v);
+	return -1;
+}
+
+/* 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 indepedent
+ * 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) {
+				if (add_vertex(&list, bset, tab) < 0)
+					goto error;
+				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 int bset_covers_tab(__isl_keep isl_basic_set *bset, struct isl_tab *tab)
+{
+	int i;
+
+	if (!bset || !tab)
+		return -1;
+
+	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 -1;
+		case isl_ineq_redundant:	continue;
+		default:			return 0;
+		}
+	}
+
+	return 1;
+}
+
+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.
+ */
+static int can_intersect(struct isl_tab *tab, __isl_keep isl_basic_set *bset)
+{
+	int i;
+	struct isl_tab_undo *snap;
+
+	if (isl_tab_extend_cons(tab, bset->n_ineq) < 0)
+		return -1;
+
+	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 -1;
+	}
+
+	if (isl_tab_detect_implicit_equalities(tab) < 0)
+		return -1;
+	if (tab->n_dead) {
+		if (isl_tab_rollback(tab, snap) < 0)
+			return -1;
+		return 0;
+	}
+
+	return 1;
+}
+
+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 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;
+}
+
+__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);
+}
+
+/* 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_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.
+ */
+int isl_vertices_foreach_disjoint_cell(__isl_keep isl_vertices *vertices,
+	int (*fn)(__isl_take isl_cell *cell, void *user), void *user)
+{
+	int i, j;
+	isl_vec *vec;
+	isl_int v;
+	isl_cell *cell;
+
+	if (!vertices)
+		return -1;
+
+	if (vertices->n_chambers == 0)
+		return 0;
+
+	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 -1;
+		return fn(cell, user);
+	}
+
+	vec = isl_basic_set_interior_point(vertices->c[0].dom);
+	if (!vec)
+		return -1;
+
+	isl_int_init(v);
+
+	for (i = 0; i < vertices->n_chambers; ++i) {
+		int r;
+		isl_basic_set *dom = isl_basic_set_copy(vertices->c[i].dom);
+		dom = isl_basic_set_cow(dom);
+		if (!dom)
+			goto error;
+		for (j = 0; i && j < dom->n_ineq; ++j) {
+			isl_seq_inner_product(vec->el, dom->ineq[j], vec->size,
+						&v);
+			if (!isl_int_is_neg(v))
+				continue;
+			isl_int_sub_ui(dom->ineq[j][0], dom->ineq[j][0], 1);
+		}
+		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_int_clear(v);
+	isl_vec_free(vec);
+
+	return 0;
+error:
+	isl_int_clear(v);
+	isl_vec_free(vec);
+	return -1;
+}
+
+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 int call_on_simplex(__isl_keep isl_cell *cell,
+	int *simplex_ids, int n_simplex, int *other_ids, int n_other,
+	int (*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 -1;
+	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 -1;
+}
+
+/* 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 int triangulate(__isl_keep isl_cell *cell, __isl_keep isl_vec *v,
+	int *simplex_ids, int n_simplex, int *other_ids, int n_other,
+	int (*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);
+	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 0;
+error:
+	free(ids);
+	return -1;
+}
+
+/* Triangulate the given cell and call "fn" on each of the resulting
+ * simplices.
+ */
+int isl_cell_foreach_simplex(__isl_take isl_cell *cell,
+	int (*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 -1;
+
+	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 -1;
+}
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..7c707fd
--- /dev/null
+++ b/final/lib/External/isl/isl_vertices_private.h
@@ -0,0 +1,64 @@
+#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.
+ */
+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;
+};
+
+int isl_vertices_foreach_disjoint_cell(__isl_keep isl_vertices *vertices,
+	int (*fn)(__isl_take isl_cell *cell, void *user), void *user);
+int isl_cell_foreach_simplex(__isl_take isl_cell *cell,
+	int (*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
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..c29db36
--- /dev/null
+++ b/final/lib/External/isl/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.10ubuntu1
+#         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.10ubuntu1"
+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/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_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..d7c043f
--- /dev/null
+++ b/final/lib/External/isl/m4/libtool.m4
@@ -0,0 +1,7997 @@
+# 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*|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
+	    ;;
+	  powerpc64le-*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*)
+	    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-*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*)
+	    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/isl/m4/ltoptions.m4 b/final/lib/External/isl/m4/ltoptions.m4
new file mode 100644
index 0000000..5d9acd8
--- /dev/null
+++ b/final/lib/External/isl/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/isl/m4/ltsugar.m4 b/final/lib/External/isl/m4/ltsugar.m4
new file mode 100644
index 0000000..9000a05
--- /dev/null
+++ b/final/lib/External/isl/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/isl/m4/ltversion.m4 b/final/lib/External/isl/m4/ltversion.m4
new file mode 100644
index 0000000..07a8602
--- /dev/null
+++ b/final/lib/External/isl/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/isl/m4/lt~obsolete.m4 b/final/lib/External/isl/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c573da9
--- /dev/null
+++ b/final/lib/External/isl/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/isl/missing b/final/lib/External/isl/missing
new file mode 100755
index 0000000..db98974
--- /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-2013 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..72b2bef
--- /dev/null
+++ b/final/lib/External/isl/pip.c
@@ -0,0 +1,382 @@
+/*
+ * 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;
+}
+
+isl_basic_set *plug_in_parameters(isl_basic_set *bset, struct isl_vec *params)
+{
+	int i;
+
+	for (i = 0; i < params->size - 1; ++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, params->size - 1);
+
+	isl_vec_free(params);
+
+	return bset;
+}
+
+isl_set *set_plug_in_parameters(isl_set *set, struct isl_vec *params)
+{
+	int i;
+
+	for (i = 0; i < params->size - 1; ++i)
+		set = isl_set_fix(set, isl_dim_param, i, params->el[1 + i]);
+
+	set = isl_set_remove_dims(set, isl_dim_param, 0, params->size - 1);
+
+	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.
+ */
+struct isl_vec *opt_at(struct isl_basic_set *bset,
+	struct isl_vec *params, int max)
+{
+	unsigned dim;
+	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);
+
+	if (isl_basic_set_plain_is_empty(bset)) {
+		opt = isl_vec_alloc(bset->ctx, 0);
+		isl_basic_set_free(bset);
+		return opt;
+	}
+
+	opt = isl_vec_alloc(bset->ctx, 1 + dim);
+	assert(opt);
+
+	obj = isl_vec_alloc(bset->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(bset->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..28ad1ef
--- /dev/null
+++ b/final/lib/External/isl/pip_test.sh.in
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+EXEEXT=@EXEEXT@
+
+PIP_TESTS="\
+	boulet.pip \
+	brisebarre.pip \
+	cg1.pip \
+	esced.pip \
+	ex2.pip \
+	ex.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..4d724e7
--- /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.c>
+#undef BASE
+#define BASE ast_node
+#include <print_templ.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..f147fdc
--- /dev/null
+++ b/final/lib/External/isl/print_templ.c
@@ -0,0 +1,33 @@
+#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 = 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/test-driver b/final/lib/External/isl/test-driver
new file mode 100755
index 0000000..d306056
--- /dev/null
+++ b/final/lib/External/isl/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/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..73731c0
--- /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 >= 1)
+    b(c0 - 1);
+  if (c0 <= 9)
+    a(c0);
+}
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..754b3d0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic.in
@@ -0,0 +1,3 @@
+{ a[i] -> [i] : 0 <= i < 10; b[i] -> [i+1] : 0 <= i < 10 }
+{ : }
+{ [i] -> 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..ca46e0e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic.st
@@ -0,0 +1,4 @@
+domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+  options: "{ atomic[x] }"
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..e63e092
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/atomic3.c
@@ -0,0 +1,8 @@
+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/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..56659a0
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/4-param.c
@@ -0,0 +1,14 @@
+{
+  for (int c0 = m; c0 <= min(n, p - 1); c0 += 1)
+    S1(c0);
+  for (int c0 = p; c0 <= min(m - 1, q); c0 += 1)
+    S2(c0);
+  for (int c0 = max(m, p); c0 <= min(n, q); c0 += 1) {
+    S1(c0);
+    S2(c0);
+  }
+  for (int c0 = max(max(m, p), q + 1); c0 <= n; c0 += 1)
+    S1(c0);
+  for (int c0 = max(max(m, n + 1), p); c0 <= q; c0 += 1)
+    S2(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..8e87cba
--- /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 >= 6) {
+      S2(c0, -c0 + 9);
+    } else {
+      if (c0 == 4)
+        for (int c1 = 3; c1 <= 4; c1 += 1)
+          S1(4, c1);
+      S1(c0, -c0 + 9);
+      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..d51254c
--- /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);
+    S4(0, 1, 2, 2, 1, 1, 2, 2);
+    S3(0, 1, 1, 2, 1, 1, 1, 2);
+    S2(0, 1, 1, 1, 1, 1, 2, 1);
+    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);
+      S4(c0, 1, c0 + 2, 2, c0 + 1, 1, c0 + 2, 2);
+      S2(c0, 1, c0 + 1, 1, c0 + 1, 1, c0 + 2, 1);
+      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);
+      S6(c0 - 1, c1 - 1, c0, c1, c0 - c1 + 2, c1 - 1, c0 - c1 + 2, c1);
+      S7(c0 - 1, c1 - 1, c0 + 1, c1, c0 - c1 + 2, c1 - 1, c0 - c1 + 3, c1);
+      S1(c0, c1, c0 - c1 + 2, c1);
+      S4(c0, c1, c0 + 2, c1 + 1, c0 - c1 + 2, c1, c0 - c1 + 3, c1 + 1);
+      S2(c0, c1, c0 + 1, c1, c0 - c1 + 2, c1, c0 - c1 + 3, c1);
+      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 (m >= c0 + 2) {
+      S7(c0 - 1, c0, c0 + 1, c0 + 1, 1, c0, 2, c0 + 1);
+      S6(c0 - 1, c0, c0, c0 + 1, 1, c0, 1, c0 + 1);
+      S1(c0, c0 + 1, 1, c0 + 1);
+      S4(c0, c0 + 1, c0 + 2, c0 + 2, 1, c0 + 1, 2, c0 + 2);
+      S2(c0, c0 + 1, c0 + 1, c0 + 1, 1, c0 + 1, 2, c0 + 1);
+      S3(c0, c0 + 1, c0 + 1, c0 + 2, 1, c0 + 1, 1, c0 + 2);
+    } else {
+      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);
+    }
+    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..939a804
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/dealII.c
@@ -0,0 +1,32 @@
+{
+  if (T_67 == 0 && T_66 <= -1) {
+    S1(0);
+  } else if (T_2 >= 1 && T_67 >= 1 && T_66 <= -1) {
+    S1(0);
+  } else if (T_2 >= 1 && T_67 >= 1 && T_66 >= 0) {
+    S1(0);
+    S2(0);
+  }
+  for (int c0 = 1; c0 <= min(min(T_2 - 1, T_67 - 1), T_66); c0 += 1) {
+    S1(c0);
+    S2(c0);
+  }
+  for (int c0 = max(1, T_66 + 1); c0 < min(T_2, T_67); c0 += 1)
+    S1(c0);
+  if (T_2 >= 1 && T_67 == 0 && T_66 >= 0) {
+    S1(0);
+    S2(0);
+  }
+  for (int c0 = max(1, T_67); c0 <= min(T_2 - 1, T_66); c0 += 1) {
+    S1(c0);
+    S2(c0);
+  }
+  for (int c0 = max(max(1, T_67), T_66 + 1); c0 < T_2; c0 += 1)
+    S1(c0);
+  if (T_2 == 0 && T_67 >= 1 && T_66 >= 0)
+    S2(0);
+  for (int c0 = max(1, T_2); c0 <= min(T_67 - 1, T_66); c0 += 1)
+    S2(c0);
+  if (T_2 == 0 && T_67 == 0 && T_66 >= 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..a1b1069
--- /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 = N + 1; c0 <= M; c0 += 1)
+    S1(c0);
+  for (int c0 = M + 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/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..2535b8b
--- /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 = c0 <= 2 ? 2 * c0 : 4; c1 <= (c0 >= 2 ? 2 * c0 : 4); 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..934aa82
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/faber.c
@@ -0,0 +1,156 @@
+{
+  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 (c0 <= 34 && c1 == 1) {
+        S3(c0, 1, 7);
+      } else if (c1 == 2) {
+        S3(c0, 2, 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);
+      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 = max(-8 * c1 + 25, c1 - (6 * c0 + 77) / 77 + 13); 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);
+    }
+    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 * ((-3 * c1 + 1) / 5) + 447 >= 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);
+    }
+    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 >= 79 && 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);
+    } else if (c0 <= 69 && c0 % 14 >= 9) {
+      if (c0 <= 41)
+        S7(c0, -3, 6);
+      S6(c0, c0 / 14 - 5, 8);
+      for (int c2 = -((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 = (c0 + 5) / 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);
+    }
+    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(min(-2 * c1 + 24, c1 - (6 * c0 + 91) / 77 + 15), (2 * c0 - 7 * c1 - 10) / 21 + 1); c2 += 1)
+        S9(c0, c1, c2);
+      if (c1 >= 1 && c1 <= 5 && 14 * c1 + 46 >= c0)
+        S9(c0, c1, c1 + 5);
+      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 && 7 * c1 + 21 * ((2 * c1 + 41) / 5) >= 2 * c0 + 12)
+        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 = c1 - (6 * c0 + 91) / 77 + 16; 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 = 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 + (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, 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..a36715c
--- /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)
+      S3(c1, -2 * N + c0);
+    for (int c1 = 1; c1 <= N; c1 += 1)
+      S2(c1, -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..0baf706
--- /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) {
+      S1(c0, c1);
+      S2(c0 + c1, c0);
+    }
+    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..50840a8
--- /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, ((t1 + 31) % 32) + g2);
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..0e470b4
--- /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..bcfd318
--- /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 = max(0, N + 1); c1 <= c0; c1 += 1)
+    S1(c0, c1);
+  for (int c1 = c0 + 1; c1 <= N; c1 += 1)
+    S2(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..e7774d5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/param-split.c
@@ -0,0 +1,6 @@
+for (int c0 = 0; c0 <= (M <= 0 ? 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..dc84444
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/pouchet.c
@@ -0,0 +1,11 @@
+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..0c17655
--- /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 - 2) % 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..3827707
--- /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 >= 1)
+    S2(c0, 1);
+  for (int c1 = max(1, -c0 + 1); c1 <= min(99, -c0 + 100); c1 += 1) {
+    S1(c0 + c1, c1);
+    S2(c0 + c1, c1 + 1);
+  }
+  if (c0 <= 0)
+    S1(c0 + 100, 100);
+}
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..4254711
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/reservoir-liu-zhuge1.c
@@ -0,0 +1,17 @@
+if (M >= 0 && N >= 0)
+  for (int c0 = -4; c0 <= 3 * M + N; c0 += 1) {
+    if (c0 >= 0 && 3 * M + 1 >= c0 && (c0 + 1) % 3 >= 1 && N + 1 >= (c0 + 1) % 3)
+      S2((c0 + 1) / 3, ((c0 + 1) % 3) - 1);
+    for (int c1 = max(-3 * M + c0 - 2, (c0 + 4) % 3); c1 <= min(min(N - 2, c0 - 2), -3 * M + c0 + 3); c1 += 3)
+      S2((c0 - c1 - 2) / 3, c1 + 2);
+    for (int c1 = max(-3 * M + c0 + 4, (c0 + 4) % 3); c1 < min(N - 1, c0 - 1); c1 += 3) {
+      S1((c0 - c1 + 4) / 3, c1);
+      S2((c0 - c1 - 2) / 3, c1 + 2);
+    }
+    if (3 * M + N >= c0 + 4 && c0 >= N + 1 && ((-N + c0) % 3) + N >= 2 && (-N + c0) % 3 >= 1)
+      S1((-N + c0 + 3) / 3 + 1, ((-N + c0) % 3) + N - 2);
+    for (int c1 = max(max(c0 + 1, -3 * M + c0 + 4), (c0 + 4) % 3); c1 <= min(N, c0 + 4); c1 += 3)
+      S1((c0 - c1 + 4) / 3, c1);
+    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..ddb1293
--- /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..84c8493
--- /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 (M >= c0) {
+      S1(c0, c0);
+      S2(c0, c0);
+    }
+    for (int c1 = c0 + 1; c1 <= M; c1 += 1)
+      S1(c0, c1);
+    if (c0 >= M + 1)
+      S2(c0, c0);
+  }
+}
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..6dc0a9b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/union.c
@@ -0,0 +1,6 @@
+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..7dfadcf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vasilache.c
@@ -0,0 +1,23 @@
+{
+  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..ab0854a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vivien.c
@@ -0,0 +1,87 @@
+{
+  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) {
+        S4(-c1, c0 + c1);
+        S6(-c1 + 2, c0 + c1 - 2);
+        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) {
+        S6(2, n);
+        S1(n + 1);
+      } 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) {
+            S6(2, c0 - 2);
+            S1(c0 - 1);
+          }
+          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) {
+        S4(-c1, c0 + c1);
+        S6(-c1 + 2, c0 + c1 - 2);
+        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..48be9ad
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/vivien2.c
@@ -0,0 +1,78 @@
+{
+  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) {
+        S4(-c1, c0 + c1);
+        S6(-c1 + 2, c0 + c1 - 2);
+        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) {
+          S6(2, n);
+          S1(n + 1);
+        }
+      } 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 <= 4) {
+          S1(c0 - 1);
+        } else if (n + 1 >= c0) {
+          S6(2, c0 - 2);
+          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) {
+        S4(-c1, c0 + c1);
+        S6(-c1 + 2, c0 + c1 - 2);
+        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..2c1bd93
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/cloog/walters.c
@@ -0,0 +1,15 @@
+{
+  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 % 3 == 0) {
+      S1(c0, c0 / 3, c0 / 3, c0 / 3);
+    } else if ((c0 - 1) % 3 == 0) {
+      S2(c0, (c0 - 1) / 3, (c0 + 2) / 3, (c0 - 1) / 3);
+    } else
+      S3(c0, (c0 - 2) / 3, (c0 + 1) / 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..b9a4aa1
--- /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 c1 = 1; c1 < c0; c1 += 1)
+      for (int c2 = c1 + 1; c2 <= n; c2 += 1)
+        S2(c1, c2, c0);
+    for (int c2 = c0 + 1; c2 <= n; c2 += 1)
+      S1(c0, c2);
+  }
+  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..a52909c
--- /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 = c0 + 1; c2 <= M; c2 += 1)
+      for (int c3 = 1; c3 < c0; c3 += 1)
+        S3(c0, c2, c3);
+    for (int c1 = 1; c1 < c0; c1 += 1)
+      S4(c1, c0);
+    for (int c2 = 1; c2 < c0; c2 += 1)
+      S1(c0, c2);
+  }
+}
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/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/dwt.c b/final/lib/External/isl/test_inputs/codegen/dwt.c
new file mode 100644
index 0000000..52adb5d
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/dwt.c
@@ -0,0 +1,8 @@
+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..58f7b7b
--- /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);
+  if (c0 == 5)
+    S2();
+  S1(c0);
+}
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..c539f6f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/filter.c
@@ -0,0 +1,8 @@
+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..24cfc63
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/hoist2.c
@@ -0,0 +1,3 @@
+for (int c0 = 1; c0 <= 5; c0 += 1)
+  for (int c1 = t1 - 64 * b + 64; c1 <= min(70, -((c0 - 1) % 2) - c0 + 73); c1 += 64)
+    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..fda8033
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate2.c
@@ -0,0 +1,13 @@
+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 if (c0 >= 7 || c0 <= 3) {
+    if (c0 >= 7) {
+      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..fe8c35f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate5.c
@@ -0,0 +1,23 @@
+{
+  for (int c0 = 0; c0 <= 9; c0 += 1)
+    for (int c1 = 0; c1 <= 1; c1 += 1) {
+      if (c0 % 2 == 0) {
+        A(c0 / 2, c1);
+      } else
+        B((c0 - 1) / 2, c1);
+    }
+  for (int c0 = 10; c0 <= 89; c0 += 1)
+    for (int c1 = 0; c1 <= 1; c1 += 1) {
+      if (c0 % 2 == 0) {
+        A(c0 / 2, c1);
+      } else
+        B((c0 - 1) / 2, c1);
+    }
+  for (int c0 = 90; c0 <= 199; c0 += 1)
+    for (int c1 = 0; c1 <= 1; c1 += 1) {
+      if (c0 % 2 == 0) {
+        A(c0 / 2, c1);
+      } else
+        B((c0 - 1) / 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..bc304cd
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/isolate7.c
@@ -0,0 +1,34 @@
+{
+  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);
+        }
+    }
+  if (n >= 32) {
+    for (int c1 = 0; c1 < n; c1 += 32) {
+      if (n >= c1 + 32) {
+        for (int c2 = 0; c2 < n % 32; c2 += 1)
+          for (int c3 = 0; c3 <= 31; c3 += 1)
+            S_1(-((n - 1) % 32) + n + c2 - 1, 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);
+        }
+    }
+  } else
+    for (int c2 = 0; c2 < n; c2 += 1) {
+      for (int c3 = 0; c3 < n; c3 += 1)
+        S_1(c2, c3);
+      S_2(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/lu.c b/final/lib/External/isl/test_inputs/codegen/lu.c
new file mode 100644
index 0000000..ecbb895
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/lu.c
@@ -0,0 +1,17 @@
+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..f4ec0e9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/code_gen-1.c
@@ -0,0 +1,15 @@
+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..a3e4458
--- /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) / 10 - 1);
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..555d644
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/guard1-0.c
@@ -0,0 +1,2 @@
+if ((n - m + 2) % 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..335c1b8
--- /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..bc8d337
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-0.c
@@ -0,0 +1,12 @@
+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..18ca370
--- /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) {
+    if (n >= 2)
+      s1(c0, c1);
+    s2(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..d1ce579
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-2.c
@@ -0,0 +1,11 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (n >= 2) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s1(c0, c1);
+      s2(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..570cbe5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/if_then-3.c
@@ -0,0 +1,12 @@
+if (n >= 2) {
+  for (int c0 = 1; c0 <= 100; c0 += 1) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s1(c0, c1);
+      s2(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..4f268a6
--- /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) {
+    s4(c0);
+    s0(c0);
+    s3(c0);
+    s2(c0);
+    s1(c0);
+  }
+  if (((-exprVar1 + 15) % 8) + c0 <= 15 || (c0 >= 9 && (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..05ac73f
--- /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(2 * c0 - 3, c0 / 2); 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..124d0f1
--- /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(2 * c0 - 3, c0 / 2); 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(c1 - (-c1 + 3) / 3, c0 - (-c2 + 3) / 3), c2 - (c2 + 2) / 3), c2 + floord(3 * c1 - c2 - 1, 6)); c3 <= min(3, c0 + c2 / 3 + 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..3910e4f
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-1.c
@@ -0,0 +1,13 @@
+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..8737f3c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-2.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) {
+      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..4d73f89
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-3.c
@@ -0,0 +1,15 @@
+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..7d2de29
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift1-4.c
@@ -0,0 +1,16 @@
+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..f914743
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-1.c
@@ -0,0 +1,16 @@
+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..8b6dbaf
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-2.c
@@ -0,0 +1,18 @@
+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..1a5954a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-3.c
@@ -0,0 +1,20 @@
+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..d1d04d6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lift2-4.c
@@ -0,0 +1,22 @@
+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..4c8c72a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-0.c
@@ -0,0 +1,12 @@
+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..4c8c72a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/lu_spmd-1.c
@@ -0,0 +1,12 @@
+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..07b91f7
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m1-1.c
@@ -0,0 +1,13 @@
+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..b3f34f6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m10-1.c
@@ -0,0 +1,14 @@
+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..1ecb4a5
--- /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 <= 2; 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..eba7c8a
--- /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) {
+      s5(3, c1, 1, c3);
+      s4(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..669f51a
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m2-0.c
@@ -0,0 +1,11 @@
+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..a01856e
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m7-1.c
@@ -0,0 +1,10 @@
+for (int c0 = 1; c0 <= 9; c0 += 1) {
+  if (c0 % 2 == 0) {
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      s0(c1, c0);
+      s1(c1, c0);
+    }
+  } else
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      s0(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..51c77da
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/m8-1.c
@@ -0,0 +1,10 @@
+for (int c0 = 2; c0 <= 8; c0 += 2) {
+  if (c0 % 4 == 0) {
+    for (int c1 = 1; c1 <= 9; c1 += 1) {
+      s0(c1, c0);
+      s1(c1, c0);
+    }
+  } else
+    for (int c1 = 1; c1 <= 9; c1 += 1)
+      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..ad5a4ca
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/p.delft2-0.c
@@ -0,0 +1,10 @@
+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 ((5 * P2 + 2 * c3) % 9 <= 3) {
+          if (P1 >= 1 && c0 + 1 == P1 && (5 * P1 + 2 * c2) % 9 <= 2) {
+            s0(P1 - 1, P2, c2, c3, ((5 * P1 + 2 * c2) % 9) + 1, (-4 * P2 + 2 * c3 + 9) % 9);
+          } else if (P1 == 0 && c0 == 3 && c2 % 4 == 0)
+            s0(3, P2, c2, c3, (-c2 / 4) + 3, (-4 * P2 + 2 * c3 + 9) % 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..7fe1758
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/stride7-0.c
@@ -0,0 +1,14 @@
+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..c70e95b
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-check-sblock-0.c
@@ -0,0 +1,14 @@
+{
+  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..5cf4bc9
--- /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 % 2) + c2, 0, c2 % 2, 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..41e3ae6
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/ts1d-mp-i_ts-m_b-0.c
@@ -0,0 +1,35 @@
+{
+  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..2c310e8
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak1-0.c
@@ -0,0 +1,27 @@
+{
+  for (int c0 = a2; c0 <= min(min(a1 - 1, a3 - 1), b2); c0 += 1)
+    s1(c0);
+  for (int c0 = a1; c0 <= min(b1, a3 - 1); c0 += 1) {
+    s0(c0);
+    if (c0 >= a2 && b2 >= c0)
+      s1(c0);
+  }
+  for (int c0 = max(max(a1, b1 + 1), a2); c0 <= min(a3 - 1, b2); c0 += 1)
+    s1(c0);
+  for (int c0 = a3; c0 <= b3; c0 += 1) {
+    if (c0 >= a1 && b1 >= c0)
+      s0(c0);
+    if (c0 >= a2 && b2 >= c0)
+      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 = max(max(a1, a3), b3 + 1); c0 <= b1; c0 += 1) {
+    s0(c0);
+    if (c0 >= a2 && b2 >= c0)
+      s1(c0);
+  }
+  for (int c0 = max(max(max(max(a1, b1 + 1), a3), b3 + 1), a2); c0 <= b2; c0 += 1)
+    s1(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..7fdda1d
--- /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 = 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(max(a1, b1 + 1), a2); c0 <= min(a3 - 1, b2); c0 += 1)
+    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, b1 + 1), a3); c0 <= min(b3, a2 - 1); c0 += 1)
+    s2(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, b1 + 1), a3), a2); c0 <= min(b3, b2); c0 += 1) {
+    s1(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 <= min(b1, a3 - 1); c0 += 1)
+    s0(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, b1 + 1), a3), a2), b2 + 1); c0 <= b3; c0 += 1)
+    s2(c0);
+  for (int c0 = max(max(a3, b3 + 1), a2); c0 <= min(a1 - 1, b2); c0 += 1)
+    s1(c0);
+  for (int c0 = max(max(a1, a3), b3 + 1); c0 <= min(b1, a2 - 1); c0 += 1)
+    s0(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(max(max(a1, b1 + 1), a3), b3 + 1), a2); c0 <= b2; c0 += 1)
+    s1(c0);
+  for (int c0 = max(max(max(max(a1, a3), b3 + 1), a2), b2 + 1); c0 <= b1; c0 += 1)
+    s0(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..3f51dbc
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak2-0.c
@@ -0,0 +1,26 @@
+{
+  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);
+  if (c2 >= d2 + 1) {
+    for (int c0 = max(a1, a2); c0 <= min(b1, b2); c0 += 1)
+      for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+        s0(c0, c1_0);
+  } else
+    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..cc20357
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/omega/wak2-1.c
@@ -0,0 +1,35 @@
+{
+  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);
+  if (c2 >= d2 + 1) {
+    for (int c0 = max(a1, a2); c0 <= min(b1, b2); c0 += 1)
+      for (int c1_0 = c1; c1_0 <= d1; c1_0 += 1)
+        s0(c0, c1_0);
+  } else
+    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 = c1; c1_0 <= min(d1, c2 - 1); c1_0 += 1)
+          s0(c0, c1_0);
+        for (int c1_0 = c2; c1_0 <= min(c1 - 1, d2); c1_0 += 1)
+          s1(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(c1, d2 + 1); c1_0 <= d1; c1_0 += 1)
+          s0(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 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..18ca370
--- /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) {
+    if (n >= 2)
+      s1(c0, c1);
+    s2(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..d1ce579
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_c.c
@@ -0,0 +1,11 @@
+for (int c0 = 1; c0 <= 100; c0 += 1) {
+  if (n >= 2) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s1(c0, c1);
+      s2(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..570cbe5
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/pldi2012/figure7_d.c
@@ -0,0 +1,12 @@
+if (n >= 2) {
+  for (int c0 = 1; c0 <= 100; c0 += 1) {
+    s0(c0);
+    for (int c1 = 1; c1 <= 100; c1 += 1) {
+      s1(c0, c1);
+      s2(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..d7fa3cd
--- /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 >= 2 && 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/roman.c b/final/lib/External/isl/test_inputs/codegen/roman.c
new file mode 100644
index 0000000..1dd43c5
--- /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 (np1 >= i && 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..042e3e7
--- /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) {
+    b(c0 - 1);
+    a(c0);
+  }
+  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..58486c3
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate.in
@@ -0,0 +1,3 @@
+{ a[i] -> [i] : 0 <= i < 10; b[i] -> [i+1] : 0 <= i < 10 }
+{ : }
+{ [i] -> 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..408c7d9
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate.st
@@ -0,0 +1,4 @@
+domain: "{ a[i] : 0 <= i < 10; b[i] : 0 <= i < 10 }"
+child:
+  schedule: "[{ a[i] -> [i]; b[i] -> [i+1] }]"
+  options: "{ separate[x] }"
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..8166821
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separate2.c
@@ -0,0 +1,9 @@
+if ((length - 1) % 16 <= 14)
+  for (int c0 = 0; c0 <= 1; c0 += 1)
+    for (int c5 = 0; c5 <= 31; c5 += 1)
+      for (int c6 = max(0, 2 * ((length - 1) % 16) + 2 * c5 - 60); c6 <= 30; c6 += 1) {
+        if (length + c5 >= ((length - 1) % 32) + 2 && (length - 1) % 32 >= c5 && 2 * ((length - 1) % 32) + c6 >= 2 * c5 && 2 * c5 + 30 >= 2 * ((length - 1) % 32) + c6 && 2 * ((length - 1) % 32) + c6 == 2 * ((length - 1) % 16) + 2 * c5 && (2 * c5 - c6) % 32 == 0)
+          S_3(c0, 0, (c6 / 2) - ((length - 1) % 16) + length - 1);
+        if (length <= 16 && 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..0fdbc32
--- /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 - 1) % 8) + n + c3 - 1);
+  }
+  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 - 1) % 8) + n + c2 - 1, 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..d21b19c
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class3.c
@@ -0,0 +1,29 @@
+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..2ff2364
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/separation_class4.c
@@ -0,0 +1,20 @@
+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..30ea633
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/shift2.c
@@ -0,0 +1,43 @@
+for (int c0 = 0; c0 <= 1; c0 += 1) {
+  for (int c2 = 0; c2 <= length; c2 += 32) {
+    if (length >= c2 + 1) {
+      for (int c3 = 0; c3 <= length; c3 += 32) {
+        for (int c5 = 0; c5 <= min(31, length - c2 - 1); c5 += 1) {
+          for (int c6 = max(0, -c3 + 1); c6 <= min(min(31, length - c3), 2 * c2 - c3 + 2 * c5 - 1); c6 += 1)
+            S_0(c0, c2 + c5, c3 + c6 - 1);
+          if (c2 + c5 >= 1 && 2 * c2 + 2 * c5 >= c3 && c3 + 30 >= 2 * c2 + 2 * c5) {
+            S_3(c0, 0, c2 + c5);
+            if (length >= 2 * c2 + 2 * c5)
+              S_0(c0, c2 + c5, 2 * c2 + 2 * c5 - 1);
+          }
+          for (int c6 = max(0, 2 * c2 - c3 + 2 * c5 + 1); c6 <= min(31, length - c3); c6 += 1)
+            S_0(c0, c2 + c5, c3 + c6 - 1);
+        }
+        if (length <= 15 && c2 == 0 && c3 == 0)
+          S_4(c0);
+        if (c3 >= 2 * c2 && 2 * c2 + 32 >= c3)
+          for (int c4 = 1; c4 <= min(min(31, length - 2), (c3 / 2) + 14); c4 += 1)
+            for (int c5 = max((c3 / 2) - c2, -c2 + c4 + 1); c5 <= min(length - c2 - 1, (c3 / 2) - c2 + 15); c5 += 1)
+              S_3(c0, c4, c2 + c5);
+      }
+      for (int c3 = max(2 * c2, -(length % 32) + length + 32); c3 <= min(2 * length - 2, 2 * c2 + 62); c3 += 32)
+        for (int c4 = 0; c4 <= min(31, length - 2); c4 += 1) {
+          for (int c5 = max((c3 / 2) - c2, -c2 + c4 + 1); c5 <= min(length - c2 - 1, (c3 / 2) - c2 + 15); c5 += 1)
+            S_3(c0, c4, c2 + c5);
+          if (c3 + 30 >= 2 * length && c4 == 0)
+            S_4(c0);
+        }
+      if (c2 + 16 == length && (length - 16) % 32 == 0)
+        S_4(c0);
+    } else if (length == 0) {
+      S_4(c0);
+    } else
+      S_4(c0);
+  }
+  for (int c1 = 32; c1 < length - 1; c1 += 32)
+    for (int c2 = c1; c2 < length; c2 += 32)
+      for (int c3 = c2; c3 <= min(length - 1, c2 + 31); c3 += 16)
+        for (int c4 = 0; c4 <= min(min(31, length - c1 - 2), -c1 + c3 + 14); c4 += 1)
+          for (int c5 = max(-c2 + c3, c1 - c2 + c4 + 1); c5 <= min(length - c2 - 1, -c2 + c3 + 15); c5 += 1)
+            S_3(c0, c1 + c4, c2 + c5);
+}
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/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..ee89e36
--- /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..95a30ba
--- /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 + 125) % 128) - 3);
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..c5dea63
--- /dev/null
+++ b/final/lib/External/isl/test_inputs/codegen/unroll4.c
@@ -0,0 +1,22 @@
+{
+  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);
+  {
+    int c3 = t2 >= 2 && ((t1 + 3) % 4) + 1 >= t2 ? t2 + 32 : ((t2 + 30) % 32) + 2;
+    if (c3 == t2 + 32 || t2 >= ((t1 + 3) % 4) + ((t2 + 1) % 2) + 2)
+      write_shared_A(3, ((t1 + 3) % 4) + 5, c3);
+  }
+  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);
+  {
+    int c3 = t2 >= 2 && ((t1 + 3) % 4) + 1 >= t2 ? t2 + 32 : ((t2 + 30) % 32) + 2;
+    if (c3 == t2 + 32 || t2 >= ((t1 + 3) % 4) + ((t2 + 1) % 2) + 2)
+      write_shared_A(4, ((t1 + 3) % 4) + 5, c3);
+  }
+  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/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/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/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..940eb81
--- /dev/null
+++ b/final/lib/External/isl_config.h.cmake
@@ -0,0 +1,25 @@
+
+/* 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 if your compiler has __attribute__ */
+#cmakedefine HAVE___ATTRIBUTE__ /**/
+
+/* 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/JSON/LICENSE.txt b/final/lib/JSON/LICENSE.txt
new file mode 100644
index 0000000..1c37b11
--- /dev/null
+++ b/final/lib/JSON/LICENSE.txt
@@ -0,0 +1 @@
+The json-cpp library and this documentation are in Public Domain.
diff --git a/final/lib/JSON/include/json/autolink.h b/final/lib/JSON/include/json/autolink.h
new file mode 100644
index 0000000..37c9258
--- /dev/null
+++ b/final/lib/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/JSON/include/json/config.h b/final/lib/JSON/include/json/config.h
new file mode 100644
index 0000000..b6dde91
--- /dev/null
+++ b/final/lib/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/JSON/include/json/features.h b/final/lib/JSON/include/json/features.h
new file mode 100644
index 0000000..5a9adec
--- /dev/null
+++ b/final/lib/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/JSON/include/json/forwards.h b/final/lib/JSON/include/json/forwards.h
new file mode 100644
index 0000000..d0ce830
--- /dev/null
+++ b/final/lib/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/JSON/include/json/json.h b/final/lib/JSON/include/json/json.h
new file mode 100644
index 0000000..c71ed65
--- /dev/null
+++ b/final/lib/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/JSON/include/json/reader.h b/final/lib/JSON/include/json/reader.h
new file mode 100644
index 0000000..0fea022
--- /dev/null
+++ b/final/lib/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/JSON/include/json/value.h b/final/lib/JSON/include/json/value.h
new file mode 100644
index 0000000..aa25e3b
--- /dev/null
+++ b/final/lib/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/JSON/include/json/writer.h b/final/lib/JSON/include/json/writer.h
new file mode 100644
index 0000000..83def71
--- /dev/null
+++ b/final/lib/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/JSON/json_batchallocator.h b/final/lib/JSON/json_batchallocator.h
new file mode 100644
index 0000000..87ea5ed
--- /dev/null
+++ b/final/lib/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/JSON/json_internalarray.inl b/final/lib/JSON/json_internalarray.inl
new file mode 100644
index 0000000..9b985d2
--- /dev/null
+++ b/final/lib/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/JSON/json_internalmap.inl b/final/lib/JSON/json_internalmap.inl
new file mode 100644
index 0000000..1977148
--- /dev/null
+++ b/final/lib/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/JSON/json_reader.cpp b/final/lib/JSON/json_reader.cpp
new file mode 100644
index 0000000..680c2b6
--- /dev/null
+++ b/final/lib/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/JSON/json_value.cpp b/final/lib/JSON/json_value.cpp
new file mode 100644
index 0000000..691e418
--- /dev/null
+++ b/final/lib/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/JSON/json_valueiterator.inl b/final/lib/JSON/json_valueiterator.inl
new file mode 100644
index 0000000..736e260
--- /dev/null
+++ b/final/lib/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/JSON/json_writer.cpp b/final/lib/JSON/json_writer.cpp
new file mode 100644
index 0000000..bf475c3
--- /dev/null
+++ b/final/lib/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/JSON/sconscript b/final/lib/JSON/sconscript
new file mode 100644
index 0000000..6e7c6c8
--- /dev/null
+++ b/final/lib/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/Makefile b/final/lib/Makefile
new file mode 100644
index 0000000..23d74fc
--- /dev/null
+++ b/final/lib/Makefile
@@ -0,0 +1,144 @@
+##===- polly/lib/Makefile -----------------------*- Makefile -*-===##
+
+#
+# Indicate where we are relative to the top of the source tree.
+#
+LEVEL :=..
+
+LIBRARYNAME=LLVMPolly
+LOADABLE_MODULE = 1
+
+# TODO: Export symbols for RTTI or EH?
+
+CPP.Flags += $(POLLY_INC)
+C.Flags += $(POLLY_CFLAGS)
+LD.Flags += $(POLLY_LD) $(POLLY_LIB)
+
+include $(LEVEL)/Makefile.config
+
+# Enable optional source files
+ifeq ($(GPU_CODEGEN), yes)
+GPGPU_CODEGEN_FILES=""
+endif
+
+ISL_CODEGEN_FILES= CodeGen/IslAst.cpp \
+                   CodeGen/IslExprBuilder.cpp \
+                   CodeGen/IslNodeBuilder.cpp \
+                   CodeGen/CodeGeneration.cpp
+
+POLLY_JSON_FILES= JSON/json_reader.cpp \
+		  JSON/json_value.cpp \
+		  JSON/json_writer.cpp
+
+ISL_FILES= External/isl/basis_reduction_tab.c \
+           External/isl/isl_aff.c \
+           External/isl/isl_affine_hull.c \
+           External/isl/isl_arg.c \
+           External/isl/isl_ast_build.c \
+           External/isl/isl_ast_build_expr.c \
+           External/isl/isl_ast.c \
+           External/isl/isl_ast_codegen.c \
+           External/isl/isl_ast_graft.c \
+           External/isl/isl_band.c \
+           External/isl/isl_bernstein.c \
+           External/isl/isl_blk.c \
+           External/isl/isl_bound.c \
+           External/isl/isl_coalesce.c \
+           External/isl/isl_constraint.c \
+           External/isl/isl_convex_hull.c \
+           External/isl/isl_ctx.c \
+           External/isl/isl_deprecated.c \
+           External/isl/isl_dim_map.c \
+           External/isl/isl_equalities.c \
+           External/isl/isl_factorization.c \
+           External/isl/isl_farkas.c \
+           External/isl/isl_flow.c \
+           External/isl/isl_fold.c \
+           External/isl/isl_hash.c \
+           External/isl/isl_id.c \
+           External/isl/isl_id_to_ast_expr.c \
+           External/isl/isl_id_to_pw_aff.c \
+           External/isl/isl_ilp.c \
+           External/isl/isl_imath.c \
+           External/isl/isl_input.c \
+           External/isl/isl_int_sioimath.c \
+           External/isl/isl_local_space.c \
+           External/isl/isl_lp.c \
+           External/isl/isl_map.c \
+	   External/isl/isl_map_list.c \
+           External/isl/isl_map_simplify.c \
+           External/isl/isl_map_subtract.c \
+           External/isl/isl_map_to_basic_set.c \
+           External/isl/isl_mat.c \
+           External/isl/isl_morph.c \
+           External/isl/isl_obj.c \
+           External/isl/isl_options.c \
+           External/isl/isl_output.c \
+           External/isl/isl_point.c \
+           External/isl/isl_polynomial.c \
+           External/isl/isl_printer.c \
+           External/isl/isl_range.c \
+           External/isl/isl_reordering.c \
+           External/isl/isl_sample.c \
+           External/isl/isl_scan.c \
+           External/isl/isl_schedule.c \
+	   External/isl/isl_schedule_band.c \
+	   External/isl/isl_schedule_node.c \
+	   External/isl/isl_schedule_read.c \
+	   External/isl/isl_schedule_tree.c \
+           External/isl/isl_scheduler.c \
+           External/isl/isl_seq.c \
+           External/isl/isl_set_list.c \
+           External/isl/isl_sort.c \
+           External/isl/isl_space.c \
+           External/isl/isl_stream.c \
+           External/isl/isl_tab.c \
+           External/isl/isl_tab_pip.c \
+           External/isl/isl_tarjan.c \
+           External/isl/isl_transitive_closure.c \
+           External/isl/isl_union_map.c \
+           External/isl/isl_val.c \
+           External/isl/isl_val_sioimath.c \
+           External/isl/isl_vec.c \
+           External/isl/isl_version.c \
+           External/isl/isl_vertices.c \
+           External/isl/print.c \
+           External/isl/imath/gmp_compat.c \
+           External/isl/imath/imath.c \
+           External/isl/imath/imrat.c
+
+SOURCES= Polly.cpp \
+	 Support/GICHelper.cpp \
+	 Support/SCEVValidator.cpp \
+	 Support/RegisterPasses.cpp \
+	 Support/ScopHelper.cpp \
+	 Support/ScopLocation.cpp \
+	 Analysis/DependenceInfo.cpp \
+	 Analysis/ScopDetection.cpp \
+	 Analysis/ScopDetectionDiagnostic.cpp \
+	 Analysis/ScopInfo.cpp \
+	 Analysis/ScopGraphPrinter.cpp \
+	 Analysis/ScopPass.cpp \
+	 Analysis/TempScopInfo.cpp \
+	 CodeGen/BlockGenerators.cpp \
+	 CodeGen/LoopGenerators.cpp \
+	 CodeGen/IRBuilder.cpp \
+	 CodeGen/Utils.cpp \
+	 CodeGen/RuntimeDebugBuilder.cpp \
+	 Exchange/JSONExporter.cpp \
+	 Transform/Canonicalization.cpp \
+	 Transform/CodePreparation.cpp \
+	 Transform/DeadCodeElimination.cpp \
+	 Transform/IndependentBlocks.cpp \
+	 Transform/ScheduleOptimizer.cpp \
+	 ${GPGPU_FILES} \
+	 ${ISL_CODEGEN_FILES} \
+	 ${POLLY_JSON_FILES} \
+	 ${ISL_FILES}
+
+#
+# Include Makefile.common so we know what to do.
+#
+include $(LEVEL)/Makefile.common
+
+LIBS += $(POLLY_LD) $(POLLY_LIB)
diff --git a/final/lib/Polly.cpp b/final/lib/Polly.cpp
new file mode 100644
index 0000000..c879fd9
--- /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 {
+
+/// @brief 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/GICHelper.cpp b/final/lib/Support/GICHelper.cpp
new file mode 100644
index 0000000..c260767
--- /dev/null
+++ b/final/lib/Support/GICHelper.cpp
@@ -0,0 +1,159 @@
+//===- 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 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/union_map.h"
+#include "isl/union_set.h"
+#include "isl/val.h"
+
+using namespace llvm;
+
+__isl_give isl_val *polly::isl_valFromAPInt(isl_ctx *Ctx, const APInt Int,
+                                            bool IsSigned) {
+  APInt Abs;
+  isl_val *v;
+
+  if (IsSigned)
+    Abs = Int.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;
+
+  NumChunks = isl_val_n_abs_num_chunks(Val, sizeof(uint64_t));
+
+  Data = (uint64_t *)malloc(NumChunks * sizeof(uint64_t));
+  isl_val_get_abs_num_chunks(Val, sizeof(uint64_t), Data);
+  APInt A(8 * sizeof(uint64_t) * NumChunks, NumChunks, Data);
+
+  if (isl_val_is_neg(Val)) {
+    A = A.zext(A.getBitWidth() + 1);
+    A = -A;
+  }
+
+  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) {
+  isl_ctx *ctx = ctx_getter_fn(isl_obj);
+  isl_printer *p = isl_printer_to_str(ctx);
+  printer_fn(p, isl_obj);
+  char *char_str = isl_printer_get_str(p);
+  std::string string(char_str);
+  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_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);
+}
+
+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");
+}
+
+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 Value *Val,
+                                        const std::string &Suffix) {
+  std::string ValStr;
+  raw_string_ostream OS(ValStr);
+  Val->printAsOperand(OS, false);
+  ValStr = OS.str();
+  // Remove the leading %
+  ValStr.erase(0, 1);
+  return getIslCompatibleName(Prefix, ValStr, Suffix);
+}
diff --git a/final/lib/Support/RegisterPasses.cpp b/final/lib/Support/RegisterPasses.cpp
new file mode 100644
index 0000000..1304930
--- /dev/null
+++ b/final/lib/Support/RegisterPasses.cpp
@@ -0,0 +1,268 @@
+//===------ 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/DependenceInfo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopDetection.h"
+#include "polly/ScopInfo.h"
+#include "polly/TempScopInfo.h"
+#include "llvm/Analysis/CFGPrinter.h"
+#include "llvm/IR/LegacyPassManager.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 OptimizerChoice { OPTIMIZER_NONE, OPTIMIZER_ISL };
+
+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"),
+               clEnumValEnd),
+    cl::Hidden, cl::init(OPTIMIZER_ISL), cl::ZeroOrMore,
+    cl::cat(PollyCategory));
+
+enum CodeGenChoice { CODEGEN_ISL, CODEGEN_NONE };
+static cl::opt<CodeGenChoice> CodeGenerator(
+    "polly-code-generator", cl::desc("Select the code generator"),
+    cl::values(clEnumValN(CODEGEN_ISL, "isl", "isl code generator"),
+               clEnumValN(CODEGEN_NONE, "none", "no code generation"),
+               clEnumValEnd),
+    cl::Hidden, cl::init(CODEGEN_ISL), cl::ZeroOrMore, cl::cat(PollyCategory));
+
+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"),
+        clEnumValEnd),
+    cl::location(PollyVectorizerChoice), cl::init(polly::VECTORIZER_NONE),
+    cl::ZeroOrMore, cl::cat(PollyCategory));
+
+static cl::opt<bool> ImportJScop(
+    "polly-import",
+    cl::desc("Export the polyhedral description 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));
+
+namespace polly {
+void initializePollyPasses(PassRegistry &Registry) {
+  initializeCodeGenerationPass(Registry);
+  initializeCodePreparationPass(Registry);
+  initializeDeadCodeElimPass(Registry);
+  initializeDependenceInfoPass(Registry);
+  initializeIndependentBlocksPass(Registry);
+  initializeJSONExporterPass(Registry);
+  initializeJSONImporterPass(Registry);
+  initializeIslAstInfoPass(Registry);
+  initializeIslScheduleOptimizerPass(Registry);
+  initializePollyCanonicalizePass(Registry);
+  initializeScopDetectionPass(Registry);
+  initializeScopInfoPass(Registry);
+  initializeTempScopInfoPass(Registry);
+}
+
+/// @brief 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) {
+  registerCanonicalicationPasses(PM);
+
+  PM.add(polly::createScopDetectionPass());
+
+  if (PollyDetectOnly)
+    return;
+
+  PM.add(polly::createScopInfoPass());
+
+  if (PollyViewer)
+    PM.add(polly::createDOTViewerPass());
+  if (PollyOnlyViewer)
+    PM.add(polly::createDOTOnlyViewerPass());
+  if (PollyPrinter)
+    PM.add(polly::createDOTPrinterPass());
+  if (PollyOnlyPrinter)
+    PM.add(polly::createDOTOnlyPrinterPass());
+
+  if (ImportJScop)
+    PM.add(polly::createJSONImporterPass());
+
+  if (DeadCodeElim)
+    PM.add(polly::createDeadCodeElimPass());
+
+  switch (Optimizer) {
+  case OPTIMIZER_NONE:
+    break; /* Do nothing */
+
+  case OPTIMIZER_ISL:
+    PM.add(polly::createIslScheduleOptimizerPass());
+    break;
+  }
+
+  if (ExportJScop)
+    PM.add(polly::createJSONExporterPass());
+
+  switch (CodeGenerator) {
+  case CODEGEN_ISL:
+    PM.add(polly::createCodeGenerationPass());
+    break;
+  case CODEGEN_NONE:
+    break;
+  }
+
+  if (CFGPrinter)
+    PM.add(llvm::createCFGPrinterPass());
+}
+
+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;
+
+  polly::registerPollyPasses(PM);
+}
+
+/// @brief Register Polly to be available as an optimizer
+///
+/// We currently 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.
+static llvm::RegisterStandardPasses
+    RegisterPollyOptimizer(llvm::PassManagerBuilder::EP_EarlyAsPossible,
+                           registerPollyEarlyAsPossiblePasses);
+}
diff --git a/final/lib/Support/SCEVValidator.cpp b/final/lib/Support/SCEVValidator.cpp
new file mode 100644
index 0000000..2092047
--- /dev/null
+++ b/final/lib/Support/SCEVValidator.cpp
@@ -0,0 +1,600 @@
+
+#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"
+#include <vector>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "polly-scev-validator"
+
+namespace SCEVType {
+/// @brief 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
+};
+}
+
+/// @brief The result the validator returns for a SCEV expression.
+class ValidatorResult {
+  /// @brief The type of the expression
+  SCEVType::TYPE Type;
+
+  /// @brief The set of Parameters in the expression.
+  std::vector<const SCEV *> Parameters;
+
+public:
+  /// @brief The copy constructor
+  ValidatorResult(const ValidatorResult &Source) {
+    Type = Source.Type;
+    Parameters = Source.Parameters;
+  }
+
+  /// @brief 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");
+  }
+
+  /// @brief Construct a result with a certain type and a single parameter.
+  ValidatorResult(SCEVType::TYPE Type, const SCEV *Expr) : Type(Type) {
+    Parameters.push_back(Expr);
+  }
+
+  /// @brief Get the type of the ValidatorResult.
+  SCEVType::TYPE getType() { return Type; }
+
+  /// @brief Is the analyzed SCEV constant during the execution of the SCoP.
+  bool isConstant() { return Type == SCEVType::INT || Type == SCEVType::PARAM; }
+
+  /// @brief Is the analyzed SCEV valid.
+  bool isValid() { return Type != SCEVType::INVALID; }
+
+  /// @brief Is the analyzed SCEV of Type IV.
+  bool isIV() { return Type == SCEVType::IV; }
+
+  /// @brief Is the analyzed SCEV of Type INT.
+  bool isINT() { return Type == SCEVType::INT; }
+
+  /// @brief Is the analyzed SCEV of Type PARAM.
+  bool isPARAM() { return Type == SCEVType::PARAM; }
+
+  /// @brief Get the parameters of this validator result.
+  std::vector<const SCEV *> getParameters() { return Parameters; }
+
+  /// @brief Add the parameters of Source to this result.
+  void addParamsFrom(const ValidatorResult &Source) {
+    Parameters.insert(Parameters.end(), Source.Parameters.begin(),
+                      Source.Parameters.end());
+  }
+
+  /// @brief 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;
+}
+
+/// Check if a SCEV is valid in a SCoP.
+struct SCEVValidator
+    : public SCEVVisitor<SCEVValidator, class ValidatorResult> {
+private:
+  const Region *R;
+  ScalarEvolution &SE;
+  const Value *BaseAddress;
+
+public:
+  SCEVValidator(const Region *R, ScalarEvolution &SE, const Value *BaseAddress)
+      : R(R), SE(SE), BaseAddress(BaseAddress) {}
+
+  class ValidatorResult visitConstant(const SCEVConstant *Constant) {
+    return ValidatorResult(SCEVType::INT);
+  }
+
+  class ValidatorResult visitTruncateExpr(const SCEVTruncateExpr *Expr) {
+    ValidatorResult Op = visit(Expr->getOperand());
+
+    switch (Op.getType()) {
+    case SCEVType::INT:
+    case SCEVType::PARAM:
+      // We currently do not represent a truncate expression as an affine
+      // expression. If it is constant during Scop execution, we treat it as a
+      // parameter.
+      return ValidatorResult(SCEVType::PARAM, Expr);
+    case SCEVType::IV:
+      DEBUG(dbgs() << "INVALID: Truncation of SCEVType::IV expression");
+      return ValidatorResult(SCEVType::INVALID);
+    case SCEVType::INVALID:
+      return Op;
+    }
+
+    llvm_unreachable("Unknown SCEVType");
+  }
+
+  class ValidatorResult visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
+    ValidatorResult Op = visit(Expr->getOperand());
+
+    switch (Op.getType()) {
+    case SCEVType::INT:
+    case SCEVType::PARAM:
+      // We currently do not represent a truncate expression as an affine
+      // expression. If it is constant during Scop execution, we treat it as a
+      // parameter.
+      return ValidatorResult(SCEVType::PARAM, Expr);
+    case SCEVType::IV:
+      DEBUG(dbgs() << "INVALID: ZeroExtend of SCEVType::IV expression");
+      return ValidatorResult(SCEVType::INVALID);
+    case SCEVType::INVALID:
+      return Op;
+    }
+
+    llvm_unreachable("Unknown SCEVType");
+  }
+
+  class ValidatorResult visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
+    // We currently allow only signed SCEV expressions. In the case of a
+    // signed value, a sign extend is a noop.
+    //
+    // TODO: Reconsider this when we add support for unsigned values.
+    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;
+    }
+
+    // TODO: Check for NSW and NUW.
+    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);
+
+    // TODO: Check for NSW and NUW.
+    return Return;
+  }
+
+  class ValidatorResult visitUDivExpr(const SCEVUDivExpr *Expr) {
+    ValidatorResult LHS = visit(Expr->getLHS());
+    ValidatorResult RHS = visit(Expr->getRHS());
+
+    // We currently do not represent an unsigned division as an affine
+    // expression. If the division is constant during Scop execution we treat it
+    // as a parameter, otherwise we bail out.
+    if (LHS.isConstant() && RHS.isConstant())
+      return ValidatorResult(SCEVType::PARAM, Expr);
+
+    DEBUG(dbgs() << "INVALID: unsigned division of non-constant expressions");
+    return ValidatorResult(SCEVType::INVALID);
+  }
+
+  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;
+
+    if (R->contains(Expr->getLoop())) {
+      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(Start.isConstant() && Recurrence.isConstant() &&
+           "Expected 'Start' and '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 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 visitSDivInstruction(Instruction *SDiv, const SCEV *S) {
+    assert(SDiv->getOpcode() == Instruction::SDiv &&
+           "Assumed SDiv instruction!");
+
+    auto *Divisor = SDiv->getOperand(1);
+    auto *CI = dyn_cast<ConstantInt>(Divisor);
+    if (!CI)
+      return visitGenericInst(SDiv, S);
+
+    auto *Dividend = SDiv->getOperand(0);
+    auto *DividendSCEV = SE.getSCEV(Dividend);
+    return visit(DividendSCEV);
+  }
+
+  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)
+      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 type");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    if (isa<UndefValue>(V)) {
+      DEBUG(dbgs() << "INVALID: UnknownExpr references an undef value");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    if (BaseAddress == V) {
+      DEBUG(dbgs() << "INVALID: UnknownExpr references BaseAddress\n");
+      return ValidatorResult(SCEVType::INVALID);
+    }
+
+    if (Instruction *I = dyn_cast<Instruction>(Expr->getValue())) {
+      switch (I->getOpcode()) {
+      case Instruction::SDiv:
+        return visitSDivInstruction(I, Expr);
+      case Instruction::SRem:
+        return visitSRemInstruction(I, Expr);
+      default:
+        return visitGenericInst(I, Expr);
+      }
+    }
+
+    return ValidatorResult(SCEVType::PARAM, Expr);
+  }
+};
+
+/// @brief Check whether a SCEV refers to an SSA name defined inside a region.
+///
+struct SCEVInRegionDependences
+    : public SCEVVisitor<SCEVInRegionDependences, bool> {
+public:
+  /// Returns true when the SCEV has SSA names defined in region R.
+  static bool hasDependences(const SCEV *S, const Region *R) {
+    SCEVInRegionDependences Ignore(R);
+    return Ignore.visit(S);
+  }
+
+  SCEVInRegionDependences(const Region *R) : R(R) {}
+
+  bool visit(const SCEV *Expr) {
+    return SCEVVisitor<SCEVInRegionDependences, bool>::visit(Expr);
+  }
+
+  bool visitConstant(const SCEVConstant *Constant) { return false; }
+
+  bool visitTruncateExpr(const SCEVTruncateExpr *Expr) {
+    return visit(Expr->getOperand());
+  }
+
+  bool visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr) {
+    return visit(Expr->getOperand());
+  }
+
+  bool visitSignExtendExpr(const SCEVSignExtendExpr *Expr) {
+    return visit(Expr->getOperand());
+  }
+
+  bool visitAddExpr(const SCEVAddExpr *Expr) {
+    for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
+      if (visit(Expr->getOperand(i)))
+        return true;
+
+    return false;
+  }
+
+  bool visitMulExpr(const SCEVMulExpr *Expr) {
+    for (int i = 0, e = Expr->getNumOperands(); i < e; ++i)
+      if (visit(Expr->getOperand(i)))
+        return true;
+
+    return false;
+  }
+
+  bool visitUDivExpr(const SCEVUDivExpr *Expr) {
+    if (visit(Expr->getLHS()))
+      return true;
+
+    if (visit(Expr->getRHS()))
+      return true;
+
+    return false;
+  }
+
+  bool visitAddRecExpr(const SCEVAddRecExpr *Expr) {
+    if (visit(Expr->getStart()))
+      return true;
+
+    for (size_t i = 0; i < Expr->getNumOperands(); ++i)
+      if (visit(Expr->getOperand(i)))
+        return true;
+
+    return false;
+  }
+
+  bool visitSMaxExpr(const SCEVSMaxExpr *Expr) {
+    for (size_t i = 0; i < Expr->getNumOperands(); ++i)
+      if (visit(Expr->getOperand(i)))
+        return true;
+
+    return false;
+  }
+
+  bool visitUMaxExpr(const SCEVUMaxExpr *Expr) {
+    for (size_t i = 0; i < Expr->getNumOperands(); ++i)
+      if (visit(Expr->getOperand(i)))
+        return true;
+
+    return false;
+  }
+
+  bool visitUnknown(const SCEVUnknown *Expr) {
+    Instruction *Inst = dyn_cast<Instruction>(Expr->getValue());
+
+    // Return true when Inst is defined inside the region R.
+    if (Inst && R->contains(Inst))
+      return true;
+
+    return false;
+  }
+
+private:
+  const Region *R;
+};
+
+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 {
+  SetVector<Value *> &Values;
+
+public:
+  SCEVFindValues(SetVector<Value *> &Values) : Values(Values) {}
+
+  bool follow(const SCEV *S) {
+    if (const SCEVUnknown *Unknown = dyn_cast<SCEVUnknown>(S))
+      Values.insert(Unknown->getValue());
+    return true;
+  }
+  bool isDone() { return false; }
+};
+
+void findValues(const SCEV *Expr, SetVector<Value *> &Values) {
+  SCEVFindValues FindValues(Values);
+  SCEVTraversal<SCEVFindValues> ST(FindValues);
+  ST.visitAll(Expr);
+}
+
+bool hasScalarDepsInsideRegion(const SCEV *Expr, const Region *R) {
+  return SCEVInRegionDependences::hasDependences(Expr, R);
+}
+
+bool isAffineExpr(const Region *R, const SCEV *Expr, ScalarEvolution &SE,
+                  const Value *BaseAddress) {
+  if (isa<SCEVCouldNotCompute>(Expr))
+    return false;
+
+  SCEVValidator Validator(R, SE, BaseAddress);
+  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();
+}
+
+std::vector<const SCEV *> getParamsInAffineExpr(const Region *R,
+                                                const SCEV *Expr,
+                                                ScalarEvolution &SE,
+                                                const Value *BaseAddress) {
+  if (isa<SCEVCouldNotCompute>(Expr))
+    return std::vector<const SCEV *>();
+
+  SCEVValidator Validator(R, SE, BaseAddress);
+  ValidatorResult Result = Validator.visit(Expr);
+  assert(Result.isValid() && "Requested parameters for an invalid SCEV!");
+
+  return Result.getParameters();
+}
+
+std::pair<const SCEV *, const SCEV *>
+extractConstantFactor(const SCEV *S, ScalarEvolution &SE) {
+
+  const SCEV *LeftOver = SE.getConstant(S->getType(), 1);
+  const SCEV *ConstPart = SE.getConstant(S->getType(), 1);
+
+  const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(S);
+  if (!M)
+    return std::make_pair(ConstPart, S);
+
+  for (const SCEV *Op : M->operands())
+    if (isa<SCEVConstant>(Op))
+      ConstPart = SE.getMulExpr(ConstPart, Op);
+    else
+      LeftOver = SE.getMulExpr(LeftOver, Op);
+
+  return std::make_pair(ConstPart, LeftOver);
+}
+}
diff --git a/final/lib/Support/ScopHelper.cpp b/final/lib/Support/ScopHelper.cpp
new file mode 100644
index 0000000..8fdecec
--- /dev/null
+++ b/final/lib/Support/ScopHelper.cpp
@@ -0,0 +1,197 @@
+//===- 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/ScopInfo.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "polly-scop-helper"
+
+// Helper function for Scop
+// TODO: Add assertion to not allow parameter to be null
+//===----------------------------------------------------------------------===//
+// Temporary Hack for extended region tree.
+// Cast the region to loop if there is a loop have the same header and exit.
+Loop *polly::castToLoop(const Region &R, LoopInfo &LI) {
+  BasicBlock *entry = R.getEntry();
+
+  if (!LI.isLoopHeader(entry))
+    return 0;
+
+  Loop *L = LI.getLoopFor(entry);
+
+  BasicBlock *exit = L->getExitBlock();
+
+  // Is the loop with multiple exits?
+  if (!exit)
+    return 0;
+
+  if (exit != R.getExit()) {
+    // SubRegion/ParentRegion with the same entry.
+    assert((R.getNode(R.getEntry())->isSubRegion() ||
+            R.getParent()->getEntry() == entry) &&
+           "Expect the loop is the smaller or bigger region");
+    return 0;
+  }
+
+  return L;
+}
+
+Value *polly::getPointerOperand(Instruction &Inst) {
+  if (LoadInst *load = dyn_cast<LoadInst>(&Inst))
+    return load->getPointerOperand();
+  else if (StoreInst *store = dyn_cast<StoreInst>(&Inst))
+    return store->getPointerOperand();
+  else if (GetElementPtrInst *gep = dyn_cast<GetElementPtrInst>(&Inst))
+    return gep->getPointerOperand();
+
+  return 0;
+}
+
+Type *polly::getAccessInstType(Instruction *AccInst) {
+  if (StoreInst *Store = dyn_cast<StoreInst>(AccInst))
+    return Store->getValueOperand()->getType();
+  if (BranchInst *Branch = dyn_cast<BranchInst>(AccInst))
+    return Branch->getCondition()->getType();
+  return AccInst->getType();
+}
+
+bool polly::hasInvokeEdge(const PHINode *PN) {
+  for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i)
+    if (InvokeInst *II = dyn_cast<InvokeInst>(PN->getIncomingValue(i)))
+      if (II->getParent() == PN->getIncomingBlock(i))
+        return true;
+
+  return false;
+}
+
+BasicBlock *polly::createSingleExitEdge(Region *R, Pass *P) {
+  BasicBlock *BB = R->getExit();
+
+  SmallVector<BasicBlock *, 4> Preds;
+  for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI)
+    if (R->contains(*PI))
+      Preds.push_back(*PI);
+
+  auto *AA = P->getAnalysisIfAvailable<AliasAnalysis>();
+  auto *DTWP = P->getAnalysisIfAvailable<DominatorTreeWrapperPass>();
+  auto *DT = DTWP ? &DTWP->getDomTree() : nullptr;
+  auto *LIWP = P->getAnalysisIfAvailable<LoopInfoWrapperPass>();
+  auto *LI = LIWP ? &LIWP->getLoopInfo() : nullptr;
+
+  return SplitBlockPredecessors(BB, Preds, ".region", AA, DT, LI);
+}
+
+static void replaceScopAndRegionEntry(polly::Scop *S, BasicBlock *OldEntry,
+                                      BasicBlock *NewEntry) {
+  if (polly::ScopStmt *Stmt = S->getStmtForBasicBlock(OldEntry))
+    Stmt->setBasicBlock(NewEntry);
+
+  S->getRegion().replaceEntryRecursive(NewEntry);
+}
+
+BasicBlock *polly::simplifyRegion(Scop *S, Pass *P) {
+  Region *R = &S->getRegion();
+
+  // The entering block for the region.
+  BasicBlock *EnteringBB = R->getEnteringBlock();
+  BasicBlock *OldEntry = R->getEntry();
+  BasicBlock *NewEntry = nullptr;
+
+  auto *DTWP = P->getAnalysisIfAvailable<DominatorTreeWrapperPass>();
+  auto *DT = DTWP ? &DTWP->getDomTree() : nullptr;
+  auto *LIWP = P->getAnalysisIfAvailable<LoopInfoWrapperPass>();
+  auto *LI = LIWP ? &LIWP->getLoopInfo() : nullptr;
+
+  // Create single entry edge if the region has multiple entry edges.
+  if (!EnteringBB) {
+    NewEntry = SplitBlock(OldEntry, OldEntry->begin(), DT, LI);
+    EnteringBB = OldEntry;
+  }
+
+  // Create an unconditional entry edge.
+  if (EnteringBB->getTerminator()->getNumSuccessors() != 1) {
+    BasicBlock *EntryBB = NewEntry ? NewEntry : OldEntry;
+    BasicBlock *SplitEdgeBB = SplitEdge(EnteringBB, EntryBB, DT, LI);
+
+    // Once the edge between EnteringBB and EntryBB is split, two cases arise.
+    // The first is simple. The new block is inserted between EnteringBB and
+    // EntryBB. In this case no further action is needed. However it might
+    // happen (if the splitted edge is not critical) that the new block is
+    // inserted __after__ EntryBB causing the following situation:
+    //
+    // EnteringBB
+    //    _|_
+    //    | |
+    //    |  \-> some_other_BB_not_in_R
+    //    V
+    // EntryBB
+    //    |
+    //    V
+    // SplitEdgeBB
+    //
+    // In this case we need to swap the role of EntryBB and SplitEdgeBB.
+
+    // Check which case SplitEdge produced:
+    if (SplitEdgeBB->getTerminator()->getSuccessor(0) == EntryBB) {
+      // First (simple) case.
+      EnteringBB = SplitEdgeBB;
+    } else {
+      // Second (complicated) case.
+      NewEntry = SplitEdgeBB;
+      EnteringBB = EntryBB;
+    }
+
+    EnteringBB->setName("polly.entering.block");
+  }
+
+  if (NewEntry)
+    replaceScopAndRegionEntry(S, OldEntry, NewEntry);
+
+  // Create single exit edge if the region has multiple exit edges.
+  if (!R->getExitingBlock()) {
+    BasicBlock *NewExiting = createSingleExitEdge(R, P);
+    (void)NewExiting;
+    assert(NewExiting == R->getExitingBlock() &&
+           "Did not create a single exiting block");
+  }
+
+  return EnteringBB;
+}
+
+void polly::splitEntryBlockForAlloca(BasicBlock *EntryBlock, Pass *P) {
+  // Find first non-alloca instruction. Every basic block has a non-alloc
+  // instruction, as every well formed basic block has a terminator.
+  BasicBlock::iterator I = EntryBlock->begin();
+  while (isa<AllocaInst>(I))
+    ++I;
+
+  auto *DTWP = P->getAnalysisIfAvailable<DominatorTreeWrapperPass>();
+  auto *DT = DTWP ? &DTWP->getDomTree() : nullptr;
+  auto *LIWP = P->getAnalysisIfAvailable<LoopInfoWrapperPass>();
+  auto *LI = LIWP ? &LIWP->getLoopInfo() : nullptr;
+
+  // SplitBlock updates DT, DF and LI.
+  BasicBlock *NewEntry = SplitBlock(EntryBlock, I, DT, LI);
+  if (RegionInfoPass *RIP = P->getAnalysisIfAvailable<RegionInfoPass>())
+    RIP->getRegionInfo().splitBlock(NewEntry, EntryBlock);
+}
diff --git a/final/lib/Support/ScopLocation.cpp b/final/lib/Support/ScopLocation.cpp
new file mode 100644
index 0000000..8625c31
--- /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);
+    }
+}
+}
diff --git a/final/lib/Transform/Canonicalization.cpp b/final/lib/Transform/Canonicalization.cpp
new file mode 100644
index 0000000..0e74675
--- /dev/null
+++ b/final/lib/Transform/Canonicalization.cpp
@@ -0,0 +1,80 @@
+//===---- 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/LinkAllPasses.h"
+#include "polly/Canonicalization.h"
+#include "llvm/Transforms/Scalar.h"
+
+using namespace llvm;
+using namespace polly;
+
+void polly::registerCanonicalicationPasses(llvm::legacy::PassManagerBase &PM) {
+  PM.add(llvm::createPromoteMemoryToRegisterPass());
+  PM.add(llvm::createInstructionCombiningPass());
+  PM.add(llvm::createCFGSimplificationPass());
+  PM.add(llvm::createTailCallEliminationPass());
+  PM.add(llvm::createCFGSimplificationPass());
+  PM.add(llvm::createReassociatePass());
+  PM.add(llvm::createLoopRotatePass());
+  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;
+  //@}
+};
+}
+
+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..78e2563
--- /dev/null
+++ b/final/lib/Transform/CodePreparation.cpp
@@ -0,0 +1,99 @@
+//===---- 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/LinkAllPasses.h"
+#include "polly/CodeGen/BlockGenerators.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 {
+
+/// @brief 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();
+
+  bool eliminatePHINodes(Function &F);
+
+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;
+  //@}
+};
+}
+
+void CodePreparation::clear() {}
+
+CodePreparation::~CodePreparation() { clear(); }
+
+void CodePreparation::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addRequired<ScalarEvolution>();
+
+  AU.addPreserved<LoopInfoWrapperPass>();
+  AU.addPreserved<RegionInfoPass>();
+  AU.addPreserved<DominatorTreeWrapperPass>();
+  AU.addPreserved<DominanceFrontier>();
+}
+
+bool CodePreparation::runOnFunction(Function &F) {
+  LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  SE = &getAnalysis<ScalarEvolution>();
+
+  splitEntryBlockForAlloca(&F.getEntryBlock(), this);
+
+  return false;
+}
+
+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/DeadCodeElimination.cpp b/final/lib/Transform/DeadCodeElimination.cpp
new file mode 100644
index 0000000..1d5ccbe
--- /dev/null
+++ b/final/lib/Transform/DeadCodeElimination.cpp
@@ -0,0 +1,183 @@
+//===- 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/ScopInfo.h"
+#include "llvm/Support/CommandLine.h"
+#include "isl/flow.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));
+
+class DeadCodeElim : public ScopPass {
+public:
+  static char ID;
+  explicit DeadCodeElim() : ScopPass(ID) {}
+
+  bool runOnScop(Scop &S) override;
+
+  void printScop(raw_ostream &OS, Scop &S) const override;
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  /// @brief 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);
+};
+}
+
+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 *WriteIterations = isl_union_map_reverse(S.getMustWrites());
+  isl_union_map *WriteTimes =
+      isl_union_map_apply_range(WriteIterations, isl_union_map_copy(Schedule));
+
+  isl_union_map *LastWriteTimes = isl_union_map_lexmax(WriteTimes);
+  isl_union_map *LastWriteIterations = isl_union_map_apply_range(
+      LastWriteTimes, isl_union_map_reverse(Schedule));
+
+  isl_union_set *Live = isl_union_map_range(LastWriteIterations);
+  Live = isl_union_set_union(Live, isl_union_map_domain(S.getMayWrites()));
+  return isl_union_set_coalesce(Live);
+}
+
+/// 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();
+
+  if (!D.hasValidDependences())
+    return false;
+
+  isl_union_set *Live = getLiveOut(S);
+  isl_union_map *Dep =
+      D.getDependences(Dependences::TYPE_RAW | Dependences::TYPE_RED);
+  Dep = isl_union_map_reverse(Dep);
+
+  if (PreciseSteps == -1)
+    Live = isl_union_set_affine_hull(Live);
+
+  isl_union_set *OriginalDomain = S.getDomains();
+  int Steps = 0;
+  while (true) {
+    isl_union_set *Extra;
+    Steps++;
+
+    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);
+
+    if (Steps > PreciseSteps) {
+      Steps = 0;
+      Live = isl_union_set_affine_hull(Live);
+    }
+
+    Live = isl_union_set_intersect(Live, isl_union_set_copy(OriginalDomain));
+  }
+  isl_union_map_free(Dep);
+  isl_union_set_free(OriginalDomain);
+
+  bool Changed = S.restrictDomains(isl_union_set_coalesce(Live));
+
+  // FIXME: We can probably avoid the recomputation of all dependences by
+  // updating them explicitly.
+  if (Changed)
+    DI.recomputeDependences();
+  return Changed;
+}
+
+bool DeadCodeElim::runOnScop(Scop &S) {
+  return eliminateDeadCode(S, DCEPreciseSteps);
+}
+
+void DeadCodeElim::printScop(raw_ostream &, Scop &) const {}
+
+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(ScopInfo)
+INITIALIZE_PASS_END(DeadCodeElim, "polly-dce", "Polly - Remove dead iterations",
+                    false, false)
diff --git a/final/lib/Transform/IndependentBlocks.cpp b/final/lib/Transform/IndependentBlocks.cpp
new file mode 100644
index 0000000..104f51e
--- /dev/null
+++ b/final/lib/Transform/IndependentBlocks.cpp
@@ -0,0 +1,557 @@
+//===------ IndependentBlocks.cpp - Create Independent Blocks in Regions --===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Create independent blocks in the regions detected by ScopDetection.
+//
+//===----------------------------------------------------------------------===//
+//
+#include "polly/LinkAllPasses.h"
+#include "polly/CodeGen/BlockGenerators.h"
+#include "polly/Options.h"
+#include "polly/ScopDetection.h"
+#include "polly/Support/ScopHelper.h"
+#include "llvm/Analysis/DominanceFrontier.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/PostDominators.h"
+#include "llvm/Analysis/RegionInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Utils/Local.h"
+#include <vector>
+
+using namespace polly;
+using namespace llvm;
+
+#define DEBUG_TYPE "polly-independent"
+
+static cl::opt<bool> DisableIntraScopScalarToArray(
+    "disable-polly-intra-scop-scalar-to-array",
+    cl::desc("Do not rewrite scalar to array to generate independent blocks"),
+    cl::Hidden, cl::init(true), cl::cat(PollyCategory));
+
+namespace {
+struct IndependentBlocks : public FunctionPass {
+  RegionInfo *RI;
+  ScalarEvolution *SE;
+  ScopDetection *SD;
+  LoopInfo *LI;
+
+  BasicBlock *AllocaBlock;
+
+  static char ID;
+
+  IndependentBlocks() : FunctionPass(ID) {}
+
+  // Create new code for every instruction operator that can be expressed by a
+  // SCEV.  Like this there are just two types of instructions left:
+  //
+  // 1. Instructions that only reference loop ivs or parameters outside the
+  // region.
+  //
+  // 2. Instructions that are not used for any memory modification. (These
+  //    will be ignored later on.)
+  //
+  // Blocks containing only these kind of instructions are called independent
+  // blocks as they can be scheduled arbitrarily.
+  bool createIndependentBlocks(BasicBlock *BB, const Region *R);
+  bool createIndependentBlocks(const Region *R);
+
+  // Elimination on the Scop to eliminate the scalar dependences come with
+  // trivially dead instructions.
+  bool eliminateDeadCode(const Region *R);
+
+  //===--------------------------------------------------------------------===//
+  /// Non trivial scalar dependences checking functions.
+  /// Non trivial scalar dependences occur when the def and use are located in
+  /// different BBs and we can not move them into the same one. This will
+  /// prevent use from schedule BBs arbitrarily.
+  ///
+  /// @brief This function checks if a scalar value that is part of the
+  ///        Scop is used outside of the Scop.
+  ///
+  /// @param Use  The use of the instruction.
+  /// @param R    The maximum region in the Scop.
+  ///
+  /// @return Return true if the Use of an instruction and the instruction
+  ///         itself form a non trivial scalar dependence.
+  static bool isEscapeUse(const Value *Use, const Region *R);
+
+  /// @brief This function just checks if a Value is either defined in the same
+  ///        basic block or outside the region, such that there are no scalar
+  ///        dependences between basic blocks that are both part of the same
+  ///        region.
+  ///
+  /// @param Operand  The operand of the instruction.
+  /// @param CurBB    The BasicBlock that contains the instruction.
+  /// @param R        The maximum region in the Scop.
+  ///
+  /// @return Return true if the Operand of an instruction and the instruction
+  ///         itself form a non trivial scalar (true) dependence.
+  bool isEscapeOperand(const Value *Operand, const BasicBlock *CurBB,
+                       const Region *R) const;
+
+  //===--------------------------------------------------------------------===//
+  /// Operand tree moving functions.
+  /// Trivial scalar dependences can eliminate by move the def to the same BB
+  /// that containing use.
+  ///
+  /// @brief Check if the instruction can be moved to another place safely.
+  ///
+  /// @param Inst The instruction.
+  ///
+  /// @return Return true if the instruction can be moved safely, false
+  ///         otherwise.
+  static bool isSafeToMove(Instruction *Inst);
+
+  typedef std::map<Instruction *, Instruction *> ReplacedMapType;
+
+  /// @brief Move all safe to move instructions in the Operand Tree (DAG) to
+  ///        eliminate trivial scalar dependences.
+  ///
+  /// @param Inst         The root of the operand Tree.
+  /// @param R            The maximum region in the Scop.
+  /// @param ReplacedMap  The map that mapping original instruction to the moved
+  ///                     instruction.
+  /// @param InsertPos    The insert position of the moved instructions.
+  void moveOperandTree(Instruction *Inst, const Region *R,
+                       ReplacedMapType &ReplacedMap, Instruction *InsertPos);
+
+  bool isIndependentBlock(const Region *R, BasicBlock *BB) const;
+  bool areAllBlocksIndependent(const Region *R) const;
+
+  // Split the exit block to hold load instructions.
+  bool splitExitBlock(Region *R);
+  bool onlyUsedInRegion(Instruction *Inst, const Region *R);
+  bool translateScalarToArray(BasicBlock *BB, const Region *R);
+  bool translateScalarToArray(Instruction *Inst, const Region *R);
+  bool translateScalarToArray(const Region *R);
+
+  bool runOnFunction(Function &F);
+  void verifyAnalysis() const;
+  void verifyScop(const Region *R) const;
+  void getAnalysisUsage(AnalysisUsage &AU) const;
+};
+}
+
+bool IndependentBlocks::isSafeToMove(Instruction *Inst) {
+  if (Inst->mayReadFromMemory() || Inst->mayWriteToMemory())
+    return false;
+
+  return isSafeToSpeculativelyExecute(Inst);
+}
+
+void IndependentBlocks::moveOperandTree(Instruction *Inst, const Region *R,
+                                        ReplacedMapType &ReplacedMap,
+                                        Instruction *InsertPos) {
+  BasicBlock *CurBB = Inst->getParent();
+
+  // Depth first traverse the operand tree (or operand dag, because we will
+  // stop at PHINodes, so there are no cycle).
+  typedef Instruction::op_iterator ChildIt;
+  std::vector<std::pair<Instruction *, ChildIt>> WorkStack;
+
+  WorkStack.push_back(std::make_pair(Inst, Inst->op_begin()));
+  DenseSet<Instruction *> VisitedSet;
+
+  while (!WorkStack.empty()) {
+    Instruction *CurInst = WorkStack.back().first;
+    ChildIt It = WorkStack.back().second;
+    DEBUG(dbgs() << "Checking Operand of Node:\n" << *CurInst << "\n------>\n");
+    if (It == CurInst->op_end()) {
+      // Insert the new instructions in topological order.
+      if (!CurInst->getParent()) {
+        CurInst->insertBefore(InsertPos);
+        SE->forgetValue(CurInst);
+      }
+
+      WorkStack.pop_back();
+    } else {
+      // for each node N,
+      Instruction *Operand = dyn_cast<Instruction>(*It);
+      ++WorkStack.back().second;
+
+      // Can not move no instruction value.
+      if (Operand == 0)
+        continue;
+
+      DEBUG(dbgs() << "For Operand:\n" << *Operand << "\n--->");
+
+      // If the Scop Region does not contain N, skip it and all its operands and
+      // continue: because we reach a "parameter".
+      // FIXME: we must keep the predicate instruction inside the Scop,
+      // otherwise it will be translated to a load instruction, and we can not
+      // handle load as affine predicate at this moment.
+      if (!R->contains(Operand) && !isa<TerminatorInst>(CurInst)) {
+        DEBUG(dbgs() << "Out of region.\n");
+        continue;
+      }
+
+      if (canSynthesize(Operand, LI, SE, R)) {
+        DEBUG(dbgs() << "is IV.\n");
+        continue;
+      }
+
+      // We can not move the operand, a non trivial scalar dependence found!
+      if (!isSafeToMove(Operand)) {
+        DEBUG(dbgs() << "Can not move!\n");
+        continue;
+      }
+
+      // Do not need to move instruction if it is contained in the same BB with
+      // the root instruction.
+      if (Operand->getParent() == CurBB) {
+        DEBUG(dbgs() << "No need to move.\n");
+        // Try to move its operand, but do not visit an instuction twice.
+        if (VisitedSet.insert(Operand).second)
+          WorkStack.push_back(std::make_pair(Operand, Operand->op_begin()));
+        continue;
+      }
+
+      // Now we need to move Operand to CurBB.
+      // Check if we already moved it.
+      ReplacedMapType::iterator At = ReplacedMap.find(Operand);
+      if (At != ReplacedMap.end()) {
+        DEBUG(dbgs() << "Moved.\n");
+        Instruction *MovedOp = At->second;
+        It->set(MovedOp);
+        SE->forgetValue(MovedOp);
+      } else {
+        // Note that NewOp is not inserted in any BB now, we will insert it when
+        // it popped form the work stack, so it will be inserted in topological
+        // order.
+        Instruction *NewOp = Operand->clone();
+        NewOp->setName(Operand->getName() + ".moved.to." + CurBB->getName());
+        DEBUG(dbgs() << "Move to " << *NewOp << "\n");
+        It->set(NewOp);
+        ReplacedMap.insert(std::make_pair(Operand, NewOp));
+        SE->forgetValue(Operand);
+
+        // Process its operands, but do not visit an instuction twice.
+        if (VisitedSet.insert(NewOp).second)
+          WorkStack.push_back(std::make_pair(NewOp, NewOp->op_begin()));
+      }
+    }
+  }
+
+  SE->forgetValue(Inst);
+}
+
+bool IndependentBlocks::createIndependentBlocks(BasicBlock *BB,
+                                                const Region *R) {
+  std::vector<Instruction *> WorkList;
+  for (Instruction &Inst : *BB)
+    if (!isSafeToMove(&Inst) && !canSynthesize(&Inst, LI, SE, R))
+      WorkList.push_back(&Inst);
+
+  ReplacedMapType ReplacedMap;
+  Instruction *InsertPos = BB->getFirstNonPHIOrDbg();
+
+  for (Instruction *Inst : WorkList)
+    if (!isa<PHINode>(Inst))
+      moveOperandTree(Inst, R, ReplacedMap, InsertPos);
+
+  // The BB was changed if we replaced any operand.
+  return !ReplacedMap.empty();
+}
+
+bool IndependentBlocks::createIndependentBlocks(const Region *R) {
+  bool Changed = false;
+
+  for (BasicBlock *BB : R->blocks())
+    Changed |= createIndependentBlocks(BB, R);
+
+  return Changed;
+}
+
+bool IndependentBlocks::eliminateDeadCode(const Region *R) {
+  std::vector<Instruction *> WorkList;
+
+  // Find all trivially dead instructions.
+  for (BasicBlock *BB : R->blocks())
+    for (Instruction &Inst : *BB)
+      if (!isIgnoredIntrinsic(&Inst) && isInstructionTriviallyDead(&Inst))
+        WorkList.push_back(&Inst);
+
+  if (WorkList.empty())
+    return false;
+
+  // Delete them so the cross BB scalar dependences come with them will
+  // also be eliminated.
+  while (!WorkList.empty()) {
+    RecursivelyDeleteTriviallyDeadInstructions(WorkList.back());
+    WorkList.pop_back();
+  }
+
+  return true;
+}
+
+bool IndependentBlocks::isEscapeUse(const Value *Use, const Region *R) {
+  // Non-instruction user will never escape.
+  if (!isa<Instruction>(Use))
+    return false;
+
+  return !R->contains(cast<Instruction>(Use));
+}
+
+bool IndependentBlocks::isEscapeOperand(const Value *Operand,
+                                        const BasicBlock *CurBB,
+                                        const Region *R) const {
+  const Instruction *OpInst = dyn_cast<Instruction>(Operand);
+
+  // Non-instruction operand will never escape.
+  if (OpInst == 0)
+    return false;
+
+  // Induction variables are valid operands.
+  if (canSynthesize(OpInst, LI, SE, R))
+    return false;
+
+  // A value from a different BB is used in the same region.
+  return R->contains(OpInst) && (OpInst->getParent() != CurBB);
+}
+
+bool IndependentBlocks::splitExitBlock(Region *R) {
+  // Split the exit BB to place the load instruction of escaped users.
+  BasicBlock *ExitBB = R->getExit();
+  Region *ExitRegion = RI->getRegionFor(ExitBB);
+
+  if (ExitBB != ExitRegion->getEntry())
+    return false;
+
+  BasicBlock *NewExit = createSingleExitEdge(R, this);
+
+  std::vector<Region *> toUpdate;
+  toUpdate.push_back(R);
+
+  while (!toUpdate.empty()) {
+    Region *R = toUpdate.back();
+    toUpdate.pop_back();
+
+    for (auto &&SubRegion : *R)
+      if (SubRegion->getExit() == ExitBB)
+        toUpdate.push_back(SubRegion.get());
+
+    R->replaceExit(NewExit);
+  }
+
+  RI->setRegionFor(NewExit, R->getParent());
+  return true;
+}
+
+bool IndependentBlocks::translateScalarToArray(const Region *R) {
+  bool Changed = false;
+
+  for (BasicBlock *BB : R->blocks())
+    Changed |= translateScalarToArray(BB, R);
+
+  return Changed;
+}
+
+// Returns true when Inst is only used inside region R.
+bool IndependentBlocks::onlyUsedInRegion(Instruction *Inst, const Region *R) {
+  for (User *U : Inst->users())
+    if (Instruction *UI = dyn_cast<Instruction>(U))
+      if (isEscapeUse(UI, R))
+        return false;
+
+  return true;
+}
+
+bool IndependentBlocks::translateScalarToArray(Instruction *Inst,
+                                               const Region *R) {
+  if (canSynthesize(Inst, LI, SE, R) && onlyUsedInRegion(Inst, R))
+    return false;
+  if (isIgnoredIntrinsic(Inst))
+    return false;
+
+  SmallVector<Instruction *, 4> LoadInside, LoadOutside;
+  for (User *U : Inst->users())
+    // Inst is referenced outside or referenced as an escaped operand.
+    if (Instruction *UI = dyn_cast<Instruction>(U)) {
+      if (isEscapeUse(UI, R))
+        LoadOutside.push_back(UI);
+
+      if (DisableIntraScopScalarToArray)
+        continue;
+
+      if (canSynthesize(UI, LI, SE, R))
+        continue;
+
+      BasicBlock *UParent = UI->getParent();
+      if (R->contains(UParent) && isEscapeOperand(Inst, UParent, R))
+        LoadInside.push_back(UI);
+    }
+
+  if (LoadOutside.empty() && LoadInside.empty())
+    return false;
+
+  // Create the alloca.
+  AllocaInst *Slot = new AllocaInst(
+      Inst->getType(), 0, Inst->getName() + ".s2a", AllocaBlock->begin());
+  assert(!isa<InvokeInst>(Inst) && "Unexpect Invoke in Scop!");
+
+  // Store right after Inst, and make sure the position is after all phi nodes.
+  BasicBlock::iterator StorePos;
+  if (isa<PHINode>(Inst)) {
+    StorePos = Inst->getParent()->getFirstNonPHI();
+  } else {
+    StorePos = Inst;
+    StorePos++;
+  }
+  (void)new StoreInst(Inst, Slot, StorePos);
+
+  if (!LoadOutside.empty()) {
+    LoadInst *ExitLoad = new LoadInst(Slot, Inst->getName() + ".loadoutside",
+                                      false, R->getExit()->getFirstNonPHI());
+
+    while (!LoadOutside.empty()) {
+      Instruction *U = LoadOutside.pop_back_val();
+      SE->forgetValue(U);
+      U->replaceUsesOfWith(Inst, ExitLoad);
+    }
+  }
+
+  while (!LoadInside.empty()) {
+    Instruction *U = LoadInside.pop_back_val();
+    assert(!isa<PHINode>(U) && "Can not handle PHI node inside!");
+    SE->forgetValue(U);
+    LoadInst *L = new LoadInst(Slot, Inst->getName() + ".loadarray", false, U);
+    U->replaceUsesOfWith(Inst, L);
+  }
+
+  SE->forgetValue(Inst);
+  return true;
+}
+
+bool IndependentBlocks::translateScalarToArray(BasicBlock *BB,
+                                               const Region *R) {
+  bool changed = false;
+
+  SmallVector<Instruction *, 32> Insts;
+  for (BasicBlock::iterator II = BB->begin(), IE = --BB->end(); II != IE; ++II)
+    Insts.push_back(II);
+
+  while (!Insts.empty()) {
+    Instruction *Inst = Insts.pop_back_val();
+    changed |= translateScalarToArray(Inst, R);
+  }
+
+  return changed;
+}
+
+bool IndependentBlocks::isIndependentBlock(const Region *R,
+                                           BasicBlock *BB) const {
+  for (Instruction &Inst : *BB) {
+    if (canSynthesize(&Inst, LI, SE, R))
+      continue;
+    if (isIgnoredIntrinsic(&Inst))
+      continue;
+
+    // A value inside the Scop is referenced outside.
+    for (User *U : Inst.users()) {
+      if (isEscapeUse(U, R)) {
+        DEBUG(dbgs() << "Instruction not independent:\n");
+        DEBUG(dbgs() << "Instruction used outside the Scop!\n");
+        DEBUG(Inst.print(dbgs()));
+        DEBUG(dbgs() << "\n");
+        return false;
+      }
+    }
+
+    if (DisableIntraScopScalarToArray)
+      continue;
+
+    for (Value *Op : Inst.operands()) {
+      if (isIgnoredIntrinsic(Op))
+        continue;
+      if (isEscapeOperand(Op, BB, R)) {
+        DEBUG(dbgs() << "Instruction in function '";
+              BB->getParent()->printAsOperand(dbgs(), false);
+              dbgs() << "' not independent:\n");
+        DEBUG(dbgs() << "Uses invalid operator\n");
+        DEBUG(Inst.print(dbgs()));
+        DEBUG(dbgs() << "\n");
+        DEBUG(dbgs() << "Invalid operator is: ";
+              Op->printAsOperand(dbgs(), false); dbgs() << "\n");
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool IndependentBlocks::areAllBlocksIndependent(const Region *R) const {
+  for (BasicBlock *BB : R->blocks())
+    if (!isIndependentBlock(R, BB))
+      return false;
+
+  return true;
+}
+
+void IndependentBlocks::getAnalysisUsage(AnalysisUsage &AU) const {
+  // FIXME: If we set preserves cfg, the cfg only passes do not need to
+  // be "addPreserved"?
+  AU.addPreserved<DominatorTreeWrapperPass>();
+  AU.addPreserved<DominanceFrontier>();
+  AU.addPreserved<PostDominatorTree>();
+  AU.addRequired<RegionInfoPass>();
+  AU.addPreserved<RegionInfoPass>();
+  AU.addRequired<LoopInfoWrapperPass>();
+  AU.addPreserved<LoopInfoWrapperPass>();
+  AU.addRequired<ScalarEvolution>();
+  AU.addPreserved<ScalarEvolution>();
+  AU.addRequired<ScopDetection>();
+  AU.addPreserved<ScopDetection>();
+}
+
+bool IndependentBlocks::runOnFunction(llvm::Function &F) {
+
+  bool Changed = false;
+
+  RI = &getAnalysis<RegionInfoPass>().getRegionInfo();
+  LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+  SD = &getAnalysis<ScopDetection>();
+  SE = &getAnalysis<ScalarEvolution>();
+
+  AllocaBlock = &F.getEntryBlock();
+
+  DEBUG(dbgs() << "Run IndepBlock on " << F.getName() << '\n');
+
+  for (const Region *R : *SD) {
+    Changed |= createIndependentBlocks(R);
+    Changed |= eliminateDeadCode(R);
+  }
+
+  verifyAnalysis();
+
+  return Changed;
+}
+
+void IndependentBlocks::verifyAnalysis() const {}
+
+void IndependentBlocks::verifyScop(const Region *R) const {
+  assert(areAllBlocksIndependent(R) && "Cannot generate independent blocks");
+}
+
+char IndependentBlocks::ID = 0;
+char &polly::IndependentBlocksID = IndependentBlocks::ID;
+
+Pass *polly::createIndependentBlocksPass() { return new IndependentBlocks(); }
+
+INITIALIZE_PASS_BEGIN(IndependentBlocks, "polly-independent",
+                      "Polly - Create independent blocks", false, false);
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
+INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
+INITIALIZE_PASS_DEPENDENCY(ScalarEvolution);
+INITIALIZE_PASS_DEPENDENCY(ScopDetection);
+INITIALIZE_PASS_END(IndependentBlocks, "polly-independent",
+                    "Polly - Create independent blocks", false, false)
diff --git a/final/lib/Transform/ScheduleOptimizer.cpp b/final/lib/Transform/ScheduleOptimizer.cpp
new file mode 100644
index 0000000..43ed278
--- /dev/null
+++ b/final/lib/Transform/ScheduleOptimizer.cpp
@@ -0,0 +1,527 @@
+//===- 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 the isl to calculate a schedule that is optimized for parallelism
+// and tileablility. The algorithm used in isl is an optimized version of the
+// algorithm described in following paper:
+//
+// 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.
+//===----------------------------------------------------------------------===//
+
+#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/Support/GICHelper.h"
+#include "llvm/Support/Debug.h"
+#include "isl/aff.h"
+#include "isl/band.h"
+#include "isl/constraint.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"
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-opt-isl"
+
+namespace polly {
+bool DisablePollyTiling;
+}
+static cl::opt<bool, true>
+    DisableTiling("polly-no-tiling",
+                  cl::desc("Disable tiling in the scheduler"),
+                  cl::location(polly::DisablePollyTiling), cl::init(false),
+                  cl::ZeroOrMore, cl::cat(PollyCategory));
+
+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<int> DefaultTileSize(
+    "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> TileSizes("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));
+namespace {
+
+class IslScheduleOptimizer : public ScopPass {
+public:
+  static char ID;
+  explicit IslScheduleOptimizer() : ScopPass(ID) { LastSchedule = nullptr; }
+
+  ~IslScheduleOptimizer() { isl_schedule_free(LastSchedule); }
+
+  bool runOnScop(Scop &S) override;
+  void printScop(raw_ostream &OS, Scop &S) const override;
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  isl_schedule *LastSchedule;
+
+  /// @brief 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.
+  bool isProfitableSchedule(Scop &S, __isl_keep isl_union_map *NewSchedule);
+
+  /// @brief Create a map that pre-vectorizes one scheduling dimension.
+  ///
+  /// getPrevectorMap creates a map that maps each input dimension to the same
+  /// output dimension, except for the dimension DimToVectorize.
+  /// DimToVectorize is strip mined by 'VectorWidth' and the newly created
+  /// point loop of DimToVectorize is moved to the innermost level.
+  ///
+  /// Example (DimToVectorize=0, ScheduleDimensions=2, VectorWidth=4):
+  ///
+  /// | Before transformation
+  /// |
+  /// | A[i,j] -> [i,j]
+  /// |
+  /// | for (i = 0; i < 128; i++)
+  /// |    for (j = 0; j < 128; j++)
+  /// |      A(i,j);
+  ///
+  ///   Prevector map:
+  ///   [i,j] -> [it,j,ip] : it % 4 = 0 and it <= ip <= it + 3 and i = ip
+  ///
+  /// | After transformation:
+  /// |
+  /// | A[i,j] -> [it,j,ip] : it % 4 = 0 and it <= ip <= it + 3 and i = ip
+  /// |
+  /// | for (it = 0; it < 128; it+=4)
+  /// |    for (j = 0; j < 128; j++)
+  /// |      for (ip = max(0,it); ip < min(128, it + 3); ip++)
+  /// |        A(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_give isl_map *getPrevectorMap(isl_ctx *ctx, int DimToVectorize,
+                                             int ScheduleDimensions,
+                                             int VectorWidth = 4);
+
+  /// @brief 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 point loop of the tile
+  ///      - 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);
+
+  /// @brief Apply post-scheduling transformations.
+  ///
+  /// This function applies a set of additional local transformations on the
+  /// schedule tree as it computed by the isl scheduler. Local transformations
+  /// applied include:
+  ///
+  ///   - Tiling
+  ///   - Prevectorization
+  ///
+  /// @param Schedule The schedule object post-transformations will be applied
+  ///                 on.
+  /// @returns        The transformed schedule.
+  static __isl_give isl_schedule *
+  addPostTransforms(__isl_take isl_schedule *Schedule);
+
+  using llvm::Pass::doFinalization;
+
+  virtual bool doFinalization() override {
+    isl_schedule_free(LastSchedule);
+    LastSchedule = nullptr;
+    return true;
+  }
+};
+}
+
+char IslScheduleOptimizer::ID = 0;
+
+__isl_give isl_map *
+IslScheduleOptimizer::getPrevectorMap(isl_ctx *ctx, int DimToVectorize,
+                                      int ScheduleDimensions, int VectorWidth) {
+  isl_space *Space;
+  isl_local_space *LocalSpace, *LocalSpaceRange;
+  isl_set *Modulo;
+  isl_map *TilingMap;
+  isl_constraint *c;
+  isl_aff *Aff;
+  int PointDimension; /* ip */
+  int TileDimension;  /* it */
+  isl_val *VectorWidthMP;
+
+  assert(0 <= DimToVectorize && DimToVectorize < ScheduleDimensions);
+
+  Space = isl_space_alloc(ctx, 0, ScheduleDimensions, ScheduleDimensions + 1);
+  TilingMap = isl_map_universe(isl_space_copy(Space));
+  LocalSpace = isl_local_space_from_space(Space);
+  PointDimension = ScheduleDimensions;
+  TileDimension = DimToVectorize;
+
+  // Create an identity map for everything except DimToVectorize and map
+  // DimToVectorize to the point loop at the innermost dimension.
+  for (int i = 0; i < ScheduleDimensions; i++)
+    if (i == DimToVectorize)
+      TilingMap =
+          isl_map_equate(TilingMap, isl_dim_in, i, isl_dim_out, PointDimension);
+    else
+      TilingMap = isl_map_equate(TilingMap, isl_dim_in, i, isl_dim_out, i);
+
+  // it % 'VectorWidth' = 0
+  LocalSpaceRange = isl_local_space_range(isl_local_space_copy(LocalSpace));
+  Aff = isl_aff_zero_on_domain(LocalSpaceRange);
+  Aff = isl_aff_set_constant_si(Aff, VectorWidth);
+  Aff = isl_aff_set_coefficient_si(Aff, isl_dim_in, TileDimension, 1);
+  VectorWidthMP = isl_val_int_from_si(ctx, VectorWidth);
+  Aff = isl_aff_mod_val(Aff, VectorWidthMP);
+  Modulo = isl_pw_aff_zero_set(isl_pw_aff_from_aff(Aff));
+  TilingMap = isl_map_intersect_range(TilingMap, Modulo);
+
+  // it <= ip
+  TilingMap = isl_map_order_le(TilingMap, isl_dim_out, TileDimension,
+                               isl_dim_out, PointDimension);
+
+  // ip <= it + ('VectorWidth' - 1)
+  c = isl_inequality_alloc(LocalSpace);
+  isl_constraint_set_coefficient_si(c, isl_dim_out, TileDimension, 1);
+  isl_constraint_set_coefficient_si(c, isl_dim_out, PointDimension, -1);
+  isl_constraint_set_constant_si(c, VectorWidth - 1);
+  TilingMap = isl_map_add_constraint(TilingMap, c);
+
+  return TilingMap;
+}
+
+isl_schedule_node *IslScheduleOptimizer::optimizeBand(isl_schedule_node *Node,
+                                                      void *User) {
+  if (isl_schedule_node_get_type(Node) != isl_schedule_node_band)
+    return Node;
+
+  if (isl_schedule_node_n_children(Node) != 1)
+    return Node;
+
+  if (!isl_schedule_node_band_get_permutable(Node))
+    return Node;
+
+  auto Space = isl_schedule_node_band_get_space(Node);
+  auto Dims = isl_space_dim(Space, isl_dim_set);
+
+  if (Dims <= 1) {
+    isl_space_free(Space);
+    return Node;
+  }
+
+  auto Child = isl_schedule_node_get_child(Node, 0);
+  auto Type = isl_schedule_node_get_type(Child);
+  isl_schedule_node_free(Child);
+
+  if (Type != isl_schedule_node_leaf) {
+    isl_space_free(Space);
+    return Node;
+  }
+
+  auto Sizes = isl_multi_val_zero(Space);
+  auto Ctx = isl_schedule_node_get_ctx(Node);
+
+  for (unsigned i = 0; i < Dims; i++) {
+    auto tileSize = TileSizes.size() > i ? TileSizes[i] : DefaultTileSize;
+    Sizes = isl_multi_val_set_val(Sizes, i, isl_val_int_from_si(Ctx, tileSize));
+  }
+
+  isl_schedule_node *Res;
+
+  if (DisableTiling) {
+    isl_multi_val_free(Sizes);
+    Res = Node;
+  } else {
+    Res = isl_schedule_node_band_tile(Node, Sizes);
+  }
+
+  if (PollyVectorizerChoice == VECTORIZER_NONE)
+    return Res;
+
+  Child = isl_schedule_node_get_child(Res, 0);
+  auto ChildSchedule = isl_schedule_node_band_get_partial_schedule(Child);
+
+  for (int i = Dims - 1; i >= 0; i--) {
+    if (isl_schedule_node_band_member_get_coincident(Child, i)) {
+      auto TileMap = IslScheduleOptimizer::getPrevectorMap(Ctx, i, Dims);
+      auto TileUMap = isl_union_map_from_map(TileMap);
+      auto ChildSchedule2 = isl_union_map_apply_range(
+          isl_union_map_from_multi_union_pw_aff(ChildSchedule), TileUMap);
+      ChildSchedule = isl_multi_union_pw_aff_from_union_map(ChildSchedule2);
+      break;
+    }
+  }
+
+  isl_schedule_node_free(Res);
+  Res = isl_schedule_node_delete(Child);
+  Res = isl_schedule_node_insert_partial_schedule(Res, ChildSchedule);
+  return Res;
+}
+
+__isl_give isl_schedule *
+IslScheduleOptimizer::addPostTransforms(__isl_take isl_schedule *Schedule) {
+  isl_schedule_node *Root = isl_schedule_get_root(Schedule);
+  isl_schedule_free(Schedule);
+  Root = isl_schedule_node_map_descendant_bottom_up(
+      Root, IslScheduleOptimizer::optimizeBand, NULL);
+  auto S = isl_schedule_node_get_schedule(Root);
+  isl_schedule_node_free(Root);
+  return S;
+}
+
+bool IslScheduleOptimizer::isProfitableSchedule(
+    Scop &S, __isl_keep isl_union_map *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)
+  isl_union_map *OldSchedule = S.getSchedule();
+  bool changed = !isl_union_map_is_equal(OldSchedule, NewSchedule);
+  isl_union_map_free(OldSchedule);
+  return changed;
+}
+
+bool IslScheduleOptimizer::runOnScop(Scop &S) {
+
+  // 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();
+
+  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;
+
+  isl_union_map *Validity = D.getDependences(ValidityKinds);
+  isl_union_map *Proximity = 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 = isl_union_map_gist_domain(Validity, isl_union_set_copy(Domain));
+    Validity = isl_union_map_gist_range(Validity, isl_union_set_copy(Domain));
+    Proximity =
+        isl_union_map_gist_domain(Proximity, isl_union_set_copy(Domain));
+    Proximity = isl_union_map_gist_range(Proximity, isl_union_set_copy(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 := " << stringFromIslObj(Domain) << ";\n");
+  DEBUG(dbgs() << "Proximity := " << stringFromIslObj(Proximity) << ";\n");
+  DEBUG(dbgs() << "Validity := " << stringFromIslObj(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;
+  }
+
+  isl_options_set_schedule_serialize_sccs(S.getIslCtx(), IslSerializeSCCs);
+  isl_options_set_schedule_maximize_band_depth(S.getIslCtx(), IslMaximizeBands);
+  isl_options_set_schedule_max_constant_term(S.getIslCtx(), MaxConstantTerm);
+  isl_options_set_schedule_max_coefficient(S.getIslCtx(), MaxCoefficient);
+  isl_options_set_tile_scale_tile_loops(S.getIslCtx(), 0);
+
+  isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_CONTINUE);
+
+  isl_schedule_constraints *ScheduleConstraints;
+  ScheduleConstraints = isl_schedule_constraints_on_domain(Domain);
+  ScheduleConstraints =
+      isl_schedule_constraints_set_proximity(ScheduleConstraints, Proximity);
+  ScheduleConstraints = isl_schedule_constraints_set_validity(
+      ScheduleConstraints, isl_union_map_copy(Validity));
+  ScheduleConstraints =
+      isl_schedule_constraints_set_coincidence(ScheduleConstraints, Validity);
+  isl_schedule *Schedule;
+  Schedule = isl_schedule_constraints_compute_schedule(ScheduleConstraints);
+  isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_ABORT);
+
+  // In cases the scheduler is not able to optimize the code, we just do not
+  // touch the schedule.
+  if (!Schedule)
+    return false;
+
+  DEBUG({
+    auto *P = isl_printer_to_str(S.getIslCtx());
+    P = isl_printer_set_yaml_style(P, ISL_YAML_STYLE_BLOCK);
+    P = isl_printer_print_schedule(P, Schedule);
+    dbgs() << "NewScheduleTree: \n" << isl_printer_get_str(P) << "\n";
+    isl_printer_free(P);
+  });
+
+  isl_schedule *NewSchedule = addPostTransforms(Schedule);
+  isl_union_map *NewScheduleMap = isl_schedule_get_map(NewSchedule);
+
+  if (!isProfitableSchedule(S, NewScheduleMap)) {
+    isl_union_map_free(NewScheduleMap);
+    isl_schedule_free(NewSchedule);
+    return false;
+  }
+
+  S.setScheduleTree(NewSchedule);
+  S.markAsOptimized();
+
+  isl_union_map_free(NewScheduleMap);
+  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>();
+}
+
+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(ScopInfo);
+INITIALIZE_PASS_END(IslScheduleOptimizer, "polly-opt-isl",
+                    "Polly - Optimize schedule of SCoP", false, false)
diff --git a/final/test/CMakeLists.txt b/final/test/CMakeLists.txt
new file mode 100644
index 0000000..4075f0a
--- /dev/null
+++ b/final/test/CMakeLists.txt
@@ -0,0 +1,87 @@
+set(POLLY_TEST_DIRECTORIES
+  "AffineIterator"
+  "ScopInfo"
+  "ScheduleOptimizer"
+  "CodeGen"
+  "OpenMP"
+  "polybench"
+  "vect")
+
+
+set(POLLY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
+set(POLLY_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/..")
+set(LLVM_SHLIBEXT "${CMAKE_SHARED_MODULE_SUFFIX}")
+
+if (NOT DEFINED LLVM_MAIN_SRC_DIR)
+
+  # We are building polly out of tree, adjust the settings.
+  # FIXME: FileCheck is not available in llvm install directory at the moment.
+  set(LLVM_LIT ${LLVM_INSTALL_ROOT}/bin/llvm-lit)
+  set(POLLY_TEST_DEPS LLVMPolly)
+
+  set(LLVM_BINARY_DIR "${LLVM_INSTALL_ROOT}")
+  set(LLVM_TOOLS_DIR "${LLVM_INSTALL_ROOT}/bin")
+  set(LLVM_LIBS_DIR "${LLVM_INSTALL_ROOT}/lib")
+  set(POLLY_LIB_DIR "${POLLY_BINARY_DIR}/lib")
+
+  include(FindPythonInterp)
+  if(PYTHONINTERP_FOUND)
+    option(POLLY_TEST_DISABLE_BAR "Run Polly tests with --no-progress-bar" OFF)
+    set(POLLY_TEST_EXTRA_ARGS)
+    if (MSVC OR XCODE OR POLLY_TEST_DISABLE_BAR)
+      set(POLLY_TEST_EXTRA_ARGS "--no-progress-bar")
+    endif()
+
+    option(POLLY_TEST_USE_VG "Run Polly tests under Valgrind" OFF)
+    if(POLLY_TEST_USE_VG)
+      set(POLLY_TEST_EXTRA_ARGS ${POLLY_TEST_EXTRA_ARGS} "--vg")
+    endif ()
+
+    foreach(testdir ${POLLY_TEST_DIRECTORIES})
+      add_custom_target(polly-test-${testdir}
+        COMMAND ${LLVM_LIT}
+                    --param polly_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+                    --param build_config=${CMAKE_CFG_INTDIR}
+                    -sv ${POLLY_TEST_EXTRA_ARGS}
+                    ${CMAKE_CURRENT_BINARY_DIR}/${testdir}
+                    DEPENDS ${POLLY_TEST_DEPS}
+                    COMMENT "Running Polly regression tests in ${testdir}")
+    endforeach()
+
+    add_custom_target(check-polly
+      COMMAND ${LLVM_LIT}
+                  --param polly_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+                  --param build_config=${CMAKE_CFG_INTDIR}
+                  -sv ${POLLY_TEST_EXTRA_ARGS}
+                  ${CMAKE_CURRENT_BINARY_DIR}
+                  DEPENDS ${POLLY_TEST_DEPS}
+                  COMMENT "Running Polly regression tests")
+  endif()
+
+else (NOT DEFINED LLVM_MAIN_SRC_DIR)
+
+  set(LLVM_LIT ${LLVM_TOOLS_BINARY_DIR}/llvm-lit)
+  set(POLLY_TEST_DEPS llvm-config opt LLVMPolly FileCheck not)
+
+  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 "${LLVM_LIBS_DIR}")
+
+  add_lit_testsuite(check-polly "Running polly regression tests"
+    ${CMAKE_CURRENT_BINARY_DIR}
+    PARAMS polly_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+    DEPENDS ${POLLY_TEST_DEPS}
+    )
+
+  set_target_properties(check-polly PROPERTIES FOLDER "polly tests")
+
+endif (NOT DEFINED LLVM_MAIN_SRC_DIR)
+
+configure_file(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
+
+# Add a legacy target spelling: polly-test
+add_custom_target(polly-test)
+add_dependencies(polly-test check-polly)
diff --git a/final/test/DeadCodeElimination/chained_iterations.ll b/final/test/DeadCodeElimination/chained_iterations.ll
new file mode 100644
index 0000000..d6aa3b0
--- /dev/null
+++ b/final/test/DeadCodeElimination/chained_iterations.ll
@@ -0,0 +1,61 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences-analysis-type=value-based -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-ast -analyze -polly-no-early-exit < %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..d2cbe78
--- /dev/null
+++ b/final/test/DeadCodeElimination/chained_iterations_2.ll
@@ -0,0 +1,65 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences-analysis-type=value-based -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-ast -analyze -polly-no-early-exit < %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..cd5fbea
--- /dev/null
+++ b/final/test/DeadCodeElimination/computeout.ll
@@ -0,0 +1,63 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dce -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dce -polly-ast -analyze -polly-no-early-exit -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..6d0f8c5
--- /dev/null
+++ b/final/test/DeadCodeElimination/dead_iteration_elimination.ll
@@ -0,0 +1,78 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-dce-precise-steps=2 -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s -check-prefix=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"
+;
+; 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..ffe5cb0
--- /dev/null
+++ b/final/test/DeadCodeElimination/non-affine-affine-mix.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-allow-nonaffine -polly-dce -polly-ast -analyze -polly-no-early-exit < %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..8505ea5
--- /dev/null
+++ b/final/test/DeadCodeElimination/non-affine.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-allow-nonaffine -polly-dce -polly-ast -analyze -polly-no-early-exit < %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..ff0bbd7
--- /dev/null
+++ b/final/test/DeadCodeElimination/null_schedule.ll
@@ -0,0 +1,56 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences-analysis-type=value-based -polly-dce -polly-ast -analyze -polly-no-early-exit < %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..b864943
--- /dev/null
+++ b/final/test/DependenceInfo/computeout.ll
@@ -0,0 +1,71 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s -check-prefix=VALUE
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -polly-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: region: 'S1 => exit.3' in function 'sequential_writes':
+; VALUE:   RAW dependences:
+; VALUE:     {  }
+; VALUE:   WAR dependences:
+; VALUE:     {  }
+; VALUE:   WAW dependences:
+; VALUE:     {
+; VALUE:       Stmt_S1[i0] -> Stmt_S2[i0] : i0 >= 0 and i0 <= 9;
+; VALUE:       Stmt_S2[i0] -> Stmt_S3[i0] : i0 >= 0 and i0 <= 9;
+; VALUE:       Stmt_S1[i0] -> Stmt_S3[i0] : i0 >= 10 and i0 <= 99
+; VALUE:     }
+
+; TIMEOUT: region: 'S1 => exit.3' in function 'sequential_writes':
+; TIMEOUT:   RAW dependences:
+; TIMEOUT:     n/a
+; TIMEOUT:   WAR dependences:
+; TIMEOUT:     n/a
+; TIMEOUT:   WAW dependences:
+; TIMEOUT:     n/a
diff --git a/final/test/DependenceInfo/do_pluto_matmult.ll b/final/test/DependenceInfo/do_pluto_matmult.ll
new file mode 100644
index 0000000..efdef08
--- /dev/null
+++ b/final/test/DependenceInfo/do_pluto_matmult.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=value-based < %s | FileCheck %s -check-prefix=VALUE
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=memory-based -polly-delinearize < %s | FileCheck %s -check-prefix=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: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : i0 >= 0 and i0 <= 35 and i1 >= 0 and i1 <= 35 and i2 >= 0 and i2 <= 34 }
+; VALUE: WAR dependences:
+; VALUE: {  }
+; VALUE: WAW dependences:
+; VALUE: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, 1 + i2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 <= 34 and i2 >= 0 }
+
+
+; MEMORY: RAW dependences:
+; MEMORY:  { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 and o2 >= 0 }
+; MEMORY: WAR dependences:
+; MEMORY:  { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 and o2 >= 0 }
+; MEMORY: WAW dependences:
+; MEMORY:  { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 and o2 >= 0 }
diff --git a/final/test/DependenceInfo/reduction_complex_location.ll b/final/test/DependenceInfo/reduction_complex_location.ll
new file mode 100644
index 0000000..8ae27fe
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_complex_location.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK:   { Stmt_for_body3[i0, i1] -> Stmt_for_body3[2 + i0, -1 + i1] : i0 <= 97 and i0 >= 0 and i1 <= 99 and i1 >= 1 }
+;
+; 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..5e23534
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_dependences_equal_non_reduction_dependences.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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:   { Stmt_for_body[i0] -> Stmt_for_body[1 + i0] : i0 >= 0 and i0 <= 1022 }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   { Stmt_for_body[i0] -> Stmt_for_body[1 + i0] : i0 <= 1022 and i0 >= 0 }
+; CHECK: Reduction dependences:
+; CHECK:   { Stmt_for_body[i0] -> Stmt_for_body[1 + i0] : i0 <= 1022 and i0 >= 0 }
+;
+;
+;    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_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..9c1d77a
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_mixed_reduction_and_non_reduction_dependences.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK: RAW dependences:
+; CHECK-DAG: Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0 + i1, o1] : i1 <= 1023 - i0 and i1 >= 0 and i1 <= 1 and i0 >= 0 and o1 <= 511 and o1 >= 1 
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK-DAG: Stmt_for_body3[i0, i1] -> Stmt_for_body3[1 + i0, -1 + i1] : i0 <= 1022 and i0 >= 0 and i1 <= 511 and i1 >= 2
+; CHECK-DAG: Stmt_for_body3[i0, 2] -> Stmt_for_body3[2 + i0, 0] : i0 <= 1021 and i0 >= 0
+; CHECK: Reduction dependences:
+; CHECK:   { Stmt_for_body3[i0, 1] -> Stmt_for_body3[1 + i0, 0] : i0 <= 1022 and i0 >= 0 }
+;
+; 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..e698040
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_loops_array_sum.ll
@@ -0,0 +1,77 @@
+; RUN: opt -basicaa %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; Verify that only the inner reduction like accesses cause reduction dependences
+;
+; CHECK: Reduction dependences:
+; CHECK:   { Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0, 1 + i1] : i0 <= 99 and i0 >= 0 and i1 <= 98 and i1 >= 0 }
+;
+; 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..b2897d3
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_loops_array_sum_2.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze -basicaa < %s | FileCheck %s
+;
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK-DAG: Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0, 1 + i1] : i0 <= 99 and i0 >= 0 and i1 <= 98 and i1 >= 0
+; CHECK-DAG: Stmt_for_body3[i0, 99] -> Stmt_for_body3[1 + i0, 0] : i0 <= 98 and i0 >= 0
+;
+; 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..054bab7
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_loops_array_sum_3.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze -basicaa < %s | FileCheck %s
+;
+; CHECK: Reduction dependences:
+; CHECK:   { Stmt_for_inc[i0, i1] -> Stmt_for_inc[i0, 1 + i1] : i0 <= 99 and i0 >= 0 and i1 <= 98 and i1 >= 0 }
+;
+; 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..c023b2a
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_reductions.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences -analyze < %s | FileCheck %s
+;
+; Verify we do not have dependences between the if and the else clause
+;
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK-DAG: Stmt_if_then[i0] -> Stmt_if_then[1 + i0] : i0 <= 510 and i0 >= 0
+; CHECK-DAG: Stmt_if_else[i0] -> Stmt_if_else[1 + i0] : i0 <= 1022 and i0 >= 512
+;
+; 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..812a20e
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_multiple_reductions_2.ll
@@ -0,0 +1,110 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK: RAW dependences:
+; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S3[i0] : i0 <= 1023 and i0 >= 0 and i1 <= 1023 and i1 >= 0
+; CHECK-DAG: Stmt_S3[i0] -> Stmt_S0[1 + i0] : i0 <= 1022 and i0 >= 0
+; CHECK-DAG: Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
+; These are the important RAW dependences, as they need to originate/end in only one iteration:
+; CHECK-DAG: Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
+; CHECK-DAG: Stmt_S1[i0, i1] -> Stmt_S2[i0, 0] : i0 <= 1023 and i0 >= 0 and i1 <= 1022 and i1 >= 0
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK-DAG: Stmt_S2[i0, i1] -> Stmt_S3[i0] : i0 <= 1023 and i0 >= 0 and i1 <= 1023 and i1 >= 0
+; CHECK-DAG: Stmt_S3[i0] -> Stmt_S0[1 + i0] : i0 <= 1022 and i0 >= 0
+; CHECK-DAG: Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
+; These are the important WAW dependences, as they need to originate/end in only one iteration:
+; CHECK-DAG: Stmt_S1[i0, 1023] -> Stmt_S2[i0, o1] : i0 <= 1023 and i0 >= 0 and o1 <= 1023 and o1 >= 0
+; CHECK-DAG: Stmt_S1[i0, i1] -> Stmt_S2[i0, 0] : i0 <= 1023 and i0 >= 0 and i1 <= 1022 and i1 >= 0
+; CHECK: Reduction dependences:
+; CHECK-DAG:  Stmt_S1[i0, i1] -> Stmt_S1[i0, 1 + i1] : i0 <= 1023 and i0 >= 0 and i1 <= 1022 and i1 >= 0
+; CHECK-DAG:  Stmt_S2[i0, i1] -> Stmt_S2[i0, 1 + i1] : i0 <= 1023 and i0 >= 0 and i1 <= 1022 and i1 >= 0
+;
+;    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..fcf1e8b
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_only_reduction_like_access.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..063aef3
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_partially_escaping_intermediate_in_other_stmt.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze -basicaa < %s | FileCheck %s
+;
+; CHECK: Reduction dependences:
+; CHECK:   [N] -> { Stmt_for_body3[i0, i1] -> Stmt_for_body3[i0, 1 + i1] : i0 <= 1023 and i0 >= 0 and i1 <= 1022 and i1 >= 0 and i1 >= 1024 - N + i0 }
+;
+; 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..d6e0fb9
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps.ll
@@ -0,0 +1,111 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-DAG:    Stmt_S0[i0] -> Stmt_S1[o0, i0 - o0] : i0 <= 1023 and o0 >= 0 and o0 <= i0
+; CHECK-DAG:     Stmt_S1[i0, i1] -> Stmt_S2[-1 + i0 + i1] : i1 <= 1023 and i1 >= 0 and i1 >= 1 - i0 and i0 >= 0 and i0 <= 1023 and i1 <= 1024 - i0 
+; CHECK:      WAR dependences:
+; CHECK-DAG:    Stmt_S2[i0] -> Stmt_S2[1 + i0] : i0 <= 1022 and i0 >= 0
+; CHECK-DAG:    Stmt_S1[i0, i1] -> Stmt_S2[i0 + i1] : i1 <= 1023 - i0 and i1 >= 0 and i1 >= 1 - i0 and i0 >= 0 }
+; CHECK:      WAW dependences:
+; CHECK-DAG:    Stmt_S0[i0] -> Stmt_S1[o0, i0 - o0] : i0 <= 1023 and o0 >= 0 and o0 <= i0
+; CHECK-DAG:    Stmt_S1[0, 0] -> Stmt_S2[0]
+; CHECK:      Reduction dependences:
+; CHECK-DAG:    Stmt_S1[i0, i1] -> Stmt_S1[1 + i0, -1 + i1] : i0 <= 1022 and i0 >= 0 and i1 <= 1023 and i1 >= 1
+;
+;    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..aaee4af
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_2.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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-DAG:  Stmt_S3[i0] -> Stmt_S2[1 + i0, o1] : i0 <= 97 and i0 >= 0 and o1 <= 99 and o1 >= 0
+;  CHECK-DAG:  Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
+;  CHECK: WAR dependences:
+;  CHECK:   {  }
+;  CHECK: WAW dependences:
+;  CHECK-DAG:  Stmt_S3[i0] -> Stmt_S2[1 + i0, o1] : i0 <= 97 and i0 >= 0 and o1 <= 99 and o1 >= 0
+;  CHECK-DAG:  Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
+;  CHECK: Reduction dependences:
+;  CHECK:   { Stmt_S2[i0, i1] -> Stmt_S2[i0, 1 + i1] : i0 <= 98 and i0 >= 0 and i1 <= 98 and i1 >= 0 }
+;
+;    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..6c34c08
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_3.ll
@@ -0,0 +1,87 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+;  CHECK: RAW dependences:
+;  CHECK-DAG:  Stmt_S2[i0, i1] -> Stmt_S3[o0] : o0 <= 1 and i1 <= 1 - i0 and o0 <= 1 + i0 - i1 and o0 >= 1 - i1
+;  CHECK-DAG:  Stmt_S3[i0] -> Stmt_S2[o0, 1 - i0] : i0 <= 1 and i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
+;  CHECK-DAG:  Stmt_S1[i0] -> Stmt_S3[2 + i0] : i0 <= 96 and i0 >= 0
+;  CHECK: WAR dependences:
+;  CHECK:   {  }
+;  CHECK: WAW dependences:
+;  CHECK-DAG:  Stmt_S2[i0, i1] -> Stmt_S3[o0] : o0 <= 1 and i1 <= 1 - i0 and o0 <= 1 + i0 - i1 and o0 >= 1 - i1
+;  CHECK-DAG:  Stmt_S3[i0] -> Stmt_S2[o0, 1 - i0] : i0 <= 1 and i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
+;  CHECK-DAG:  Stmt_S1[i0] -> Stmt_S3[2 + i0] : i0 <= 96 and i0 >= 0
+;  CHECK: Reduction dependences:
+;  CHECK-DAG:  Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : i0 <= 97 and i0 >= 0 and i1 <= 98 - i0 and i1 >= 0 and i1 >= 2 - i0
+;  CHECK-DAG:  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..a65ea9a
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_4.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:     RAW dependences:
+; CHECK-DAG:   Stmt_S2[i0, i1] -> Stmt_S1[i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= 98
+; CHECK-DAG:   Stmt_S1[i0] -> Stmt_S2[i0, i0] : i0 <= 98 and i0 >= 0
+; CHECK-DAG:   Stmt_S2[i0, i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
+; CHECK-DAG:   Stmt_S3[i0] -> Stmt_S2[o0, i0] : i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
+; CHECK:     WAR dependences:
+; CHECK-DAG:    {  }
+; CHECK:     WAW dependences:
+; CHECK-DAG:   Stmt_S2[i0, i1] -> Stmt_S1[i1] : i0 >= 0 and i1 >= 1 + i0 and i1 <= 98
+; CHECK-DAG:   Stmt_S1[i0] -> Stmt_S2[i0, i0] : i0 <= 98 and i0 >= 0
+; CHECK-DAG:   Stmt_S2[i0, i0] -> Stmt_S3[i0] : i0 <= 98 and i0 >= 0
+; CHECK-DAG:   Stmt_S3[i0] -> Stmt_S2[o0, i0] : i0 >= 0 and o0 >= 1 + i0 and o0 <= 98
+; CHECK:     Reduction dependences:
+; CHECK-DAG:    { Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : (i0 >= 0 and i1 >= 2 + i0 and i1 <= 99) or (i0 <= 97 and i1 >= 0 and i1 <= -1 + 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..dc66649
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_privatization_deps_5.ll
@@ -0,0 +1,88 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:     RAW dependences:
+; CHECK-DAG:   Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : i0 <= 97 and i0 >= 0
+; CHECK-DAG:   Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : i0 <= 98 and i0 >= 0
+; CHECK:     WAR dependences:
+; CHECK-DAG:   {  }
+; CHECK:     WAW dependences:
+; CHECK-DAG:   Stmt_S2[i0, 0] -> Stmt_S1[1 + i0, 0] : i0 <= 97 and i0 >= 0
+; CHECK-DAG:   Stmt_S1[i0, 0] -> Stmt_S2[i0, 0] : i0 <= 98 and i0 >= 0
+; CHECK:     Reduction dependences:
+; CHECK-DAG:   { Stmt_S2[i0, i1] -> Stmt_S2[1 + i0, i1] : i0 <= 97 and i0 >= 0 and i1 <= 99 and i1 >= 1 }
+;
+;    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_simple_iv.ll b/final/test/DependenceInfo/reduction_simple_iv.ll
new file mode 100644
index 0000000..0769107
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_iv.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:  RAW dependences:
+; CHECK:    {  }
+; CHECK:  WAR dependences:
+; CHECK:    {  }
+; CHECK:  WAW dependences:
+; CHECK:    {  }
+; CHECK:  Reduction dependences:
+; CHECK:    { Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0] : i0 <= 99 and i0 >= 0 }
+;
+; 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..30e89ea
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_iv_debug_wrapped_dependences.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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] : i0 >= 0 and i0 <= 100 }
+; CHECK: Write: { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> MemRef_sum[0] : i0 >= 0 and i0 <= 100 }
+; CHECK: Wrapped Dependences:
+; CHECK: RAW dependences:
+; CHECK:   { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 <= 99 and i0 >= 0 }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 <= 99 and i0 >= 0 }
+; CHECK: Reduction dependences:
+; CHECK:   n/a
+; CHECK: Final Wrapped Dependences:
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK:   { [Stmt_for_cond[i0] -> MemRef_sum[0]] -> [Stmt_for_cond[1 + i0] -> MemRef_sum[0]] : i0 <= 99 and i0 >= 0 }
+; CHECK: Zipped Dependences:
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK:   { [Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0]] -> [MemRef_sum[0] -> MemRef_sum[0]] : i0 <= 99 and i0 >= 0 }
+; CHECK: Unwrapped Dependences:
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK:   { Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0] : i0 <= 99 and i0 >= 0 }
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK:   { Stmt_for_cond[i0] -> Stmt_for_cond[1 + i0] : i0 <= 99 and i0 >= 0 }
+;
+; 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..3f4fa44
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_privatization_deps_2.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-DAG:    Stmt_S1[i0, i1] -> Stmt_S2[i0] : i0 <= 99 and i0 >= 0 and i1 <= 99 and i1 >= 0
+; CHECK-DAG:    Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 99 and i0 >= 0 and o1 <= 99 and o1 >= 0
+; CHECK-DAG:    Stmt_S2[i0] -> Stmt_S0[1 + i0] : i0 <= 98 and i0 >= 0
+; CHECK:      WAR dependences:
+; CHECK-DAG:     {  }
+; CHECK:      WAW dependences:
+; CHECK-DAG:    Stmt_S1[i0, i1] -> Stmt_S2[i0] : i0 <= 99 and i0 >= 0 and i1 <= 99 and i1 >= 0
+; CHECK-DAG:    Stmt_S0[i0] -> Stmt_S1[i0, o1] : i0 <= 99 and i0 >= 0 and o1 <= 99 and o1 >= 0
+; CHECK-DAG:    Stmt_S2[i0] -> Stmt_S0[1 + i0] : i0 <= 98 and i0 >= 0
+; CHECK:      Reduction dependences:
+; CHECK-DAG:    Stmt_S1[i0, i1] -> Stmt_S1[i0, 1 + i1] : i0 <= 99 and i0 >= 0 and i1 <= 98 and i1 >= 0
+;
+;    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..660fe4d
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_simple_privatization_deps_w_parameter.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK:      RAW dependences:
+; CHECK-DAG:    Stmt_S0[] -> Stmt_S1[o0] : N >= 11 and o0 <= 1023 and o0 >= 0
+; CHECK-DAG:    Stmt_S1[i0] -> Stmt_S2[] : N >= 11 and i0 <= 1023 and i0 >= 0
+; CHECK:      WAR dependences:
+; CHECK:       [N] -> {  }
+; CHECK:      WAW dependences:
+; CHECK-DAG:    Stmt_S0[] -> Stmt_S1[o0] : N >= 11 and o0 <= 1023 and o0 >= 0
+; CHECK-DAG:    Stmt_S1[i0] -> Stmt_S2[] : N >= 11 and i0 <= 1023 and i0 >= 0
+; CHECK:   Reduction dependences:
+; CHECK:        Stmt_S1[i0] -> Stmt_S1[1 + i0] : N >= 11 and i0 <= 1022 and i0 >= 0
+;
+;    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..033afa1
--- /dev/null
+++ b/final/test/DependenceInfo/reduction_two_reductions_different_rloops.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences -analyze < %s | FileCheck %s
+;
+; CHECK: RAW dependences:
+; CHECK:   {  }
+; CHECK: WAR dependences:
+; CHECK:   {  }
+; CHECK: WAW dependences:
+; CHECK:   {  }
+; CHECK: Reduction dependences:
+; CHECK-DAG: Stmt_for_body3[i0, i1] -> Stmt_for_body3[o0, 1 + i0 + i1 - o0] : o0 <= 1 + i0 and o0 >= i0 and o0 <= 1023 and i0 >= 0 and i1 >= 0 and o0 >= -1022 + i0 + i1
+;
+; 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..cc2cdce
--- /dev/null
+++ b/final/test/DependenceInfo/sequential_loops.ll
@@ -0,0 +1,295 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=value-based < %s | FileCheck %s -check-prefix=VALUE
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-dependences -analyze -polly-dependences-analysis-type=memory-based < %s | FileCheck %s -check-prefix=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"
+
+;     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-LABEL: region: 'S1 => exit.3' in function 'sequential_writes':
+; VALUE:   RAW dependences:
+; VALUE:     {  }
+; VALUE:   WAR dependences:
+; VALUE:     {  }
+; VALUE:   WAW dependences:
+; VALUE:     {
+; VALUE:       Stmt_S1[i0] -> Stmt_S2[i0] : i0 >= 0 and i0 <= 9;
+; VALUE:       Stmt_S2[i0] -> Stmt_S3[i0] : i0 >= 0 and i0 <= 9;
+; VALUE:       Stmt_S1[i0] -> Stmt_S3[i0] : i0 >= 10 and i0 <= 99
+; VALUE:     }
+
+; MEMORY-LABEL: region: 'S1 => exit.3' in function 'sequential_writes':
+; MEMORY:   RAW dependences:
+; MEMORY:     {  }
+; MEMORY:   WAR dependences:
+; MEMORY:     {  }
+; MEMORY:   WAW dependences:
+; MEMORY:     {
+; MEMORY:       Stmt_S1[i0] -> Stmt_S2[i0] : i0 <= 9 and i0 >= 0;
+; MEMORY:       Stmt_S2[i0] -> Stmt_S3[i0] : i0 <= 9 and i0 >= 0;
+; MEMORY:       Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 99 and i0 >= 0
+; MEMORY:     }
+
+;     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
+}
+
+; VALUE-LABEL: region: 'S1 => exit.3' in function 'read_after_writes':
+; VALUE:   RAW dependences:
+; VALUE:     {
+; VALUE:       Stmt_S2[i0] -> Stmt_S3[i0] : i0 >= 0 and i0 <= 9;
+; VALUE:       Stmt_S1[i0] -> Stmt_S3[i0] : i0 >= 10 and i0 <= 99
+; VALUE:     }
+; VALUE:   WAR dependences:
+; VALUE:     {  }
+; VALUE:   WAW dependences:
+; VALUE:     {
+; VALUE:       Stmt_S1[i0] -> Stmt_S2[i0] : i0 <= 9 and i0 >= 0
+; VALUE:     }
+
+; MEMORY-LABEL: region: 'S1 => exit.3' in function 'read_after_writes':
+; MEMORY:   RAW dependences:
+; MEMORY:     {
+; MEMORY:       Stmt_S2[i0] -> Stmt_S3[i0] : i0 <= 9 and i0 >= 0;
+; MEMORY:       Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 99 and i0 >= 0
+; MEMORY:     }
+; MEMORY:   WAR dependences:
+; MEMORY:     {  }
+; MEMORY:   WAW dependences:
+; MEMORY:     {
+; MEMORY:       Stmt_S1[i0] -> Stmt_S2[i0] : i0 <= 9 and i0 >= 0
+; MEMORY:     }
+
+;     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
+}
+
+; VALUE-LABEL: region: 'S1 => exit.3' in function 'write_after_read':
+; VALUE:   RAW dependences:
+; VALUE:     {
+; VALUE:     }
+; VALUE:   WAR dependences:
+; VALUE:     {
+; VALUE:       Stmt_S1[i0] -> Stmt_S2[i0] : i0 <= 9 and i0 >= 0;
+; VALUE:       Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 99 and i0 >= 10
+; VALUE:     }
+; VALUE:   WAW dependences:
+; VALUE:     {
+; VALUE:       Stmt_S2[i0] -> Stmt_S3[i0] : i0 <= 9 and i0 >= 0
+; VALUE:     }
+
+; MEMORY-LABEL: region: 'S1 => exit.3' in function 'write_after_read':
+; MEMORY:   RAW dependences:
+; MEMORY:     {
+; MEMORY:     }
+; MEMORY:   WAR dependences:
+; MEMORY:     {
+; MEMORY:        Stmt_S1[i0] -> Stmt_S2[i0] : i0 <= 9 and i0 >= 0;
+; MEMORY:        Stmt_S1[i0] -> Stmt_S3[i0] : i0 <= 99 and i0 >= 0
+; MEMORY:     }
+; MEMORY:   WAW dependences:
+; MEMORY:     {
+; MEMORY:        Stmt_S2[i0] -> Stmt_S3[i0] : i0 <= 9 and i0 >= 0
+; MEMORY:     }
+
+;     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
+}
+
+; VALUE: region: 'S1 => exit.2' in function 'parametric_offset':
+; VALUE:   RAW dependences:
+; VALUE:     [p] -> {
+; VALUE:       Stmt_S1[i0] -> Stmt_S2[-p + i0] :
+; VALUE:           p <= 190 and i0 >= p and i0 <= 9 + p and i0 >= 0 and i0 <= 99
+; VALUE:     }
+; VALUE:   WAR dependences:
+; VALUE:     [p] -> {
+; VALUE:     }
+; VALUE:   WAW dependences:
+; VALUE:     [p] -> {
+; VALUE:     }
+
+; MEMORY: region: 'S1 => exit.2' in function 'parametric_offset':
+; MEMORY:   RAW dependences:
+; MEMORY:     [p] -> {
+; MEMORY:       Stmt_S1[i0] -> Stmt_S2[-p + i0] :
+; MEMORY:           i0 >= p and i0 <= 99 and i0 >= 0 and i0 <= 9 + p
+; MEMORY:     }
+; MEMORY:   WAR dependences:
+; MEMORY:     [p] -> {
+; MEMORY:     }
+; MEMORY:   WAW dependences:
+; MEMORY:     [p] -> {
+; MEMORY:     }
diff --git a/final/test/IndependentBlocks/inter_bb_scalar_dep.ll b/final/test/IndependentBlocks/inter_bb_scalar_dep.ll
new file mode 100644
index 0000000..a6e7b38
--- /dev/null
+++ b/final/test/IndependentBlocks/inter_bb_scalar_dep.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s -check-prefix=SCALARACCESS
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s -check-prefix=SCALARACCESS
+
+; 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:
+
+; SCALARACCESS-NOT: alloca
+  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
+; SCALARACCESS-NOT: store
+  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
+; SCALARACCESS: %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
+}
diff --git a/final/test/IndependentBlocks/intra_and_inter_bb_scalar_dep.ll b/final/test/IndependentBlocks/intra_and_inter_bb_scalar_dep.ll
new file mode 100644
index 0000000..d52cde4
--- /dev/null
+++ b/final/test/IndependentBlocks/intra_and_inter_bb_scalar_dep.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s -check-prefix=SCALARACCESS
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s -check-prefix=SCALARACCESS
+
+; 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;
+;     }
+;   }
+; }
+
+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:
+
+; SCALARACCESS-NOT: alloca
+  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
+; SCALARACCESS-NOT: store
+  br label %for.j
+
+for.j:
+  %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
+
+; The SCEV of %init_sum is (%init + %init_2). It is referring to both an
+; UnknownValue in the same and in a different basic block. We want only the
+; reference to the different basic block to be replaced.
+
+; SCALARACCESS: %init_2 = load i64, i64* %init_ptr
+; SCALARACCESS: %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:
+  %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/IndependentBlocks/intra_bb_scalar_dep.ll b/final/test/IndependentBlocks/intra_bb_scalar_dep.ll
new file mode 100644
index 0000000..29dfc45
--- /dev/null
+++ b/final/test/IndependentBlocks/intra_bb_scalar_dep.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %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"
+
+define void @f(i64* noalias %A, i64 %N, i64* noalias %init_ptr) nounwind {
+entry:
+
+; CHECK: entry
+; CHECK: br label %for.i
+  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:
+  br label %for.j
+
+for.j:
+  %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
+; The scalar evolution of %init_plus_two is (2 + %init). So we have a
+; non-trivial scalar evolution referring to a value in the same basic block.
+; We want to ensure that this scalar is not translated into a memory copy.
+  %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
+}
diff --git a/final/test/IndependentBlocks/phi_outside_scop.ll b/final/test/IndependentBlocks/phi_outside_scop.ll
new file mode 100644
index 0000000..6eec04f
--- /dev/null
+++ b/final/test/IndependentBlocks/phi_outside_scop.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s -check-prefix=SCALAR
+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 @phi_nodes_outside() {
+entry:
+  br label %for.i.1
+
+for.i.1:
+  %i.1 = phi i32 [ %i.1.next, %for.i.1 ], [ 0, %entry ]
+  %i.1.next = add nsw i32 %i.1, 1
+  br i1 false, label %for.i.1 , label %for.i.2.preheader
+
+for.i.2.preheader:
+  br label %for.i.2
+
+for.i.2:
+; The value of %i.1.next is used outside of the scop in a PHI node.
+  %i.2 = phi i32 [ %i.2.next , %for.i.2 ], [ %i.1.next, %for.i.2.preheader ]
+  %i.2.next = add nsw i32 %i.2, 1
+  fence seq_cst
+  br i1 false, label %for.i.2, label %cleanup
+
+cleanup:
+  ret void
+}
+
+; SCALAR-NOT: alloca
+
+; SCALAR: for.i.2.preheader:
+; SCALAR-NOT:    load
+
+; SCALAR: for.i.2:
+; SCALAR:    %i.2 = phi i32 [ %i.2.next, %for.i.2 ], [ %i.1.next, %for.i.2.preheader ]
diff --git a/final/test/IndependentBlocks/scalar_to_array.ll b/final/test/IndependentBlocks/scalar_to_array.ll
new file mode 100644
index 0000000..8a2750f
--- /dev/null
+++ b/final/test/IndependentBlocks/scalar_to_array.ll
@@ -0,0 +1,222 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent -S < %s | FileCheck %s -check-prefix=SCALARACCESS
+; RAUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-independent < %s -S | FileCheck %s -check-prefix=SCALARACCESS
+
+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
+
+define i32 @empty() nounwind {
+entry:
+  fence seq_cst
+  br label %for.cond
+
+for.cond:
+  %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:
+  br label %for.inc
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:
+  fence seq_cst
+  ret i32 0
+}
+
+
+; SCALARACCESS-LABEL: @array_access()
+define i32 @array_access() nounwind {
+entry:
+  fence seq_cst
+  br label %for.cond
+; SCALARACCESS: entry:
+; SCALARACCESS-NOT: alloca
+
+for.cond:
+  %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:
+  %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
+
+; SCALARACCESS: for.body:
+; SCALARACCESS: %float = uitofp i64 %indvar to float
+; SCALARACCESS: store float %float, float* %arrayidx
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:
+  fence seq_cst
+  ret i32 0
+}
+
+; SCALARACCESS-LABEL: @intra_scop_dep()
+define i32 @intra_scop_dep() nounwind {
+entry:
+  fence seq_cst
+  br label %for.cond
+
+; SCALARACCESS: entry:
+; SCALARACCESS-NOT: alloca
+; SCALARACCESS: fence
+
+for.cond:
+  %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:
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %scalar = load float, float* %arrayidx
+  br label %for.body.b
+
+; SCALARACCESS: for.body.a:
+; SCALARACCESS: %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+; SCALARACCESS: %scalar = load float, float* %arrayidx
+; SCALARACCESS-NOT: store
+; SCALARACCESS: br label %for.body.b
+
+for.body.b:
+  %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
+
+; SCALARACCESS: for.body.b:
+; SCALARACCESS: %arrayidx2 = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+; SCALARACCESS: %float = uitofp i64 %indvar to float
+; SCALARACCESS-NOT: load
+; SCALARACCESS: %sum = fadd float %scalar, %float
+; SCALARACCESS: store float %sum, float* %arrayidx2
+; SCALARACCESS: br label %for.inc
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:
+  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.
+
+; SCALARACCESS-LABEL: @use_after_scop()
+define i32 @use_after_scop() nounwind {
+entry:
+  fence seq_cst
+  br label %for.head
+
+; SCALARACCESS: entry:
+; SCALARACCESS-NOT: alloca
+; SCALARACCESS: fence
+
+for.head:
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %entry ]
+  br label %for.body
+
+for.body:
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  %scalar = load float, float* %arrayidx
+  br label %for.inc
+
+; SCALARACCESS: for.body:
+; SCALARACCESS: %scalar = load float, float* %arrayidx
+; SCALARACCESS-NOT: store float %scalar
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar, 1024
+  br i1 %exitcond, label %for.head, label %for.after
+
+for.after:
+  fence seq_cst
+  %return_value = fptosi float %scalar to i32
+  br label %return
+
+; SCALARACCESS: for.after:
+; SCALARACCESS: fence seq_cst
+; SCALARACCESS: %return_value = fptosi float %scalar to i32
+
+return:
+  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.
+;
+; SCALARACCESS-LABEL: @before_scop()
+define i32 @before_scop() nounwind {
+entry:
+  br label %preheader
+
+preheader:
+  %scalar = fadd float 4.0, 5.0
+  fence seq_cst
+  br label %for.cond
+
+for.cond:
+  %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:
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  store float %scalar, float* %arrayidx
+  br label %for.inc
+
+; SCALARACCESS: for.body:
+; SCALARACCESS: store float %scalar, float* %arrayidx
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:
+  fence seq_cst
+  ret i32 0
+}
+
+; Currently not working
+; SCALARACCESS-LABEL: @param_before_scop(
+define i32 @param_before_scop(float %scalar) nounwind {
+entry:
+  fence seq_cst
+  br label %for.cond
+
+for.cond:
+  %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:
+  %arrayidx = getelementptr [1024 x float], [1024 x float]* @A, i64 0, i64 %indvar
+  store float %scalar, float* %arrayidx
+  br label %for.inc
+
+for.inc:
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond
+
+return:
+  fence seq_cst
+  ret i32 0
+}
diff --git a/final/test/IndependentBlocks/scev-invalidated.ll b/final/test/IndependentBlocks/scev-invalidated.ll
new file mode 100644
index 0000000..8e9ac25
--- /dev/null
+++ b/final/test/IndependentBlocks/scev-invalidated.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-independent < %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 @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/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..04996a7
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/multiple_loops_outer_parallel.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -polly-parallel-force -analyze < %s | FileCheck %s
+;
+;       void jd(int *A) {
+; CHECK:  #pragma omp parallel for
+;         for (int i = 0; i < 1024; i++)
+;           A[i] = 1;
+; CHECK:  #pragma omp parallel for
+;         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..7937d27
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -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 < 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);
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..bbce5a3
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_both_parallel_parametric.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -polly-parallel-force -analyze -polly-delinearize < %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"
+; 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);
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..5cad725
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_inner_parallel.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -polly-parallel-force -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 < 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);
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..5d66920
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/nested_loop_outer_parallel.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -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 < 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);
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..5c45f28
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/single_loop_param_non_parallel.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -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 < 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)
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..fe212fe
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/single_loop_param_parallel.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -polly-parallel-force -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 < 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)
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..96626b1
--- /dev/null
+++ b/final/test/Isl/Ast/OpenMP/single_loop_param_parallel_computeout.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-parallel -polly-dependences-computeout=1 -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 < 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)
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..17145ee
--- /dev/null
+++ b/final/test/Isl/Ast/alias_simple_1.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -basicaa < %s | FileCheck %s --check-prefix=BASI
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -tbaa < %s | FileCheck %s --check-prefix=TBAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -scev-aa < %s | FileCheck %s --check-prefix=SCEV
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -globalsmodref-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 (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; BASI: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; TBAA: if (N <= 1024)
+; SCEV: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; GLOB: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[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..e2489ac
--- /dev/null
+++ b/final/test/Isl/Ast/alias_simple_2.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -basicaa < %s | FileCheck %s --check-prefix=BASI
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -tbaa < %s | FileCheck %s --check-prefix=TBAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -scev-aa < %s | FileCheck %s --check-prefix=SCEV
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -globalsmodref-aa < %s | FileCheck %s --check-prefix=GLOB
+;
+;    int A[1024], B[1024];
+;
+;
+;    void jd(int N) {
+;      for (int i = 0; i < N; i++)
+;        A[i] = B[i];
+;    }
+;
+; NOAA: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; BASI: if (N <= 1024)
+; TBAA: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; SCEV: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; GLOB: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[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..2e42214
--- /dev/null
+++ b/final/test/Isl/Ast/alias_simple_3.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -basicaa < %s | FileCheck %s --check-prefix=BASI
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -tbaa < %s | FileCheck %s --check-prefix=TBAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -scev-aa < %s | FileCheck %s --check-prefix=SCEV
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze -polly-no-early-exit -globalsmodref-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 (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; BASI: if (N <= 1024)
+; TBAA: if (N <= 1024)
+; SCEV: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[0]))
+; GLOB: if (N <= 1024 && (&MemRef_A[N] <= &MemRef_B[0] || &MemRef_B[N] <= &MemRef_A[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_multiple_alias_groups.ll b/final/test/Isl/Ast/aliasing_multiple_alias_groups.ll
new file mode 100644
index 0000000..7f214ed
--- /dev/null
+++ b/final/test/Isl/Ast/aliasing_multiple_alias_groups.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-ast -analyze          < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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_Float0[1024] <= &MemRef_Int0[0] || &MemRef_Int0[1024] <= &MemRef_Float0[0]
+; NOAA-DAG:    &MemRef_Float1[1024] <= &MemRef_Int0[0] || &MemRef_Int0[1024] <= &MemRef_Float1[0]
+; NOAA-DAG:    &MemRef_Int1[1024] <= &MemRef_Int0[0] || &MemRef_Int0[1024] <= &MemRef_Int1[0]
+; NOAA-DAG:    &MemRef_Float0[1024] <= &MemRef_Float1[0] || &MemRef_Float1[1024] <= &MemRef_Float0[0]
+; NOAA-DAG:    &MemRef_Int1[1024] <= &MemRef_Float0[0] || &MemRef_Float0[1024] <= &MemRef_Int1[0]
+; NOAA:      ))
+;
+; TBAA:      if (1 && (
+; TBAA-DAG:    &MemRef_Int0[1024] <= &MemRef_Int1[0] || &MemRef_Int1[1024] <= &MemRef_Int0[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..1ae73d3
--- /dev/null
+++ b/final/test/Isl/Ast/aliasing_parametric_simple_1.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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_A[1024] <= &MemRef_B[c] || &MemRef_B[c + 1] <= &MemRef_A[0]))
+; 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..bb0ac57
--- /dev/null
+++ b/final/test/Isl/Ast/aliasing_parametric_simple_2.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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 && (&MemRef_A[1024] <= &MemRef_B[c >= 15 ? 5 : c - 10] || &MemRef_B[c <= 15 ? 6 : c - 9] <= &MemRef_A[0]))
+; 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..be02b72
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_constant.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+;        void f(int *A, int N) {
+; CHECK:   #pragma minimal dependence distance: 1
+;          for (int j = 0; j < N; j++)
+; CHECK:     #pragma minimal dependence distance: 8
+;            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..121ecb1
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_multiple_constant.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+;        void f(int *restrict A, int *restrict B, int N) {
+; CHECK:   #pragma minimal dependence distance: 5
+;          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..71053a6
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_parametric.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+;        void f(int *A, int N, int c) {
+; CHECK:   #pragma minimal dependence distance: 1
+;          for (int j = 0; j < N; j++)
+; CHECK:     #pragma minimal dependence distance: c >= 1 ? c : -c
+;            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..72bcde7
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_parametric_expr.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+;        void f(int *A, int N, int c, int v) {
+; CHECK:   #pragma minimal dependence distance: 1
+;          for (int j = 0; j < N; j++)
+; CHECK:     #pragma minimal dependence distance: c + v >= 1 ? c + v : -c - v
+;            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..e63656a
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_varying.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+;         void f(int *A, int N) {
+; CHECK:    #pragma minimal dependence distance: ((N - 1) % 2) + 1
+;           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..d38df2e
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_varying_in_outer_loop.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-canonicalize -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+;        void f(int *restrict A, int *restrict sum) {
+; CHECK:   #pragma minimal dependence distance: 1
+;          for (int j = 0; j < 1024; j++)
+; CHECK:     #pragma minimal dependence distance: 1
+;            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..6e61410
--- /dev/null
+++ b/final/test/Isl/Ast/dependence_distance_varying_multiple.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+;        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
+;          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/reduction_clauses_multidimensional_access.ll b/final/test/Isl/Ast/reduction_clauses_multidimensional_access.ll
new file mode 100644
index 0000000..886eb0c
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_clauses_multidimensional_access.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-delinearize -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK: #pragma known-parallel reduction (^ : sum)
+;        void f(int N, int M, int P, int sum[P][M]) {
+;          for (int i = 0; i < N; i++)
+;            for (int j = 0; j < P; j++)
+; CHECK:       #pragma simd
+;              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..fd86e25
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_clauses_onedimensional_access.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK: #pragma known-parallel reduction (^ : 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..5543714
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_dependences_equal_non_reduction_dependences.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..d16c3b6
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_different_reduction_clauses.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK: #pragma simd reduction (+ : sum{{[1,2]}}, sum{{[1,2]}}) reduction (* : prod) reduction (| : or) reduction (& : and)
+; CHECK: #pragma known-parallel reduction (+ : sum{{[1,2]}}, sum{{[1,2]}}) reduction (* : prod) reduction (| : or) reduction (& : 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..30aaca7
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_in_one_dimension.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; Verify that we won't privatize anything in the outer dimension
+;
+; CHECK:    #pragma known-parallel
+; CHECK:    for (int c0 = 0; c0 < 2 * n; c0 += 1)
+; CHECK:      #pragma simd reduction
+; 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..0e0dc65
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_loop_reversal.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK-NOT: #pragma simd{{\s*$}}
+; CHECK: #pragma simd reduction
+; CHECK: Stmt_S0(n - c1)
+; CHECK: #pragma simd{{\s*$}}
+; CHECK: Stmt_S1(n - c1)
+;
+;    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..9ad906c
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK-NOT: #pragma simd{{\s*$}}
+; CHECK: #pragma simd reduction
+; CHECK: Stmt_S0(2 * n - c1)
+; CHECK: #pragma simd{{\s*$}}
+; CHECK: Stmt_S1
+; CHECK: #pragma simd reduction
+; CHECK: Stmt_S0(2 * n - c1)
+; CHECK-NOT: #pragma simd{{\s*$}}
+;
+;    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..a5ef418
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_and_loop_reversal_schedule_2.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -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..21a1305
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze < %s | FileCheck %s
+;
+; CHECK-NOT: #pragma simd{{\s*$}}
+; CHECK: #pragma simd reduction
+; CHECK: Stmt_S0
+; CHECK: #pragma simd{{\s*$}}
+; CHECK: Stmt_S1
+; CHECK: #pragma simd reduction
+; CHECK: Stmt_S0
+; CHECK-NOT: #pragma simd{{\s*$}}
+;
+;    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..5c66524
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -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..45db5cc
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_2.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -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..3d586a0
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_3.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -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..d57e177
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_4.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -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 <= 0 && c3 % 2 == 0) {
+; CHECK:          Stmt_for_body3(c1, -c3);
+; CHECK:        } else if (c3 >= 1 && (c3 - 1) % 2 == 0)
+; CHECK:          Stmt_for_body3(c1, c3);
+; 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..ecf6b65
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_modulo_schedule_multiple_dimensions_5.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -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 % 2 == 0) {
+; 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:      } else
+; 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:    }
+;
+;    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..0290d6c
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..a3e16b6
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions_2.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..2313349
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions_3.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..6cb2001
--- /dev/null
+++ b/final/test/Isl/Ast/reduction_multiple_dimensions_4.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..116a59e
--- /dev/null
+++ b/final/test/Isl/Ast/run-time-condition.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-ast -analyze -polly-no-early-exit < %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/simple-run-time-condition.ll b/final/test/Isl/Ast/simple-run-time-condition.ll
new file mode 100644
index 0000000..ca0ccc4
--- /dev/null
+++ b/final/test/Isl/Ast/simple-run-time-condition.ll
@@ -0,0 +1,97 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-ast -analyze -polly-no-early-exit -polly-delinearize < %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, 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 (
+; CHECK: (o >= 1 && q <= 0 && m + q >= 0)
+; CHECK: ||
+; CHECK; (o <= 0 && m + q >= 100 && q <= 100)
+; CHECK: )
+
+; CHECK:     if (o >= 1) {
+; 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:       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:     {  /* 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..94c49b3
--- /dev/null
+++ b/final/test/Isl/Ast/single_loop_strip_mine.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop-dir=%S -basicaa -polly-import-jscop -polly-ast -polly-ast-detect-parallel -analyze -polly-no-early-exit < %s | FileCheck %s -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(c1);
+
+
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..b1efd0e
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100617.ll
@@ -0,0 +1,18 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..5d6c756
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100622.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-codegen < %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..efcb966
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100707.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..cf1ed0e
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100707_2.ll
@@ -0,0 +1,114 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..272a669
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100708.ll
@@ -0,0 +1,17 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..9fc4cf1
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100708_2.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..1d297db
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100713.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..3c00127
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100713_2.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..d7a4912
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100717.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable  -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..14880fa
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100718-DomInfo-2.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..58d997b
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100718-DomInfo.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..c9e663d
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100720-MultipleConditions.ll
@@ -0,0 +1,95 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..08278f0
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100809-IndependentBlock.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..bc742a4
--- /dev/null
+++ b/final/test/Isl/CodeGen/20100811-ScalarDependencyBetweenBrAndCnd.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..8c12d8a
--- /dev/null
+++ b/final/test/Isl/CodeGen/20101030-Overflow.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..dd7d115
--- /dev/null
+++ b/final/test/Isl/CodeGen/20101103-Overflow3.ll
@@ -0,0 +1,23 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..0e56480
--- /dev/null
+++ b/final/test/Isl/CodeGen/20101103-signmissmatch.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..049fb81
--- /dev/null
+++ b/final/test/Isl/CodeGen/20110226-Ignore-Dead-Code.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..765cd64
--- /dev/null
+++ b/final/test/Isl/CodeGen/20110226-PHI-Node-removed.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/20110312-Fail-without-basicaa.ll b/final/test/Isl/CodeGen/20110312-Fail-without-basicaa.ll
new file mode 100644
index 0000000..6ca15e6
--- /dev/null
+++ b/final/test/Isl/CodeGen/20110312-Fail-without-basicaa.ll
@@ -0,0 +1,26 @@
+; This should be run without alias analysis enabled.
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-independent < %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/Isl/CodeGen/20120316-InvalidCast.ll b/final/test/Isl/CodeGen/20120316-InvalidCast.ll
new file mode 100644
index 0000000..2eac103
--- /dev/null
+++ b/final/test/Isl/CodeGen/20120316-InvalidCast.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -S -polly-detect-scops-in-functions-without-loops -polly-detect-scops-in-regions-without-loops -polly-codegen -polly-no-early-exit < %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..6100ca8
--- /dev/null
+++ b/final/test/Isl/CodeGen/20120403-RHS-type-mismatch.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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
+  unreachable
+}
diff --git a/final/test/Isl/CodeGen/20130211-getNumberOfIterations.ll b/final/test/Isl/CodeGen/20130211-getNumberOfIterations.ll
new file mode 100644
index 0000000..a3994b7
--- /dev/null
+++ b/final/test/Isl/CodeGen/20130211-getNumberOfIterations.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..e9e26fe
--- /dev/null
+++ b/final/test/Isl/CodeGen/20130221.ll
@@ -0,0 +1,20 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..d4a7c30
--- /dev/null
+++ b/final/test/Isl/CodeGen/20150328-SCEVExpanderIntroducesNewIV.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -S < %s | FileCheck %s
+
+; 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 ]
+  %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..11ff241
--- /dev/null
+++ b/final/test/Isl/CodeGen/LoopParallelMD/do_not_mutate_debug_info.ll
@@ -0,0 +1,70 @@
+; This test checks that we do not accidently mutate the debug info when
+; inserting loop parallel metadata.
+; RUN: opt %loadPolly -polly-detect-unprofitable < %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() {
+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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: true, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !12, imports: !2)
+!1 = !DIFile(filename: "t2.c", directory: "/local/mnt/workspace/build/tip-Release")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "foo", line: 3, isLocal: false, isDefinition: true, isOptimized: true, scopeLine: 3, file: !1, scope: !5, type: !6, function: void ()* @foo, variables: !8)
+!5 = !DIFile(filename: "t2.c", directory: "/local/mnt/workspace/build/tip-Release")
+!6 = !DISubroutineType(types: !7)
+!7 = !{null}
+!8 = !{!9}
+!9 = !DILocalVariable(tag: DW_TAG_auto_variable, 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 = !DIGlobalVariable(name: "A", line: 2, isLocal: false, isDefinition: true, scope: null, file: !5, type: !14, variable: i32** @A)
+!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..5a89dc8
--- /dev/null
+++ b/final/test/Isl/CodeGen/LoopParallelMD/loop_nest_param_parallel.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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{{[0-9]*}}, 1022
+; 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{{[0-9]*}}, 510
+; 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..6ce6b76
--- /dev/null
+++ b/final/test/Isl/CodeGen/LoopParallelMD/single_loop_param_parallel.ll
@@ -0,0 +1,86 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-codegen -S < %s | FileCheck %s -check-prefix=SEQUENTIAL
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..61afde7
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/bad_alignment.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop -polly-import-jscop-dir=%S -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..ad465ed
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_address_space.ll
@@ -0,0 +1,44 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -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..25bc317
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_constant_offset.ll
@@ -0,0 +1,42 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -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..482e7d1
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple.ll
@@ -0,0 +1,42 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -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..562ef0b
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll
@@ -0,0 +1,41 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -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..eda960d
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll
@@ -0,0 +1,74 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed+withconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHCONST %s
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed+withoutconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHOUTCONST %s
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed+withconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHCONST %s
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -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..7dc6369
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll
@@ -0,0 +1,71 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed+withconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHCONST %s
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed+withoutconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHOUTCONST %s
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed+withconst -polly-codegen < %s -S | FileCheck -check-prefix=WITHCONST %s
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-import-jscop -polly-import-jscop-dir=%S -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/default_aligned_new_access_function.ll b/final/test/Isl/CodeGen/MemAccess/default_aligned_new_access_function.ll
new file mode 100644
index 0000000..dc425a6
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/default_aligned_new_access_function.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-import-jscop -polly-import-jscop-dir=%S -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/simple.ll b/final/test/Isl/CodeGen/MemAccess/simple.ll
new file mode 100644
index 0000000..35cc6f4
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple.ll
@@ -0,0 +1,65 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop -polly-import-jscop-dir=%S -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..dc9101c
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple_analyze.ll
@@ -0,0 +1,76 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop -analyze -polly-import-jscop-dir=%S -polly-import-jscop-postfix=transformed < %s | FileCheck %s
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-import-jscop -polly-import-jscop-dir=%S -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..1f0d012
--- /dev/null
+++ b/final/test/Isl/CodeGen/MemAccess/simple_stride_test.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-import-jscop -polly-import-jscop-dir=%S -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/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..a8e28a2
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-iv.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..521d36f
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-2.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..a2b1a84
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values-3.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-parallel -polly-parallel-force -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);
+
+; 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);
+
+; 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..7743fe7
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-body-references-outer-values.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-codegen -S < %s | FileCheck %s -check-prefix=IR
+; RUN: opt %loadPolly -polly-detect-unprofitable -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.start:
+; IR-NEXT:  %0 = bitcast { float* }* %polly.par.userContext to i8*
+; IR-NEXT:  call void @llvm.lifetime.start(i64 8, i8* %0)
+; IR-NEXT:  %1 = getelementptr inbounds { float* }, { float* }* %polly.par.userContext, i32 0, i32 0
+; IR-NEXT:  store float* %A, float** %1
+; 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..4fe9233
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/loop-bounds-reference-outer-ids.ll
@@ -0,0 +1,102 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-codegen -S < %s | FileCheck %s -check-prefix=IR
+; RUN: opt %loadPolly -polly-detect-unprofitable -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:      %[[R0:[0-9]+]] = bitcast { i64, i64 }* %polly.par.userContext to i8*
+; IR-NEXT: call void @llvm.lifetime.start(i64 16, i8* %[[R0]])
+; IR-NEXT: %[[R1:[0-9]+]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %polly.par.userContext, i32 0, i32 0
+; IR-NEXT: store i64 %n, i64* %[[R1]]
+; IR-NEXT: %[[R2:[0-9]+]] = 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-9]+]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %polly.par.userContext1, i32 0, i32 0
+; IR-NEXT:  %[[R4:[0-9]+]] = load i64, i64* %[[R3]]
+; IR-NEXT:  %[[R5:[0-9]+]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* %polly.par.userContext1, i32 0, i32 1
+; IR-NEXT:  %[[R6:[0-9]+]] = 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/reference-other-bb.ll b/final/test/Isl/CodeGen/OpenMP/reference-other-bb.ll
new file mode 100644
index 0000000..0f63e9f
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/reference-other-bb.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..5020822
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/reference-preceeding-loop.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -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.
+; - Test the case where two parallel subfunctions are created.
+
+; AST: if (symbol >= p_2 + 1) {
+; 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: } else
+; AST-NEXT:   #pragma simd
+; AST-NEXT:   #pragma omp parallel for
+; AST-NEXT:   for (int c0 = 0; c0 <= p_0 + p_2; c0 += 1)
+; AST-NEXT:     Stmt_while_body(c0);
+
+; IR: @update_model.polly.subfn
+; IR: @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/single_loop.ll b/final/test/Isl/CodeGen/OpenMP/single_loop.ll
new file mode 100644
index 0000000..4faac8d
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/single_loop.ll
@@ -0,0 +1,117 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-import-jscop -polly-import-jscop-dir=%S -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST-STRIDE4
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-import-jscop -polly-import-jscop-dir=%S -polly-codegen -S < %s | FileCheck %s -check-prefix=IR-STRIDE4
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-import-jscop -polly-import-jscop-dir=%S -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.start:
+; IR-NEXT:   %0 = bitcast {}* %polly.par.userContext to i8*
+; IR-NEXT:   call void @llvm.lifetime.start(i64 0, i8* %0)
+; 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:   %1 = bitcast {}* %polly.par.userContext to i8*
+; IR-NEXT:   call void @llvm.lifetime.end(i64 8, i8* %1)
+; IR-NEXT:   br label %polly.merge_new_and_old
+
+; 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.adjust_ub = sub i64 %polly.par.UBAdjusted, 1
+; IR-NEXT:   %polly.loop_cond = icmp sle i64 %polly.indvar, %polly.adjust_ub
+; 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..1031829
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/single_loop_with_loop_invariant_baseptr.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -tbaa -polly-parallel -polly-parallel-force -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -tbaa -polly-parallel -polly-parallel-force -polly-parallel-force -polly-codegen -S -verify-dom-info < %s | FileCheck %s -check-prefix=IR
+; RUN: opt %loadPolly -polly-detect-unprofitable -tbaa -polly-parallel -polly-parallel-force -polly-parallel-force -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_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..9e11057
--- /dev/null
+++ b/final/test/Isl/CodeGen/OpenMP/two-parallel-loops-reference-outer-indvar.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-parallel -polly-parallel-force -polly-ast -analyze < %s | FileCheck %s -check-prefix=AST
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: if (nj >= p_1 + 3) {
+; AST:   #pragma simd
+; AST:   #pragma omp parallel for
+; AST:   for (int c0 = 0; c0 < p_0 + nj - 1; c0 += 1)
+; AST:     Stmt_for_body35(c0);
+; AST: } else
+; AST:   #pragma simd
+; AST:   #pragma omp parallel for
+; AST:   for (int c0 = 0; c0 <= p_0 + p_1; c0 += 1)
+; AST:     Stmt_for_body35(c0);
+
+; IR: @foo.polly.subfn
+; IR: @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..39a4ad6
--- /dev/null
+++ b/final/test/Isl/CodeGen/PHIInExit.ll
@@ -0,0 +1,103 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 ()*)* @pthread_once ; <i32 (i32*, void ()*)*> [#uses=0]
+@_ZL27__gthrw_pthread_getspecificj = weak alias i8* (i32)* @pthread_getspecific ; <i8* (i32)*> [#uses=0]
+@_ZL27__gthrw_pthread_setspecificjPKv = weak alias 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*)* @pthread_create ; <i32 (i64*, %union.pthread_attr_t*, i8* (i8*)*, i8*)*> [#uses=0]
+@_ZL22__gthrw_pthread_cancelm = weak alias i32 (i64)* @pthread_cancel ; <i32 (i64)*> [#uses=0]
+@_ZL26__gthrw_pthread_mutex_lockP15pthread_mutex_t = weak alias 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*)* @pthread_mutex_trylock ; <i32 (%union.pthread_mutex_t*)*> [#uses=0]
+@_ZL28__gthrw_pthread_mutex_unlockP15pthread_mutex_t = weak alias 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*)* @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*)*)* @pthread_key_create ; <i32 (i32*, void (i8*)*)*> [#uses=0]
+@_ZL26__gthrw_pthread_key_deletej = weak alias i32 (i32)* @pthread_key_delete ; <i32 (i32)*> [#uses=0]
+@_ZL30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t = weak alias 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)* @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*)* @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/alias-check-multi-dim.ll b/final/test/Isl/CodeGen/alias-check-multi-dim.ll
new file mode 100644
index 0000000..4a09d19
--- /dev/null
+++ b/final/test/Isl/CodeGen/alias-check-multi-dim.ll
@@ -0,0 +1,24 @@
+; RUN: opt %loadPolly -polly-codegen -polly-delinearize -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/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..313e6f0
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_different_base_and_access_type.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -S -polly-code-generator=isl -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..05ed7f7
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_different_pointer_types.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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]]] = bitcast float** %polly.access.B to i8*
+; CHECK:   %[[paAb:[._a-zA-Z0-9]]] = bitcast double** %polly.access.A to i8*
+; CHECK:   %[[ALeB:[._a-zA-Z0-9]]] = icmp ule i8* %[[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]]] = bitcast double** %polly.access.A1 to i8*
+; CHECK:   %[[paB2b:[._a-zA-Z0-9]]] = bitcast float** %polly.access.B2 to i8*
+; CHECK:   %[[A1LeB2:[._a-zA-Z0-9]]] = icmp ule i8* %[[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..ee9fb69
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_multidimensional_access.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -S -polly-codegen -polly-code-generator=isl -polly-delinearize < %s | FileCheck %s
+;
+; Check that we calculate the maximal access into array A correctly.
+;
+; CHECK:  %[[TMP0:[._0-9a-zA-Z]*]] = mul i64 99, %m
+; CHECK:  %[[TMP1:[._0-9a-zA-Z]*]] = add i64 %[[TMP0]], 149
+; CHECK:  %[[TMP2:[._0-9a-zA-Z]*]] = mul i64 %[[TMP1]], %p
+; CHECK:  %[[TMP3:[._0-9a-zA-Z]*]] = add i64 %[[TMP2]], 150
+; CHECK:  %polly.access.A{{[0-9]*}} = getelementptr double, double* %A, i64 %[[TMP3]]
+;
+;    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..28da514
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_parametric_simple_1.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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:  %[[AMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 1024
+; CHECK:  %[[BMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i32 %c
+; CHECK:  %[[AltB:[._a-zA-Z0-9]*]] = icmp ule i32* %[[AMax]], %[[BMin]]
+; CHECK:  %[[Cext:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK:  %[[Cp1:[._a-zA-Z0-9]*]] = add nsw i64 %[[Cext]], 1
+; CHECK:  %[[BMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i64 %[[Cp1]]
+; CHECK:  %[[AMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 0
+; CHECK:  %[[BltA:[._a-zA-Z0-9]*]] = icmp ule i32* %[[BMax]], %[[AMin]]
+; CHECK:  %[[NoAlias:[._a-zA-Z0-9]*]] = or i1 %[[AltB]], %[[BltA]]
+; CHECK:  %[[RTC:[._a-zA-Z0-9]*]] = and i1 true, %[[NoAlias]]
+; CHECK:  br i1 %[[RTC]], 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..972ce0a
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_parametric_simple_2.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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:  %[[AMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 1024
+; CHECK:  %[[m0:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK:  %[[m1:[._a-zA-Z0-9]*]] = icmp sge i64 %[[m0]], 15
+; CHECK:  %[[m2:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK:  %[[m3:[._a-zA-Z0-9]*]] = sub nsw i64 %[[m2]], 10
+; CHECK:  %[[m4:[._a-zA-Z0-9]*]] = select i1 %[[m1]], i64 5, i64 %[[m3]]
+; CHECK:  %[[BMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i64 %[[m4]]
+; CHECK:  %[[AltB:[._a-zA-Z0-9]*]] = icmp ule i32* %[[AMax]], %[[BMin]]
+; CHECK:  %[[M0:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK:  %[[M1:[._a-zA-Z0-9]*]] = icmp sle i64 %[[M0]], 15
+; CHECK:  %[[M2:[._a-zA-Z0-9]*]] = sext i32 %c to i64
+; CHECK:  %[[M3:[._a-zA-Z0-9]*]] = sub nsw i64 %[[M2]], 9
+; CHECK:  %[[M4:[._a-zA-Z0-9]*]] = select i1 %[[M1]], i64 6, i64 %[[M3]]
+; CHECK:  %[[BMax:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %B, i64 %[[M4]]
+; CHECK:  %[[AMin:[._a-zA-Z0-9]*]] = getelementptr i32, i32* %A, i64 0
+; CHECK:  %[[BltA:[._a-zA-Z0-9]*]] = icmp ule i32* %[[BMax]], %[[AMin]]
+; CHECK:  %[[NoAlias:[._a-zA-Z0-9]*]] = or i1 %[[AltB]], %[[BltA]]
+; CHECK:  %[[RTC:[._a-zA-Z0-9]*]] = and i1 true, %[[NoAlias]]
+; CHECK:  br i1 %[[RTC]], 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..b499bb3
--- /dev/null
+++ b/final/test/Isl/CodeGen/aliasing_struct_element.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -S -polly-code-generator=isl -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..f09f6fb
--- /dev/null
+++ b/final/test/Isl/CodeGen/alignment.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..2140e85
--- /dev/null
+++ b/final/test/Isl/CodeGen/annotated_alias_scopes.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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.B"}
+; SCOPES:      ![[NoAliasB]] = !{
+; SCOPES-DAG:     ![[AliasScopeA]]
+; SCOPES-DAG:     ![[AliasScopeC]]
+; SCOPES:       }
+; SCOPES-DAG:  ![[AliasScopeA]] = distinct !{![[AliasScopeA]], !{{[0-9]*}}, !"polly.alias.scope.A"}
+; SCOPES-DAG:  ![[AliasScopeC]] = distinct !{![[AliasScopeC]], !{{[0-9]*}}, !"polly.alias.scope.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..6832f9e
--- /dev/null
+++ b/final/test/Isl/CodeGen/blas_sscal_simplified.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/constant_condition.ll b/final/test/Isl/CodeGen/constant_condition.ll
new file mode 100644
index 0000000..53d45fc
--- /dev/null
+++ b/final/test/Isl/CodeGen/constant_condition.ll
@@ -0,0 +1,55 @@
+;RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-prepare -polly-detect-scops-in-regions-without-loops -polly-detect-scops-in-functions-without-loops -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..edfb0d5
--- /dev/null
+++ b/final/test/Isl/CodeGen/create-conditional-scop.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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"
+
+; 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 ]
+  %0 = add i32 %indvar35, 1
+  %exitcond2 = icmp eq i32 %0, 0
+  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/debug-intrinsics.ll b/final/test/Isl/CodeGen/debug-intrinsics.ll
new file mode 100644
index 0000000..14b70a7
--- /dev/null
+++ b/final/test/Isl/CodeGen/debug-intrinsics.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -S < %s | 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 {
+entry:
+  br label %entry.split
+
+entry.split:                                      ; preds = %entry
+  tail call void @llvm.dbg.value(metadata float* %A, i64 0, metadata !14, metadata !DIExpression()), !dbg !15
+  tail call void @llvm.dbg.value(metadata i64 %N, i64 0, metadata !16, metadata !DIExpression()), !dbg !15
+  tail call void @llvm.dbg.value(metadata i64 0, 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, i64 0, 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, 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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5 ", isOptimized: false, emissionKind: 0, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "loop.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "foo", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 1, file: !1, scope: !5, type: !6, function: void (float*, i64)* @foo, 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(tag: DW_TAG_arg_variable, name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!15 = !DILocation(line: 1, scope: !4)
+!16 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "N", line: 1, arg: 2, scope: !4, file: !5, type: !10)
+!17 = !{i64 0}
+!18 = !DILocalVariable(tag: DW_TAG_auto_variable, 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/exprModDiv.ll b/final/test/Isl/CodeGen/exprModDiv.ll
new file mode 100644
index 0000000..f77013a
--- /dev/null
+++ b/final/test/Isl/CodeGen/exprModDiv.ll
@@ -0,0 +1,105 @@
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-dir=%S -polly-codegen -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-dir=%S -polly-codegen -polly-import-jscop-postfix=pow2 -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[p] + B[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.A6 = 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.B8 = getelementptr float, float* %B, i64 %pexp.p_div_q
+
+; #define floord(n,d) ((n < 0) ? (n - d + 1) : n) / d
+; A[p + 127 * floord(-p - 1, 127) + 127]
+; CHECK:  %20 = sub nsw i64 0, %p
+; CHECK:  %21 = sub nsw i64 %20, 1
+; CHECK:  %pexp.fdiv_q.0 = sub i64 %21, 127
+; CHECK:  %pexp.fdiv_q.1 = add i64 %pexp.fdiv_q.0, 1
+; CHECK:  %pexp.fdiv_q.2 = icmp slt i64 %21, 0
+; CHECK:  %pexp.fdiv_q.3 = select i1 %pexp.fdiv_q.2, i64 %pexp.fdiv_q.1, i64 %21
+; CHECK:  %pexp.fdiv_q.4 = sdiv i64 %pexp.fdiv_q.3, 127
+; CHECK:  %22 = mul nsw i64 127, %pexp.fdiv_q.4
+; CHECK:  %23 = add nsw i64 %p, %22
+; CHECK:  %24 = add nsw i64 %23, 127
+; CHECK:  %polly.access.A10 = getelementptr float, float* %A, i64 %24
+
+; 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.A6 = 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.B8 = getelementptr float, float* %B, i64 %pexp.p_div_q
+
+; #define floord(n,d) ((n < 0) ? (n - d + 1) : n) / d
+; A[p + 128 * floord(-p - 1, 128) + 128]
+; POW2:  %20 = sub nsw i64 0, %p
+; POW2:  %21 = sub nsw i64 %20, 1
+; POW2:  %polly.fdiv_q.shr = ashr i64 %21, 7
+; POW2:  %22 = mul nsw i64 128, %polly.fdiv_q.shr
+; POW2:  %23 = add nsw i64 %p, %22
+; POW2:  %24 = add nsw i64 %23, 128
+; POW2:  %polly.access.A10 = getelementptr float, float* %A, i64 %24
+
+; 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 %p
+  %tmp2 = load float, float* %arrayidx2, align 4
+  %add3 = fadd float %add, %tmp2
+  %arrayidx4 = getelementptr inbounds float, float* %B, i64 %p
+  %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/intrinsics_lifetime.ll b/final/test/Isl/CodeGen/intrinsics_lifetime.ll
new file mode 100644
index 0000000..7f2eb51
--- /dev/null
+++ b/final/test/Isl/CodeGen/intrinsics_lifetime.ll
@@ -0,0 +1,85 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-codegen -S < %s | FileCheck %s
+;
+; Verify that we remove the lifetime markers from the optimized SCoP.
+;
+; CHECK: for.body:
+; CHECK:   call void @llvm.lifetime.start
+; CHECK: for.end:
+; CHECK:   call void @llvm.lifetime.end
+; 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..9b0acb0
--- /dev/null
+++ b/final/test/Isl/CodeGen/intrinsics_misc.ll
@@ -0,0 +1,100 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/loop_with_condition.ll b/final/test/Isl/CodeGen/loop_with_condition.ll
new file mode 100644
index 0000000..bd55357
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition.ll
@@ -0,0 +1,174 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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 {
+; <label>:0
+  fence seq_cst
+  br label %1
+
+; <label>:1                                       ; preds = %7, %0
+  %indvar = phi i64 [ %indvar.next, %7 ], [ 0, %0 ] ; <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 %2, label %8
+
+; <label>:2                                       ; preds = %1
+  %3 = icmp sle i32 %i.0, 512                     ; <i1> [#uses=1]
+  br i1 %3, label %4, label %5
+
+; <label>:4                                       ; preds = %2
+  store i32 1, i32* %scevgep
+  br label %6
+
+; <label>:5                                       ; preds = %2
+  store i32 2, i32* %scevgep
+  br label %6
+
+; <label>:6                                       ; preds = %5, %4
+  store i32 3, i32* %scevgep1
+  br label %7
+
+; <label>:7                                       ; preds = %6
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %1
+
+; <label>:8                                       ; preds = %1
+  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 <= 512) {
+; CHECK:     Stmt_4(c0);
+; CHECK:   } else
+; CHECK:     Stmt_5(c0);
+; CHECK:   Stmt_6(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..e013a75
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition_2.ll
@@ -0,0 +1,140 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 (m + 1024 >= c0) {
+; CHECK:     Stmt_if_then(c0);
+; CHECK:   } else
+; CHECK:     Stmt_if_else(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..d440b20
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition_ineq.ll
@@ -0,0 +1,174 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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 {
+; <label>:0
+  fence seq_cst
+  br label %1
+
+; <label>:1                                       ; preds = %7, %0
+  %indvar = phi i64 [ %indvar.next, %7 ], [ 0, %0 ] ; <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 %2, label %8
+
+; <label>:2                                       ; preds = %1
+  %3 = icmp ne i32 %i.0, 512                      ; <i1> [#uses=1]
+  br i1 %3, label %4, label %5
+
+; <label>:4                                       ; preds = %2
+  store i32 1, i32* %scevgep
+  br label %6
+
+; <label>:5                                       ; preds = %2
+  store i32 2, i32* %scevgep
+  br label %6
+
+; <label>:6                                       ; preds = %5, %4
+  store i32 3, i32* %scevgep1
+  br label %7
+
+; <label>:7                                       ; preds = %6
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %1
+
+; <label>:8                                       ; preds = %1
+  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 >= 513 || c0 <= 511) {
+; CHECK:     Stmt_4(c0);
+; CHECK:   } else
+; CHECK:     Stmt_5(512);
+; CHECK:   Stmt_6(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..411c269
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_condition_nested.ll
@@ -0,0 +1,217 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -basicaa -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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 {
+; <label>:0
+  fence seq_cst
+  br label %1
+
+; <label>:1                                       ; preds = %10, %0
+  %indvar = phi i64 [ %indvar.next, %10 ], [ 0, %0 ] ; <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 %2, label %11
+
+; <label>:2                                       ; preds = %1
+  %3 = icmp sle i32 %i.0, 512                     ; <i1> [#uses=1]
+  br i1 %3, label %4, label %9
+
+; <label>:4                                       ; preds = %2
+  %5 = icmp sgt i32 %i.0, 20                      ; <i1> [#uses=1]
+  br i1 %5, label %6, label %7
+
+; <label>:6                                       ; preds = %4
+  store i32 1, i32* %scevgep
+  br label %8
+
+; <label>:7                                       ; preds = %4
+  store i32 2, i32* %scevgep
+  br label %8
+
+; <label>:8                                       ; preds = %7, %6
+  br label %9
+
+; <label>:9                                       ; preds = %8, %2
+  store i32 3, i32* %scevgep1
+  br label %10
+
+; <label>:10                                      ; preds = %9
+  %indvar.next = add i64 %indvar, 1               ; <i64> [#uses=1]
+  br label %1
+
+; <label>:11                                      ; preds = %1
+  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 >= 21 && c0 <= 512) {
+; CHECK:     Stmt_6(c0);
+; CHECK:   } else if (c0 <= 20)
+; CHECK:     Stmt_7(c0);
+; CHECK:   Stmt_9(c0);
+; CHECK: }
+
+; LOOPS: Printing analysis 'Natural Loop Information' for function 'loop_with_condition':
+; LOOPS: Loop at depth 1 containing: %1<header><exiting>,%2,%4,%7,%6,%8,%9,%10<latch>
+; LOOPS: Loop at depth 1 containing:
+; LOOPS: %polly.loop_header<header>,%polly.cond,%polly.merge,%polly.then,%polly.else,%polly.stmt.,%polly.cond3,%polly.merge4,%polly.then5,%polly.else6,%polly.stmt.7,%polly.stmt{{.*}}<latch><exiting>
diff --git a/final/test/Isl/CodeGen/loop_with_conditional_entry_edge_splited_hard_case.ll b/final/test/Isl/CodeGen/loop_with_conditional_entry_edge_splited_hard_case.ll
new file mode 100644
index 0000000..fc3111f
--- /dev/null
+++ b/final/test/Isl/CodeGen/loop_with_conditional_entry_edge_splited_hard_case.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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: 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.entering.block
+  br i1 %tobool, label %while.end, label %if
+
+; CHECK: polly.entering.block:
+; CHECK:   br label %polly.split_new_and_old
+
+; CHECK: polly.split_new_and_old:
+; CHECK:   br i1 true, label %polly.start, label %if.split
+
+; CHECK: if.split:
+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/multidim-non-matching-typesize-2.ll b/final/test/Isl/CodeGen/multidim-non-matching-typesize-2.ll
new file mode 100644
index 0000000..d1c9c79
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim-non-matching-typesize-2.ll
@@ -0,0 +1,25 @@
+; RUN: opt %loadPolly -polly-codegen -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..d3e2690
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim-non-matching-typesize.ll
@@ -0,0 +1,23 @@
+; RUN: opt %loadPolly -polly-codegen -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..8d87424
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim_2d_parametric_array_static_loop_bounds.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -S -polly-delinearize < %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..4e2ba4a
--- /dev/null
+++ b/final/test/Isl/CodeGen/multidim_alias_check.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-codegen -polly-delinearize < %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/no_guard_bb.ll b/final/test/Isl/CodeGen/no_guard_bb.ll
new file mode 100644
index 0000000..1e0d771
--- /dev/null
+++ b/final/test/Isl/CodeGen/no_guard_bb.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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-phi-node-expansion.ll b/final/test/Isl/CodeGen/non-affine-phi-node-expansion.ll
new file mode 100644
index 0000000..461eaa6
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-phi-node-expansion.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-codegen -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: polly.stmt.bb3.entry:                             ; preds = %polly.start
+; CHECK:   br label %polly.stmt.bb3
+
+; CHECK: polly.stmt.bb3:                                   ; preds = %polly.stmt.bb3.entry
+; CHECK:   %polly.subregion.iv = phi i32 [ 0, %polly.stmt.bb3.entry ]
+; CHECK:   %polly.subregion.iv.inc = add i32 %polly.subregion.iv, 1
+; 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:   %tmp7_p_scalar_ = load i32, i32* %B, !alias.scope !0, !noalias !2
+; CHECK:   store i32 %tmp7_p_scalar_, i32* %polly.access.cast.arg2, !alias.scope !3, !noalias !4
+; CHECK:   br label %polly.stmt.bb13.exit
+
+; 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
+  unreachable
+}
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..f45ab55
--- /dev/null
+++ b/final/test/Isl/CodeGen/non-affine-subregion-dominance-reuse.ll
@@ -0,0 +1,74 @@
+; RUN: opt %loadPolly -polly-codegen -S -verify-dom-info < %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_float_compare.ll b/final/test/Isl/CodeGen/non_affine_float_compare.ll
new file mode 100644
index 0000000..13f3b07
--- /dev/null
+++ b/final/test/Isl/CodeGen/non_affine_float_compare.ll
@@ -0,0 +1,78 @@
+; RUN: opt %loadPolly -polly-codegen -polly-no-early-exit -polly-allow-nonaffine-branches -S -verify-dom-info < %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, 1022
+; 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/openmp_limit_threads.ll b/final/test/Isl/CodeGen/openmp_limit_threads.ll
new file mode 100644
index 0000000..93c259e
--- /dev/null
+++ b/final/test/Isl/CodeGen/openmp_limit_threads.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-codegen -polly-parallel -S < %s | FileCheck %s --check-prefix=AUTO
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-codegen -polly-parallel -polly-num-threads=1 -S < %s | FileCheck %s --check-prefix=ONE
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/phi_condition_modeling_1.ll b/final/test/Isl/CodeGen/phi_condition_modeling_1.ll
new file mode 100644
index 0000000..4d8e5a3
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_condition_modeling_1.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -S -polly-no-early-exit -polly-detect-unprofitable -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.bb6:
+; CHECK:       store i32 3, i32* %tmp.0.phiops
+; CHECK-LABEL: polly.stmt.bb7:
+; CHECK:       store i32 5, 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..e9a64dd
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_condition_modeling_2.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -S -polly-no-early-exit -polly-detect-unprofitable  -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.bb6:
+; CHECK:       store i32 3, i32* %tmp.0.phiops
+; CHECK-LABEL: polly.stmt.bb7:
+; CHECK:       store i32 5, 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..be01724
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_conditional_simple_1.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -analyze -polly-ast -polly-no-early-exit -polly-detect-unprofitable < %s | FileCheck %s --check-prefix=AST
+; RUN: opt %loadPolly -S -polly-no-early-exit -polly-detect-unprofitable -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 == 0) {
+; AST:        Stmt_if_else(c0);
+; AST:      } else if (c <= -1 || c >= 1)
+; AST:        Stmt_if_then(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.else:
+; CHECK-NEXT:     store i32 2, i32* %phi.phiops
+; CHECK-NEXT:     br label %polly.merge{{[.]?}}
+; CHECK-LABEL:  polly.stmt.if.then:
+; CHECK-NEXT:     store i32 1, 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_loop_carried_float.ll b/final/test/Isl/CodeGen/phi_loop_carried_float.ll
new file mode 100644
index 0000000..aecb6a4
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_loop_carried_float.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -S -polly-no-early-exit -polly-detect-unprofitable  -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:      polly.merge_new_and_old:
+; CHECK-NEXT:  ret
+;
+; CHECK:      polly.start:
+; CHECK-NEXT:   store float 0.000000e+00, float* %tmp.0.phiops
+
+; CHECK:      polly.merge:
+; CHECK-NEXT:   br label %polly.merge_new_and_old
+
+; CHECK:      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:      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
+
+; CHECK: polly.stmt.bb4:                                   ; preds = %polly.then3
+; CHECK:   %tmp[[R5:[0-9]*]]_p_scalar_ = load float, float* %scevgep, align 4, !alias.scope !0, !noalias !2
+; CHECK:   %tmp.0.s2a.reload[[R3:[0-9]*]] = load float, float* %tmp.0.s2a
+; 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
+
+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..6db8bd7
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_loop_carried_float_escape.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -S -polly-no-early-exit -polly-detect-unprofitable  -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:      polly.merge_new_and_old:
+; CHECK-NEXT:   %tmp.0.merge = phi float [ %tmp.0.final_reload, %polly.merge ], [ %tmp.0, %bb8 ]
+; CHECK-NEXT:   ret float %tmp.0.merge
+;
+; CHECK:      polly.start:
+; CHECK-NEXT:   store float 0.000000e+00, float* %tmp.0.phiops
+
+; CHECK:      polly.merge:
+; CHECK-NEXT:   %tmp.0.final_reload = load float, float* %tmp.0.s2a
+; CHECK-NEXT:   br label %polly.merge_new_and_old
+
+; CHECK:      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:      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
+
+; CHECK: polly.stmt.bb4:                                   ; preds = %polly.then3
+; CHECK:   %tmp[[R5:[0-9]*]]_p_scalar_ = load float, float* %scevgep, align 4, !alias.scope !0, !noalias !2
+; CHECK:   %tmp.0.s2a.reload[[R3:[0-9]*]] = load float, float* %tmp.0.s2a
+; 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
+
+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..13cab99
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_scalar_simple_1.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -S -polly-detect-unprofitable -polly-no-early-exit -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.merge ], [ %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-LABEL: polly.merge:
+; 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
+
+; 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
+
+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.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.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.body3:                                        ; preds = %for.cond1
+  br label %for.inc
+
+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.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..361563a
--- /dev/null
+++ b/final/test/Isl/CodeGen/phi_scalar_simple_2.ll
@@ -0,0 +1,108 @@
+; RUN: opt %loadPolly -S -polly-detect-unprofitable -polly-no-early-exit -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.merge ], [ %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-LABEL: polly.merge:
+; 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
+
+; 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
+
+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/pointer-type-expressions-2.ll b/final/test/Isl/CodeGen/pointer-type-expressions-2.ll
new file mode 100644
index 0000000..68b23fe
--- /dev/null
+++ b/final/test/Isl/CodeGen/pointer-type-expressions-2.ll
@@ -0,0 +1,29 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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);
+
+; Check that we transform this into a pointer difference.
+
+; CODEGEN: %0 = ptrtoint i8* %end to i64
+; CODEGEN: %1 = ptrtoint i8* %start to i64
+; CODEGEN: %2 = sub i64 %0, %1
+
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..e3c24a7
--- /dev/null
+++ b/final/test/Isl/CodeGen/pointer-type-expressions.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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) {
+; CHECK:   for (int c0 = 0; c0 < N; c0 += 1)
+; CHECK:     Stmt_store(c0);
+; CHECK: } else if (P >= 1)
+; CHECK:   for (int c0 = 0; c0 < N; c0 += 1)
+; CHECK:     Stmt_store(c0);
+; CHECK: }
+
+; CODEGEN:   %0 = bitcast float* %P to i8*
+; CODEGEN:   %1 = icmp ule i8* %0, inttoptr (i64 -1 to i8*)
+
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..61f4606
--- /dev/null
+++ b/final/test/Isl/CodeGen/pointer-type-pointer-type-comparison.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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 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) {
+; CHECK:   for (int c0 = 0; c0 < N; c0 += 1)
+; CHECK:     Stmt_store(c0);
+; CHECK: } else if (P >= Q + 1)
+; CHECK:   for (int c0 = 0; c0 < N; c0 += 1)
+; CHECK:     Stmt_store(c0);
+; CHECK: }
+
+; CODEGEN:       %[[Pinc:[_a-zA-Z0-9]+]] = getelementptr float, float* %P, i64 1
+; CODEGEN-NEXT:                             icmp uge float* %Q, %[[Pinc]]
+; CODEGEN:       %[[Qinc:[_a-zA-Z0-9]+]] = getelementptr float, float* %Q, i64 1
+; CODEGEN-NEXT:                             icmp uge float* %P, %[[Qinc]]
diff --git a/final/test/Isl/CodeGen/reduction.ll b/final/test/Isl/CodeGen/reduction.ll
new file mode 100644
index 0000000..e99b4bf
--- /dev/null
+++ b/final/test/Isl/CodeGen/reduction.ll
@@ -0,0 +1,88 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..2810cfb
--- /dev/null
+++ b/final/test/Isl/CodeGen/reduction_2.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -basicaa -polly-ast -analyze < %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
+
+; CHECK: for (int c0 = 0; c0 <= 1018; c0 += 1)
+; CHECK:   Stmt_for_body(c0);
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..bc9dce5
--- /dev/null
+++ b/final/test/Isl/CodeGen/reduction_simple_binary.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/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..1fbc3c6
--- /dev/null
+++ b/final/test/Isl/CodeGen/run-time-condition-with-scev-parameters.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -S -polly-delinearize < %s | FileCheck %s
+
+; CHECK: polly.split_new_and_old:
+; CHECK-NEXT: %1 = zext i32 %n to i64
+; CHECK-NEXT: %2 = icmp sge i64 %1, 1
+; CHECK-NEXT: br i1 %2, 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..25eb8b8
--- /dev/null
+++ b/final/test/Isl/CodeGen/run-time-condition.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..55ae8de
--- /dev/null
+++ b/final/test/Isl/CodeGen/scalar-references-used-in-scop-compute.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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/scev.ll b/final/test/Isl/CodeGen/scev.ll
new file mode 100644
index 0000000..b1b1fbb
--- /dev/null
+++ b/final/test/Isl/CodeGen/scev.ll
@@ -0,0 +1,21 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/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..2b6c1b9
--- /dev/null
+++ b/final/test/Isl/CodeGen/scop_never_executed_runtime_check_location.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -S -polly-delinearize < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -S -polly-delinearize < %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: zext i32 %n to i64
+; CHECK: br i1 false
+;
+; CHECK: %[[T0:[._a-zA-Z0-9]]] = zext 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/sequential_loops.ll b/final/test/Isl/CodeGen/sequential_loops.ll
new file mode 100644
index 0000000..0a7d80b
--- /dev/null
+++ b/final/test/Isl/CodeGen/sequential_loops.ll
@@ -0,0 +1,137 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..663d62e
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_loop_non_single_exit.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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: Create LLVM-IR from SCoPs' for region: 'next => polly.merge_new_and_old'
+; 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..abd9c92
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_loop_non_single_exit_2.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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: Create LLVM-IR from SCoPs' for region: 'for.i => return'
+; 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..579789f
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_non_single_entry.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-detect-scops-in-regions-without-loops -polly-codegen -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-detect-scops-in-regions-without-loops -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:
+  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: Create LLVM-IR from SCoPs' for region: 'next.split => polly.merge_new_and_old'
+; 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..51aed95
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_nonaffine_loop.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..e1a6151
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_assign_scalar.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-codegen -polly-vectorizer=polly -dce -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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>*), align 8, !alias.scope !3, !noalias !4
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..b4cbbc6
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_assign_scalar_2.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..a7b5d6b
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_call.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-codegen -polly-vectorizer=polly -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: %value_p_splat_one = load <1 x float>, <1 x float>* bitcast ([1024 x float]* @A to <1 x float>*), align 8
+; CHECK: %value_p_splat = shufflevector <1 x float> %value_p_splat_one, <1 x float> %value_p_splat_one, <4 x i32> zeroinitializer
+; CHECK: %0 = extractelement <4 x float> %value_p_splat, i32 0
+; CHECK: %1 = extractelement <4 x float> %value_p_splat, i32 1
+; CHECK: %2 = extractelement <4 x float> %value_p_splat, i32 2
+; CHECK: %3 = extractelement <4 x float> %value_p_splat, i32 3
+; CHECK: [[RES1:%[a-zA-Z0-9_]+]] = tail call float @foo(float %0) [[NUW:#[0-9]+]]
+; CHECK: [[RES2:%[a-zA-Z0-9_]+]] = tail call float @foo(float %1) [[NUW]]
+; CHECK: [[RES3:%[a-zA-Z0-9_]+]] = tail call float @foo(float %2) [[NUW]]
+; CHECK: [[RES4:%[a-zA-Z0-9_]+]] = tail call float @foo(float %3) [[NUW]]
+; CHECK: %4 = insertelement <4 x float> undef, float [[RES1]], i32 0
+; CHECK: %5 = insertelement <4 x float> %4, float [[RES2]], i32 1
+; CHECK: %6 = insertelement <4 x float> %5, float [[RES3]], i32 2
+; CHECK: %7 = insertelement <4 x float> %6, float [[RES4]], i32 3
+; CHECK:  store <4 x float> %7
+; 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..0b0a512
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_call_2.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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
+
+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: %value_p_splat_one = load <1 x float>, <1 x float>* bitcast ([1024 x float]* @A to <1 x float>*), align 8
+; CHECK: %value_p_splat = shufflevector <1 x float> %value_p_splat_one, <1 x float> %value_p_splat_one, <4 x i32> zeroinitializer
+; CHECK: %0 = extractelement <4 x float> %value_p_splat, i32 0
+; CHECK: %1 = extractelement <4 x float> %value_p_splat, i32 1
+; CHECK: %2 = extractelement <4 x float> %value_p_splat, i32 2
+; CHECK: %3 = extractelement <4 x float> %value_p_splat, i32 3
+; CHECK: [[RES1:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %0) [[NUW:#[0-9]+]]
+; CHECK: [[RES2:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %1) [[NUW]]
+; CHECK: [[RES3:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %2) [[NUW]]
+; CHECK: [[RES4:%[a-zA-Z0-9_]+]] = tail call float** @foo(float %3) [[NUW]]
+; CHECK: %4 = insertelement <4 x float**> undef, float** %p_result, i32 0
+; CHECK: %5 = insertelement <4 x float**> %4, float** %p_result1, i32 1
+; CHECK: %6 = insertelement <4 x float**> %5, float** %p_result2, i32 2
+; CHECK: %7 = insertelement <4 x float**> %6, float** %p_result3, i32 3
+; CHECK: store <4 x float**> %7, <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..e7501a1
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_cast.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-codegen -polly-vectorizer=polly -dce -S < %s | FileCheck %s -check-prefix=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 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: %tmp_p_splat_one = load <1 x float>, <1 x float>* bitcast ([1024 x float]* @A to <1 x float>*), align 8, !alias.scope !0, !noalias !2
+; CHECK: %tmp_p_splat = shufflevector <1 x float> %tmp_p_splat_one, <1 x float> %tmp_p_splat_one, <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>* bitcast ([1024 x double]* @B to <4 x double>*), align 8, !alias.scope !3, !noalias !4
+
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..b59b829
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_const.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-codegen -polly-vectorizer=polly -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[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 <1 x float>, <1 x float>* bitcast ([1024 x float]* @A to <1 x float>*)
+; CHECK: shufflevector <1 x float> {{.*}}, <1 x float> {{.*}} <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..5489602
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_large_width.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..343c017
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_ptr_ptr_ty.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-codegen -polly-vectorizer=polly -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
+  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: %value_p_splat_one = load <1 x float**>, <1 x float**>* bitcast ([1024 x float**]* @A to <1 x float**>*), align 8
+; CHECK: %value_p_splat = shufflevector <1 x float**> %value_p_splat_one, <1 x float**> %value_p_splat_one, <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..ef9efdf
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_stride_negative_one.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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_x.ll b/final/test/Isl/CodeGen/simple_vec_stride_x.ll
new file mode 100644
index 0000000..17b5e49
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_stride_x.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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_two_stmts.ll b/final/test/Isl/CodeGen/simple_vec_two_stmts.ll
new file mode 100644
index 0000000..bc42c50
--- /dev/null
+++ b/final/test/Isl/CodeGen/simple_vec_two_stmts.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..21bd5cb
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_int_max_iterations.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..d68f389
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_int_param_iterations.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..236d5b0
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_ll_max_iterations.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-ast -analyze  -S < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..12d63e7
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_one_iteration.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..4afdd11
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_do_loop_scev_replace.ll
@@ -0,0 +1,94 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..d0ee7fe
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop.ll
@@ -0,0 +1,84 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..aa20ef0
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_int_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..44c7350
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_ll_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..38c1e8c
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_one_iteration.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..009aa4e
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_param.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..62c0b79
--- /dev/null
+++ b/final/test/Isl/CodeGen/single_loop_zero_iterations.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: for region: 'for.cond => for.end' in function 'main':
+; SCALAR-NOT:   Stmt_for_body(0);
diff --git a/final/test/Isl/CodeGen/split_edges.ll b/final/test/Isl/CodeGen/split_edges.ll
new file mode 100644
index 0000000..2c226e3
--- /dev/null
+++ b/final/test/Isl/CodeGen/split_edges.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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"
+
+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]
+  %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..e772d43
--- /dev/null
+++ b/final/test/Isl/CodeGen/split_edges_2.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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"
+
+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]
+  %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..08dc545
--- /dev/null
+++ b/final/test/Isl/CodeGen/srem-in-other-bb.ll
@@ -0,0 +1,38 @@
+; RUN: opt %loadPolly -polly-codegen -S -polly-no-early-exit < %s | FileCheck %s
+;
+;    void pos(float *A, long n) {
+;      for (long i = 0; i < 100; i++)
+;        A[n % 42] += 1;
+;    }
+;
+; CHECK: polly.stmt.bb3:
+; CHECK: %p_tmp.moved.to.bb3 = srem i64 %n, 42
+; CHECK: %p_tmp3 = getelementptr inbounds float, float* %A, i64 %p_tmp.moved.to.bb3
+
+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/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..c798e5f
--- /dev/null
+++ b/final/test/Isl/CodeGen/test-invalid-operands-for-select-2.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -S -polly-code-generator=isl -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..9bd3188
--- /dev/null
+++ b/final/test/Isl/CodeGen/test-invalid-operands-for-select.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -S -polly-code-generator=isl -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..6ae1082
--- /dev/null
+++ b/final/test/Isl/CodeGen/test.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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-scops-in-row.ll b/final/test/Isl/CodeGen/two-scops-in-row.ll
new file mode 100644
index 0000000..25bfe67
--- /dev/null
+++ b/final/test/Isl/CodeGen/two-scops-in-row.ll
@@ -0,0 +1,41 @@
+
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-ast -analyze -polly-ignore-aliasing < %s | FileCheck %s -check-prefix=SCALAR
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen -polly-ignore-aliasing -disable-output < %s
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; SCALAR: if (1)
+; SCALAR:     {
+; SCALAR:       for (int c0 = 0; c0 <= -Scalar0.val + 99; c0 += 1)
+; SCALAR:         Stmt_for_1(c0);
+; SCALAR:       if (Scalar0.val >= 100)
+; SCALAR:         Stmt_for_1(0);
+; 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
+  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/single_loop_param_less_equal.ll b/final/test/Isl/single_loop_param_less_equal.ll
new file mode 100644
index 0000000..bf3a54f
--- /dev/null
+++ b/final/test/Isl/single_loop_param_less_equal.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-codegen  -S < %s | FileCheck %s -check-prefix=CODEGEN
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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.adjust_ub = sub i64 %n, 1
+; CODEGEN:   %polly.loop_cond = icmp sle i64 %polly.indvar, %polly.adjust_ub
+; 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: Loop at depth 1 containing: %loop.header<header><exiting>,%loop.body,%loop.backedge<latch>
+; LOOPS: 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..67887d4
--- /dev/null
+++ b/final/test/Isl/single_loop_param_less_than.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -polly-ast -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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.adjust_ub = sub i64 %n, 1
+; CODEGEN:   %polly.loop_cond = icmp slt i64 %polly.indvar, %polly.adjust_ub
+; 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..7c05095
--- /dev/null
+++ b/final/test/Isl/single_loop_uint_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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..d069140
--- /dev/null
+++ b/final/test/Isl/single_loop_ull_max_iterations.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-no-early-exit -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/Makefile b/final/test/Makefile
new file mode 100644
index 0000000..bab51fe
--- /dev/null
+++ b/final/test/Makefile
@@ -0,0 +1,63 @@
+LEVEL := ..
+include $(LEVEL)/Makefile.common
+
+# Test in all immediate subdirectories if unset.
+ifdef TESTSUITE
+TESTDIRS := $(TESTSUITE:%=$(PROJ_SRC_DIR)/%)
+else
+TESTDIRS ?= $(PROJ_SRC_DIR)
+endif
+
+# 'lit' wants objdir paths, so it will pick up the lit.site.cfg.
+TESTDIRS := $(TESTDIRS:$(PROJ_SRC_DIR)%=$(PROJ_OBJ_DIR)%)
+
+# Allow EXTRA_TESTDIRS to provide additional test directories.
+TESTDIRS += $(EXTRA_TESTDIRS)
+
+ifndef TESTARGS
+ifdef VERBOSE
+TESTARGS = -v
+else
+TESTARGS = -s -v
+endif
+endif
+
+# Make sure any extra test suites can find the main site config.
+LIT_ARGS := --param polly_site_config=${PROJ_OBJ_DIR}/lit.site.cfg \
+            --param build_config=$(PROJ_OBJ_DIR)
+
+
+ifdef VG
+  LIT_ARGS += "--vg"
+endif
+
+
+check-polly:: lit.site.cfg polly-lib
+	@ echo '--- Running polly tests for $(TARGET_TRIPLE) ---'
+	@ $(PYTHON) $(LLVM_SRC_ROOT)/utils/lit/lit.py \
+	  $(LIT_ARGS) $(TESTARGS) $(TESTDIRS)
+
+FORCE:
+
+polly-lib: FORCE
+	$(MAKE) -C ../lib || exit 1;
+
+lit.site.cfg: FORCE
+	@echo "Making Polly 'lit.site.cfg' file..."
+	@sed -e "s#@LLVM_SOURCE_DIR@#$(LLVM_SRC_ROOT)#g" \
+	     -e "s#@LLVM_BINARY_DIR@#$(LLVM_OBJ_ROOT)#g" \
+	     -e "s#@LLVM_TOOLS_DIR@#$(LLVM_OBJ_ROOT)/$(BuildMode)/bin#g" \
+	     -e "s#@LLVM_LIBS_DIR@#$(LibDir)#g" \
+	     -e "s#@POLLY_SOURCE_DIR@#$(PROJ_SRC_DIR)/..#g" \
+	     -e "s#@POLLY_BINARY_DIR@#$(PROJ_OBJ_DIR)/..#g" \
+	     -e "s#@TARGET_TRIPLE@#$(TARGET_TRIPLE)#g" \
+	     -e "s#@LLVM_SHLIBEXT@#$(SHLIBEXT)#g" \
+             -e "s#@POLLY_LIB_DIR@#$(LibDir)#g" \
+             -e "s#@LINK_POLLY_INTO_TOOLS@#OFF#g" \
+             -e "s#@CUDALIB_FOUND@#$(CUDALIB_FOUND)#g" \
+	     $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
+
+clean::
+	@ find . -name Output | xargs rm -fr
+
+.PHONY: check-polly clean
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/ScheduleOptimizer/2012-03-16-Empty-Domain.ll b/final/test/ScheduleOptimizer/2012-03-16-Empty-Domain.ll
new file mode 100644
index 0000000..803b685
--- /dev/null
+++ b/final/test/ScheduleOptimizer/2012-03-16-Empty-Domain.ll
@@ -0,0 +1,16 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..561b023
--- /dev/null
+++ b/final/test/ScheduleOptimizer/2012-04-16-Trivially-vectorizable-loops.ll
@@ -0,0 +1,204 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/2012-10-14-Zero-Bands.ll b/final/test/ScheduleOptimizer/2012-10-14-Zero-Bands.ll
new file mode 100644
index 0000000..673e79c
--- /dev/null
+++ b/final/test/ScheduleOptimizer/2012-10-14-Zero-Bands.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect-scops-in-regions-without-loops -polly-detect-scops-in-functions-without-loops -polly-opt-isl -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"
+
+@A = common global [1536 x float] zeroinitializer
+
+define void @read_nres() {
+entry:
+  br label %if.cond
+
+if.cond:
+  br i1 false, label %if.then, label %if.end
+
+if.then:
+  %ptr = getelementptr [1536 x float], [1536 x float]* @A, i64 0, i32 23
+  store float undef, float* %ptr
+  br label %if.end
+
+if.end:
+  br label %return
+
+return:
+  ret void
+}
+
+; CHECK: Calculated schedule:
+; CHECK-NOT: Stmt_if_then
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..26b19a2
--- /dev/null
+++ b/final/test/ScheduleOptimizer/2013-04-11-Empty-Domain-two.ll
@@ -0,0 +1,23 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..17c7bb5
--- /dev/null
+++ b/final/test/ScheduleOptimizer/computeout.ll
@@ -0,0 +1,69 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-opt-isl -polly-opt-fusion=max -polly-ast -analyze -polly-no-early-exit < %s | FileCheck %s 
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-opt-isl -polly-opt-fusion=max -polly-ast -analyze -polly-no-early-exit -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/line-tiling-2.ll b/final/test/ScheduleOptimizer/line-tiling-2.ll
new file mode 100644
index 0000000..fffc79b
--- /dev/null
+++ b/final/test/ScheduleOptimizer/line-tiling-2.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-no-tiling=0 -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..315fcc2
--- /dev/null
+++ b/final/test/ScheduleOptimizer/line-tiling.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/one-dimensional-band.ll b/final/test/ScheduleOptimizer/one-dimensional-band.ll
new file mode 100644
index 0000000..3f63353
--- /dev/null
+++ b/final/test/ScheduleOptimizer/one-dimensional-band.ll
@@ -0,0 +1,107 @@
+; RUN: opt %loadPolly -polly-opt-isl -polly-ast -analyze -polly-no-early-exit < %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/prevectorization.ll b/final/test/ScheduleOptimizer/prevectorization.ll
new file mode 100644
index 0000000..5a5cccc
--- /dev/null
+++ b/final/test/ScheduleOptimizer/prevectorization.ll
@@ -0,0 +1,78 @@
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-opt-isl -polly-vectorizer=polly -polly-ast -analyze < %s | FileCheck %s 
+; RUN: opt -S %loadPolly -polly-detect-unprofitable -basicaa -polly-opt-isl -polly-vectorizer=stripmine -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 <= 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 <= 31; c3 += 4)
+; CHECK:         #pragma simd
+; CHECK:         for (int c4 = c3; c4 <= c3 + 3; c4 += 1)
+; CHECK:           Stmt_for_body3(32 * c0 + c2, 32 * c1 + 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 <= 31; c4 += 4)
+; CHECK:           for (int c5 = 0; c5 <= 31; c5 += 1)
+; CHECK:             #pragma simd
+; CHECK:             for (int c6 = c4; c6 <= c4 + 3; c6 += 1)
+; CHECK:               Stmt_for_body8(32 * c0 + c3, 32 * c1 + c6, 32 * c2 + c5);
+
+!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..62d4886
--- /dev/null
+++ b/final/test/ScheduleOptimizer/rectangular-tiling.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-ast -polly-tile-sizes=256,16 < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-opt-isl -analyze -polly-no-tiling -polly-ast -polly-tile-sizes=256,16 -polly-no-early-exit < %s | FileCheck %s --check-prefix=NOTILING
+
+; CHECK: for (int c0 = 0; c0 <= 3; c0 += 1)
+; CHECK:   for (int c1 = 0; c1 <= 31; c1 += 1)
+; 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);
+
+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/ScopDetect/aliasing_parametric_simple_1.ll b/final/test/ScopDetect/aliasing_parametric_simple_1.ll
new file mode 100644
index 0000000..f05ebe8
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_parametric_simple_1.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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..aa482c5
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_parametric_simple_2.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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..f3971c3
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_simple_1.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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..98c3611
--- /dev/null
+++ b/final/test/ScopDetect/aliasing_simple_2.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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..3d52f91
--- /dev/null
+++ b/final/test/ScopDetect/base_pointer.ll
@@ -0,0 +1,296 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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"
+
+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: for.i => then
+
+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 ]
+; 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)
+  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: Valid Region for Scop: for.i => exit
+
+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: Valid Region for Scop: for.i => exit
+
+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-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..40b72e0
--- /dev/null
+++ b/final/test/ScopDetect/cross_loop_non_single_exit.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..aae0d7f
--- /dev/null
+++ b/final/test/ScopDetect/cross_loop_non_single_exit_2.ll
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..5bf19f5
--- /dev/null
+++ b/final/test/ScopDetect/dependency_to_phi_node_outside_of_region.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/indvars.ll b/final/test/ScopDetect/indvars.ll
new file mode 100644
index 0000000..cda5a16
--- /dev/null
+++ b/final/test/ScopDetect/indvars.ll
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -analyze -polly-detect -polly-codegen < %s | FileCheck %s
+;
+; When a region header is part of a loop, then all entering edges of this region
+; should not come from the loop but outside the region.
+
+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) 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
+  %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.j => for.j2
diff --git a/final/test/ScopDetect/intrinsics_1.ll b/final/test/ScopDetect/intrinsics_1.ll
new file mode 100644
index 0000000..77f8344
--- /dev/null
+++ b/final/test/ScopDetect/intrinsics_1.ll
@@ -0,0 +1,106 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..8cb20cd
--- /dev/null
+++ b/final/test/ScopDetect/intrinsics_2.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..a58dae8
--- /dev/null
+++ b/final/test/ScopDetect/intrinsics_3.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/invalidate_scalar_evolution.ll b/final/test/ScopDetect/invalidate_scalar_evolution.ll
new file mode 100644
index 0000000..6134fde
--- /dev/null
+++ b/final/test/ScopDetect/invalidate_scalar_evolution.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/keep_going_expansion.ll b/final/test/ScopDetect/keep_going_expansion.ll
new file mode 100644
index 0000000..cc46b8a
--- /dev/null
+++ b/final/test/ScopDetect/keep_going_expansion.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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.cond2.preheader
diff --git a/final/test/ScopDetect/multidim_indirect_access.ll b/final/test/ScopDetect/multidim_indirect_access.ll
new file mode 100644
index 0000000..9917491
--- /dev/null
+++ b/final/test/ScopDetect/multidim_indirect_access.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s --check-prefix=INDEPENDENT
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze  < %s | FileCheck %s --check-prefix=NON_INDEPENDENT
+;
+; With the IndependentBlocks and PollyPrepare passes this will __correctly__
+; not be recognized as a SCoP and the debug states:
+;
+;   SCEV of PHI node refers to SSA names in region
+;
+; Without IndependentBlocks and PollyPrepare the access A[x] is mistakenly
+; treated as a multidimensional access with dimension size x. This test will
+; check that we correctly invalidate the region and do not detect a outer SCoP.
+;
+; FIXME:
+; We should detect the inner region but the PHI node in the exit blocks that.
+;
+;    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);
+;      }
+;    }
+;
+; INDEPENDENT-NOT: Valid
+; NON_INDEPENDENT-NOT: Valid
+;
+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..256e270
--- /dev/null
+++ b/final/test/ScopDetect/multidim_two_accesses_different_delinearization.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze -polly-delinearize < %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..18ac9b7
--- /dev/null
+++ b/final/test/ScopDetect/nested_loop_single_exit.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -polly-codegen -analyze < %s | FileCheck %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..d5ed1a9
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-conditional.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine-branches -polly-detect -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..875d220
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-float-compare.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches -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..9bd7ebc
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop-condition-dependent-access.ll
@@ -0,0 +1,57 @@
+; 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
+;
+; 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
+;
+;    void f(int * restrict A, int * restrict C) {
+;      int j;
+;      for (int i = 0; i < 1024; i++) {
+;        while ((j = C[i]))
+;          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
+  %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 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..c5a3f66
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop-condition-dependent-access_2.ll
@@ -0,0 +1,86 @@
+; 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
+;
+; 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 => bb26
+; REJECTNONAFFINELOOPS-NOT:       Valid
+; ALLOWNONAFFINELOOPS:            Valid Region for Scop: bb15 => bb26
+; 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..644af88
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop-condition-dependent-access_3.ll
@@ -0,0 +1,87 @@
+; 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
+;
+; 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 => bb26
+; REJECTNONAFFINELOOPS-NOT:       Valid
+; ALLOWNONAFFINELOOPS:            Valid Region for Scop: bb15 => bb26
+; 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..ad13e3e
--- /dev/null
+++ b/final/test/ScopDetect/non-affine-loop.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=false -analyze < %s | FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPSANDACCESSES
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -polly-allow-nonaffine -polly-detect-scops-in-regions-without-loops -analyze < %s | FileCheck %s --check-prefix=ALLOWNONAFFINELOOPSANDACCESSESANDNOLOOPS
+;
+; 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
+; ALLOWNONAFFINELOOPSANDACCESSES-NOT:       Valid
+; ALLOWNONAFFINELOOPSANDACCESSESANDNOLOOPS: Valid Region for Scop: bb1 => bb10
+;
+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_affine_loop_condition.ll b/final/test/ScopDetect/non_affine_loop_condition.ll
new file mode 100644
index 0000000..f0002ef
--- /dev/null
+++ b/final/test/ScopDetect/non_affine_loop_condition.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-detect -polly-allow-nonaffine-loops -analyze < %s | FileCheck %s
+;
+;    void f(int *A) {
+;      for (int i = 0; i < 1024; i++) {
+;        while (A[i])
+;          A[i]--;
+;      }
+;    }
+;
+; 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/parametric-multiply-in-scev-2.ll b/final/test/ScopDetect/parametric-multiply-in-scev-2.ll
new file mode 100644
index 0000000..beb882d
--- /dev/null
+++ b/final/test/ScopDetect/parametric-multiply-in-scev-2.ll
@@ -0,0 +1,27 @@
+; 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 ]
+  %tmp12 = load i64, i64* %tmp1
+  %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..35f7670
--- /dev/null
+++ b/final/test/ScopDetect/parametric-multiply-in-scev.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect-scops-in-regions-without-loops -polly-detect-scops-in-functions-without-loops -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect-scops-in-regions-without-loops -polly-detect-scops-in-functions-without-loops -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/remove_all_children.ll b/final/test/ScopDetect/remove_all_children.ll
new file mode 100644
index 0000000..ff04ca1
--- /dev/null
+++ b/final/test/ScopDetect/remove_all_children.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..90a879f
--- /dev/null
+++ b/final/test/ScopDetect/report-scop-location.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 {
+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 {
+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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5 ", isOptimized: false, emissionKind: 0, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "test.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!2 = !{}
+!3 = !{!4, !7}
+!4 = !DISubprogram(name: "foo", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 1, file: !1, scope: !5, type: !6, function: void (float*)* @foo, variables: !2)
+!5 = !DIFile(filename: "test.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!6 = !DISubroutineType(types: !{null})
+!7 = !DISubprogram(name: "bar", line: 6, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 6, file: !1, scope: !5, type: !6, function: void (float*)* @bar, 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/run_time_alias_check.ll b/final/test/ScopDetect/run_time_alias_check.ll
new file mode 100644
index 0000000..4d6bfb9
--- /dev/null
+++ b/final/test/ScopDetect/run_time_alias_check.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -polly-code-generator=isl -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/sequential_loops.ll b/final/test/ScopDetect/sequential_loops.ll
new file mode 100644
index 0000000..d012c34
--- /dev/null
+++ b/final/test/ScopDetect/sequential_loops.ll
@@ -0,0 +1,93 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..f019806
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..c1a42ab
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_non_single_entry.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 not detect this scop, as the loop is not in -loop-simplify 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-NOT: 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..161f3a5
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_non_single_exit.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..9640271
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_non_single_exit_2.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..0265402
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_two_phi_nodes.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..e9d9537
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_with_param.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..5d74dd1
--- /dev/null
+++ b/final/test/ScopDetect/simple_loop_with_param_2.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..fb354ad
--- /dev/null
+++ b/final/test/ScopDetect/simple_non_single_entry.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect-scops-in-regions-without-loops -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect-scops-in-regions-without-loops -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.head1
diff --git a/final/test/ScopDetect/skip_function_attribute.ll b/final/test/ScopDetect/skip_function_attribute.ll
new file mode 100644
index 0000000..02177f5
--- /dev/null
+++ b/final/test/ScopDetect/skip_function_attribute.ll
@@ -0,0 +1,44 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/ScopDetectionDiagnostics/ReportAlias-01.ll b/final/test/ScopDetectionDiagnostics/ReportAlias-01.ll
new file mode 100644
index 0000000..f1891f6
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportAlias-01.ll
@@ -0,0 +1,69 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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) {
+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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportAlias-01.c", directory: "test/ScopDetectionDiagnostic/")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 1, file: !1, scope: !5, type: !6, function: void (i32*, i32*)* @f, 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(tag: DW_TAG_arg_variable, name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!14 = !DILocation(line: 1, column: 12, scope: !4)
+!15 = !DILocalVariable(tag: DW_TAG_arg_variable, 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(tag: DW_TAG_auto_variable, 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/ReportDifferentElementSize.ll b/final/test/ScopDetectionDiagnostics/ReportDifferentElementSize.ll
new file mode 100644
index 0000000..5cc59e8
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportDifferentElementSize.ll
@@ -0,0 +1,67 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+
+; 1 void differenttypes(char *A)
+; 2 {
+; 3   for (long i = 0; i < 1024; ++i)
+; 4     ((float*)A)[i] = ((double*)A)[i];
+; 5 }
+
+; CHECK: remark: /tmp/test.c:3:20: The following errors keep this region from being a Scop.
+; CHECK-NEXT: remark: /tmp/test.c:4:14: The array "A" is accessed through elements that differ in size
+; CHECK-NEXT: remark: /tmp/test.c:4:32: Invalid Scop candidate ends here.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @differenttypes(i8* nocapture %A)  {
+entry:
+  br label %for.body, !dbg !10
+
+for.body:                                         ; preds = %for.body, %entry
+  %i.05 = phi i64 [ 0, %entry ], [ %tmp11, %for.body ]
+  %tmp = shl i64 %i.05, 3, !dbg !15
+  %uglygep = getelementptr i8, i8* %A, i64 %tmp
+  %arrayidx = bitcast i8* %uglygep to double*, !dbg !16
+  %tmp9 = shl i64 %i.05, 2, !dbg !15
+  %uglygep7 = getelementptr i8, i8* %A, i64 %tmp9
+  %arrayidx1 = bitcast i8* %uglygep7 to float*, !dbg !17
+  %tmp10 = load double, double* %arrayidx, align 8, !dbg !16, !tbaa !18
+  %conv = fptrunc double %tmp10 to float, !dbg !16
+  store float %conv, float* %arrayidx1, align 4, !dbg !17, !tbaa !22
+  %tmp11 = add nsw i64 %i.05, 1, !dbg !24
+  %exitcond = icmp eq i64 %tmp11, 1024, !dbg !10
+  br i1 %exitcond, label %for.end, label %for.body, !dbg !10
+
+for.end:                                          ; preds = %for.body
+  ret void, !dbg !25
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: true, emissionKind: 2, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly/test/ScopDetectionDiagnostics")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "differenttypes", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, scopeLine: 2, file: !1, scope: !5, type: !6, function: void (i8*)* @differenttypes, variables: !2)
+!5 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/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.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: 4, column: 32, scope: !13)
+!16 = !DILocation(line: 4, column: 22, scope: !13)
+!17 = !DILocation(line: 4, column: 14, scope: !13)
+!18 = !{!19, !19, i64 0}
+!19 = !{!"double", !20, i64 0}
+!20 = !{!"omnipotent char", !21, i64 0}
+!21 = !{!"Simple C/C++ TBAA"}
+!22 = !{!23, !23, i64 0}
+!23 = !{!"float", !20, i64 0}
+!24 = !DILocation(line: 3, column: 30, scope: !13)
+!25 = !DILocation(line: 5, column: 1, scope: !4)
diff --git a/final/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll b/final/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll
new file mode 100644
index 0000000..1e3096d
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportFuncCall-01.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 {
+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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5.0 ", isOptimized: true, emissionKind: 2, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportFuncCall.c", directory: "/home/simbuerg/Projekte/llvm/tools/polly/test/ScopDetectionDiagnostics")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "a", line: 3, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, scopeLine: 3, file: !1, scope: !5, type: !6, function: void (double*, i32)* @a, 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/ReportLoopBound-01.ll b/final/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll
new file mode 100644
index 0000000..1ff3492
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportLoopBound-01.ll
@@ -0,0 +1,105 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-allow-nonaffine-loops=false -polly-detect -analyze < %s 2>&1| FileCheck %s --check-prefix=REJECTNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-allow-nonaffine-loops=true -polly-detect -analyze < %s 2>&1| FileCheck %s --check-prefix=ALLOWNONAFFINELOOPS
+; RUN: opt %loadPolly -polly-detect-unprofitable -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-allow-nonaffine-loops=true -polly-allow-nonaffine -polly-detect -analyze < %s 2>&1| FileCheck %s --check-prefix=ALLOWNONAFFINEALL
+
+; void f(int A[], int n) {
+;   for (int i = 0; i < A[n]; i++)
+;     A[i] = 0;
+; }
+
+; If we reject non-affine loops the non-affine loop bound will be reported:
+;
+; REJECTNONAFFINELOOPS: remark: ReportLoopBound-01.c:2:8: 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:2:8: 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:2:8: The following errors keep this region from being a Scop.
+; ALLOWNONAFFINEALL: remark: ReportLoopBound-01.c:3:5: 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) {
+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
+  %2 = load i32, i32* %arrayidx, 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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportLoopBound-01.c", directory: "test/ScopDetectionDiagnostic/")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 1, file: !1, scope: !5, type: !6, function: void (i32*, i32)* @f, 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(tag: DW_TAG_arg_variable, name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!14 = !DILocation(line: 1, column: 12, scope: !4)
+!15 = !DILocalVariable(tag: DW_TAG_arg_variable, 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(tag: DW_TAG_auto_variable, 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/ReportMultipleNonAffineAccesses.ll b/final/test/ScopDetectionDiagnostics/ReportMultipleNonAffineAccesses.ll
new file mode 100644
index 0000000..62fabf2
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportMultipleNonAffineAccesses.ll
@@ -0,0 +1,154 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 -polly-detect-unprofitable -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -polly-delinearize -analyze < %s 2>&1| FileCheck %s -check-prefix=DELIN
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -polly-delinearize -polly-detect-keep-going -analyze < %s 2>&1| FileCheck %s -check-prefix=DELIN-ALL
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 -polly-detect-unprofitable -basicaa -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -polly-delinearize -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) {
+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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: true, emissionKind: 2, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly/test")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "manyaccesses", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, scopeLine: 2, file: !1, scope: !5, type: !6, function: void (float*, i64, float*)* @manyaccesses, 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..0535152
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportNonAffineAccess-01.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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) {
+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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportNonAffineAccess-01.c", directory: "test/ScopDetectionDiagnostic/")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 1, file: !1, scope: !5, type: !6, function: void (i32*)* @f, 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(tag: DW_TAG_arg_variable, 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(tag: DW_TAG_auto_variable, 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..d3decb8
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportUnprofitable.ll
@@ -0,0 +1,129 @@
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %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.
+
+
+; Function Attrs: nounwind uwtable
+define void @onlyWrite(float* %A) #0 {
+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 {
+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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.7.0  (llvm/trunk 229257)", isOptimized: false, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly")
+!2 = !{}
+!3 = !{!4, !10}
+!4 = !DISubprogram(name: "onlyWrite", line: 1, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 1, file: !1, scope: !5, type: !6, function: void (float*)* @onlyWrite, 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 = !DISubprogram(name: "onlyRead", line: 6, isLocal: false, isDefinition: true, flags: DIFlagPrototyped, isOptimized: false, scopeLine: 6, file: !1, scope: !5, type: !6, function: void (float*)* @onlyRead, 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(tag: DW_TAG_arg_variable, name: "A", line: 1, arg: 1, scope: !4, file: !5, type: !8)
+!15 = !DIExpression()
+!16 = !DILocation(line: 1, column: 23, scope: !4)
+!17 = !DILocalVariable(tag: DW_TAG_auto_variable, 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(tag: DW_TAG_arg_variable, name: "A", line: 6, arg: 1, scope: !10, file: !5, type: !8)
+!30 = !DILocation(line: 6, column: 22, scope: !10)
+!31 = !DILocalVariable(tag: DW_TAG_auto_variable, 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/ReportVariantBasePtr-01.ll b/final/test/ScopDetectionDiagnostics/ReportVariantBasePtr-01.ll
new file mode 100644
index 0000000..1bdf456
--- /dev/null
+++ b/final/test/ScopDetectionDiagnostics/ReportVariantBasePtr-01.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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->b[i] = 0;
+; }
+
+; CHECK: remark: ReportVariantBasePtr01.c:6:8: The following errors keep this region from being a Scop.
+; CHECK: remark: ReportVariantBasePtr01.c:7:5: The base address of this array is not invariant inside the loop
+
+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 {
+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
+  %b = getelementptr inbounds %struct.b, %struct.b* %A, i64 0, i32 0, !dbg !26
+  br label %for.body, !dbg !27
+
+for.body:                                         ; preds = %for.body, %entry.split
+  %indvar4 = phi i64 [ %indvar.next, %for.body ], [ 0, %entry.split ]
+  %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 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5.0 ", isOptimized: true, emissionKind: 1, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "ReportVariantBasePtr01.c", directory: "test/ScopDetectionDiagnostics")
+!2 = !{}
+!3 = !{!4}
+!4 = !DISubprogram(name: "a", line: 5, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, scopeLine: 5, file: !1, scope: !5, type: !6, function: void (%struct.b*)* @a, 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(tag: DW_TAG_arg_variable, name: "A", line: 5, arg: 1, scope: !4, file: !5, type: !8)
+!17 = !DILocalVariable(tag: DW_TAG_auto_variable, 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/ScopInfo/20111108-Parameter-not-detected.ll b/final/test/ScopInfo/20111108-Parameter-not-detected.ll
new file mode 100644
index 0000000..7759955
--- /dev/null
+++ b/final/test/ScopInfo/20111108-Parameter-not-detected.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: Context:
+; CHECK: p0: {0,+,1}<%for.cond>
+
+; CHECK: Domain :=
+; CHECK: [p_0] -> { Stmt_if_then[i0] : i0 >= 0 and i0 <= 1022 and i0 >= 999 - p_0 };
+
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..81c46f0
--- /dev/null
+++ b/final/test/ScopInfo/2012-03-16-Crash-because-of-unsigned-in-scev.ll
@@ -0,0 +1,31 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/Alias-0.ll b/final/test/ScopInfo/Alias-0.ll
new file mode 100644
index 0000000..2696dd6
--- /dev/null
+++ b/final/test/ScopInfo/Alias-0.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -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 regions that a valid part of Scop
+; NORTA: 1 polly-detect     - Number of bad regions for Scop: Found base address alias
diff --git a/final/test/ScopInfo/Alias-1.ll b/final/test/ScopInfo/Alias-1.ll
new file mode 100644
index 0000000..f8b4419
--- /dev/null
+++ b/final/test/ScopInfo/Alias-1.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -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 regions that a valid part of Scop
+; NORTA: 1 polly-detect     - Number of bad regions for Scop: Found base address alias
diff --git a/final/test/ScopInfo/Alias-2.ll b/final/test/ScopInfo/Alias-2.ll
new file mode 100644
index 0000000..98d23f2
--- /dev/null
+++ b/final/test/ScopInfo/Alias-2.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -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 regions that a valid part of Scop
+; NORTA: 1 polly-detect     - Number of bad regions for Scop: Found base address alias
diff --git a/final/test/ScopInfo/Alias-3.ll b/final/test/ScopInfo/Alias-3.ll
new file mode 100644
index 0000000..a966b26
--- /dev/null
+++ b/final/test/ScopInfo/Alias-3.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -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 regions that a valid part of Scop
+; NORTA: 1 polly-detect     - Number of bad regions for Scop: Found base address alias
diff --git a/final/test/ScopInfo/Alias-4.ll b/final/test/ScopInfo/Alias-4.ll
new file mode 100644
index 0000000..5854b45
--- /dev/null
+++ b/final/test/ScopInfo/Alias-4.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -analyze < %s -stats 2>&1 | FileCheck %s --check-prefix=RTA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-analyze-ir -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 regions that a valid part of Scop
+; NORTA: 1 polly-detect     - Number of bad regions for Scop: Found base address alias
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..ebc9a4a
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_1.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s -check-prefix=SCALAR
+;
+; SCALAR:    Function: f
+; SCALAR:    Region: %bb1---%bb13
+; SCALAR:    Max Loop Depth:  1
+; SCALAR:    Context:
+; SCALAR:    {  :  }
+; SCALAR:    Assumed Context:
+; SCALAR:    {  :  }
+; SCALAR:    Alias Groups (0):
+; SCALAR:        n/a
+; SCALAR:    Statements {
+; SCALAR:      Stmt_bb3__TO__bb11
+; SCALAR:            Domain :=
+; SCALAR:                { Stmt_bb3__TO__bb11[i0] : i0 >= 0 and i0 <= 1023 };
+; SCALAR:            Schedule :=
+; SCALAR:                { Stmt_bb3__TO__bb11[i0] -> [i0] };
+; SCALAR:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; SCALAR:                { Stmt_bb3__TO__bb11[i0] -> MemRef_C[i0] };
+; SCALAR:            ReadAccess := [Reduction Type: +] [Scalar: 0]
+; SCALAR:                { Stmt_bb3__TO__bb11[i0] -> MemRef_A[o0] : o0 <= 2147483645 and o0 >= -2147483648 };
+; SCALAR:            MayWriteAccess := [Reduction Type: +] [Scalar: 0]
+; SCALAR:                { Stmt_bb3__TO__bb11[i0] -> MemRef_A[o0] : o0 <= 2147483645 and o0 >= -2147483648 };
+; SCALAR:    }
+
+;
+;    void f(int * restrict A, int * restrict C) {
+;      int j;
+;      for (int i = 0; i < 1024; i++) {
+;        while ((j = C[i]))
+;          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
+  %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 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..041540b
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_2.ll
@@ -0,0 +1,132 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=false -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -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:    Region: %bb15---%bb26
+; INNERMOST:    Max Loop Depth:  1
+; INNERMOST:    p0: {0,+,{0,+,-1}<nw><%bb11>}<nw><%bb13>
+; INNERMOST:    p1: {0,+,{0,+,1}<nuw><nsw><%bb11>}<nuw><nsw><%bb13>
+; INNERMOST:    p2: {0,+,4}<nuw><nsw><%bb11>
+; INNERMOST:    p3: {0,+,4}<nuw><nsw><%bb13>
+; INNERMOST:    p4: {0,+,{0,+,4}<nuw><nsw><%bb11>}<%bb13>
+; INNERMOST:    Alias Groups (0):
+; INNERMOST:        n/a
+; INNERMOST:    Statements {
+; INNERMOST:      Stmt_bb16
+; INNERMOST:            Domain :=
+; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] : (i0 <= 1023 - p_1 and i0 >= 0 and i0 <= 1024 + p_0) or (i0 >= 0 and i0 >= 1025 - p_1 and i0 <= 1024 + p_0) };
+; INNERMOST:            Schedule :=
+; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> [i0] : i0 >= 1025 - p_1 or i0 <= 1023 - p_1 };
+; INNERMOST:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> MemRef_A[o0] : 4o0 = p_2 };
+; INNERMOST:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> MemRef_A[o0] : 4o0 = p_3 };
+; INNERMOST:            ReadAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> MemRef_A[o0] : 4o0 = p_4 + 4i0 };
+; INNERMOST:            MustWriteAccess :=  [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2, p_3, p_4] -> { Stmt_bb16[i0] -> MemRef_A[o0] : 4o0 = p_4 + 4i0 };
+; INNERMOST:    }
+;
+; ALL:    Function: f
+; ALL:    Region: %bb11---%bb29
+; ALL:    Max Loop Depth:  2
+; ALL:    Context:
+; ALL:    {  :  }
+; ALL:    Assumed Context:
+; ALL:    {  :  }
+; ALL:    Alias Groups (0):
+; ALL:        n/a
+; ALL:    Statements {
+; ALL:      Stmt_bb15__TO__bb25
+; ALL:            Domain :=
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 };
+; ALL:            Schedule :=
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> [i0, i1] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i0] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i1] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : o0 <= 2305843009213693949 and o0 >= 0 };
+; ALL:            MayWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : o0 <= 2305843009213693949 and o0 >= 0 };
+; ALL:    }
+;
+;    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..bbcc9ee
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non-affine-loop-condition-dependent-access_3.ll
@@ -0,0 +1,135 @@
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=false -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -basicaa -polly-scops -polly-allow-nonaffine -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -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:    Region: %bb15---%bb26
+; INNERMOST:    Max Loop Depth:  1
+; INNERMOST:    Context:
+; INNERMOST:      [p_0, p_1, p_2] -> {  : p_0 >= 0 and p_0 <= 2147483647 and p_1 >= 0 and p_1 <= 4096 and p_2 >= 0 and p_2 <= 4096 }
+; INNERMOST:    Assumed Context:
+; INNERMOST:      [p_0, p_1, p_2] -> {  :  }
+; INNERMOST:    p0: {0,+,{0,+,1}<nuw><nsw><%bb11>}<nuw><nsw><%bb13>
+; INNERMOST:    p1: {0,+,4}<nuw><nsw><%bb11>
+; INNERMOST:    p2: {0,+,4}<nuw><nsw><%bb13>
+; INNERMOST:    Alias Groups (0):
+; INNERMOST:        n/a
+; INNERMOST:    Statements {
+; INNERMOST:      Stmt_bb16
+; INNERMOST:            Domain :=
+; INNERMOST:                [p_0, p_1, p_2] -> { Stmt_bb16[i0] : i0 >= 0 and i0 <= -1 + p_0 };
+; INNERMOST:            Schedule :=
+; INNERMOST:                [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> [i0] };
+; INNERMOST:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[o0] : 4o0 = p_1 };
+; INNERMOST:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[o0] : 4o0 = p_2 };
+; INNERMOST:            ReadAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[i0] };
+; INNERMOST:            MustWriteAccess :=  [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [p_0, p_1, p_2] -> { Stmt_bb16[i0] -> MemRef_A[i0] };
+; INNERMOST:    }
+;
+; ALL:    Function: f
+; ALL:    Region: %bb11---%bb29
+; ALL:    Max Loop Depth:  2
+; ALL:    Context:
+; ALL:    {  :  }
+; ALL:    Assumed Context:
+; ALL:    {  :  }
+; ALL:    Alias Groups (0):
+; ALL:        n/a
+; ALL:    Statements {
+; ALL:      Stmt_bb15__TO__bb25
+; ALL:            Domain :=
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 };
+; ALL:            Schedule :=
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> [i0, i1] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i0] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[i1] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : o0 <= 4294967293 and o0 >= 0 };
+; ALL:            MayWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb15__TO__bb25[i0, i1] -> MemRef_A[o0] : o0 <= 4294967293 and o0 >= 0 };
+; ALL:    }
+;
+;    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..46f8753
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_access_with_range_2.ll
@@ -0,0 +1,54 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: ReadAccess := [Reduction Type: +] [Scalar: 0]
+; CHECK:     { Stmt_bb7[i0, i1] -> MemRef_A[o0] : o0 <= 2046 and o0 >= 0 };
+; CHECK: MayWriteAccess := [Reduction Type: +] [Scalar: 0]
+; CHECK:     { Stmt_bb7[i0, i1] -> MemRef_A[o0] : o0 <= 2046 and o0 >= 0 };
+;
+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..81c33e6
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_but_sdiv.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze < %s | FileCheck %s
+;
+; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:   [N] -> { Stmt_for_body[i0] -> MemRef_A[o0] : 5o0 >= -4 + N + 5i0 and 5o0 <= N + 5i0 };
+; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:   [N] -> { Stmt_for_body[i0] -> MemRef_A[o0] : 5o0 <= 4 - N + 5i0 and 5o0 >= -N + 5i0 };
+;
+;    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..acabf4e
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_but_srem.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+;    void pos(float *A, long n) {
+;      for (long i = 0; i < 100; i++)
+;        A[n % 42] += 1;
+;    }
+;
+; CHECK: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] :
+; CHECK:          exists (e0 = floor((-n + o0)/42):
+; CHECK:                  42e0 = -n + o0 and o0 <= 41 and o0 >= 0) };
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] :
+; CHECK:          exists (e0 = floor((-n + o0)/42):
+; CHECK:                  42e0 = -n + o0 and o0 <= 41 and o0 >= 0) };
+;
+;    void neg(float *A, long n) {
+;      for (long i = 0; i < 100; i++)
+;        A[n % (-42)] += 1;
+;    }
+;
+; CHECK: ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] :
+; CHECK:          exists (e0 = floor((-n + o0)/42):
+; CHECK:                  42e0 = -n + o0 and o0 <= 41 and o0 >= 0) };
+; CHECK: MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [n] -> { Stmt_bb2[i0] -> MemRef_A[o0] :
+; CHECK:          exists (e0 = floor((-n + o0)/42):
+; CHECK:                  42e0 = -n + o0 and o0 <= 41 and o0 >= 0) };
+;
+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..4983c09
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_conditional_nested.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches -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:            Domain :=
+; CHECK:                { Stmt_bb2__TO__bb16[i0] : i0 >= 0 and i0 <= 1023 };
+; 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..0a5a58b
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll
@@ -0,0 +1,105 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=ALL
+;
+; INNERMOST:    Function: f
+; INNERMOST:    Region: %bb9---%bb17
+; INNERMOST:    Max Loop Depth:  1
+; INNERMOST:    Context:
+; INNERMOST:    [N] -> {  : N >= -2147483648 and N <= 2147483647 }
+; INNERMOST:    Assumed Context:
+; INNERMOST:    [N] -> {  :  }
+; INNERMOST:    p0: %N
+; INNERMOST:    Alias Groups (0):
+; INNERMOST:        n/a
+; INNERMOST:    Statements {
+; INNERMOST:      Stmt_bb11
+; INNERMOST:            Domain :=
+; INNERMOST:                [N] -> { Stmt_bb11[i0] : i0 >= 0 and N >= 1 and i0 <= -1 + N };
+; INNERMOST:            Schedule :=
+; INNERMOST:                [N] -> { Stmt_bb11[i0] -> [i0] };
+; INNERMOST:            ReadAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [N] -> { Stmt_bb11[i0] -> MemRef_A[i0] };
+; INNERMOST:            MustWriteAccess :=  [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [N] -> { Stmt_bb11[i0] -> MemRef_A[i0] };
+; INNERMOST:    }
+;
+; ALL:    Function: f
+; ALL:    Region: %bb3---%bb19
+; ALL:    Max Loop Depth:  1
+; ALL:    Context:
+; ALL:    {  :  }
+; ALL:    Assumed Context:
+; ALL:    {  :  }
+; ALL:    Alias Groups (0):
+; ALL:        n/a
+; ALL:    Statements {
+; ALL:      Stmt_bb4__TO__bb17
+; ALL:            Domain :=
+; ALL:                { Stmt_bb4__TO__bb17[i0] : i0 >= 0 and i0 <= 1023 };
+; ALL:            Schedule :=
+; ALL:                { Stmt_bb4__TO__bb17[i0] -> [i0] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb4__TO__bb17[i0] -> MemRef_A[i0] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb4__TO__bb17[i0] -> MemRef_A[o0] : o0 <= 2147483645 and o0 >= 0 };
+; ALL:            MayWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb4__TO__bb17[i0] -> MemRef_A[o0] : o0 <= 2147483645 and o0 >= 0 };
+; ALL:    }
+;
+;    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..fb70f07
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll
@@ -0,0 +1,106 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=INNERMOST
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops=true -analyze < %s | FileCheck %s --check-prefix=ALL
+;
+; INNERMOST:    Function: f
+; INNERMOST:    Region: %bb9---%bb18
+; INNERMOST:    Max Loop Depth:  1
+; INNERMOST:    Context:
+; INNERMOST:    [p_0] -> {  : p_0 >= -2199023255552 and p_0 <= 2199023254528 }
+; INNERMOST:    Assumed Context:
+; INNERMOST:    [p_0] -> {  :  }
+; INNERMOST:    p0: {0,+,(sext i32 %N to i64)}<%bb3>
+; INNERMOST:    Alias Groups (0):
+; INNERMOST:        n/a
+; INNERMOST:    Statements {
+; INNERMOST:      Stmt_bb12
+; INNERMOST:            Domain :=
+; INNERMOST:                [p_0] -> { Stmt_bb12[i0] : i0 >= 0 and p_0 >= 1 and i0 <= -1 + p_0 };
+; INNERMOST:            Schedule :=
+; INNERMOST:                [p_0] -> { Stmt_bb12[i0] -> [i0] };
+; INNERMOST:            ReadAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [p_0] -> { Stmt_bb12[i0] -> MemRef_A[i0] };
+; INNERMOST:            MustWriteAccess :=  [Reduction Type: +] [Scalar: 0]
+; INNERMOST:                [p_0] -> { Stmt_bb12[i0] -> MemRef_A[i0] };
+; INNERMOST:    }
+;
+; ALL:    Function: f
+; ALL:    Region: %bb3---%bb20
+; ALL:    Max Loop Depth:  1
+; ALL:    Context:
+; ALL:    {  :  }
+; ALL:    Assumed Context:
+; ALL:    {  :  }
+; ALL:    Alias Groups (0):
+; ALL:        n/a
+; ALL:    Statements {
+; ALL:      Stmt_bb4__TO__bb18
+; ALL:            Domain :=
+; ALL:                { Stmt_bb4__TO__bb18[i0] : i0 >= 0 and i0 <= 1023 };
+; ALL:            Schedule :=
+; ALL:                { Stmt_bb4__TO__bb18[i0] -> [i0] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; ALL:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb4__TO__bb18[i0] -> MemRef_A[o0] : o0 <= 2199023254526 and o0 >= 0 };
+; ALL:            MayWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; ALL:                { Stmt_bb4__TO__bb18[i0] -> MemRef_A[o0] : o0 <= 2199023254526 and o0 >= 0 };
+; ALL:    }
+;
+;    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..f473d4b
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_float_compare.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches -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:    Region: %bb1---%bb14
+; CHECK:    Max Loop Depth:  1
+; CHECK:    Statements {
+; CHECK:      Stmt_bb2__TO__bb12
+; CHECK:            Domain :=
+; CHECK:                { Stmt_bb2__TO__bb12[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:            Schedule :=
+; CHECK:                { Stmt_bb2__TO__bb12[i0] -> [i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb12[i0] -> MemRef_A[i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb12[i0] -> MemRef_A[-1 + i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb12[i0] -> MemRef_A[i0] };
+; CHECK:            MayWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb12[i0] -> MemRef_A[i0] };
+; CHECK:    }
+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..66c41ef
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_loop_condition.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops -analyze < %s | FileCheck %s
+;
+;    void f(int *A, int *C) {
+;      for (int i = 0; i < 1024; i++) {
+;        while (C[i])
+;          A[i]++;
+;      }
+;    }
+;
+; CHECK:    Function: f
+; CHECK:    Region: %bb1---%bb12
+; CHECK:    Max Loop Depth:  1
+; CHECK:    Statements {
+; CHECK:      Stmt_bb3__TO__bb10
+; CHECK:            Domain :=
+; CHECK:                { Stmt_bb3__TO__bb10[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:            Schedule :=
+; CHECK:                { Stmt_bb3__TO__bb10[i0] -> [i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb3__TO__bb10[i0] -> MemRef_C[i0] };
+; CHECK:            ReadAccess := [Reduction Type: +] [Scalar: 0]
+; CHECK:                { Stmt_bb3__TO__bb10[i0] -> MemRef_A[i0] };
+; CHECK:            MayWriteAccess :=  [Reduction Type: +] [Scalar: 0]
+; CHECK:                { Stmt_bb3__TO__bb10[i0] -> MemRef_A[i0] };
+; CHECK:    }
+
+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..fac63fc
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_loop_used_later.ll
@@ -0,0 +1,137 @@
+; RUN: opt %loadPolly -polly-scops -polly-allow-nonaffine -polly-allow-nonaffine-branches -polly-allow-nonaffine-loops -analyze < %s | FileCheck %s
+;
+; 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:    Region: %bb2---%bb24
+; CHECK:    Max Loop Depth:  1
+; CHECK:    Context:
+; CHECK:    [N] -> {  : N >= -2147483648 and N <= 2147483647 }
+; CHECK:    Assumed Context:
+; CHECK:    [N] -> {  :  }
+; CHECK:    p0: %N
+; CHECK:    Alias Groups (0):
+; CHECK:        n/a
+; CHECK:    Statements {
+; CHECK:      Stmt_bb2
+; CHECK:            Domain :=
+; CHECK:                [N] -> { Stmt_bb2[i0] : i0 >= 0 and N >= 1 and i0 <= N; Stmt_bb2[0] : N <= 0 }
+; CHECK:            Schedule :=
+; CHECK:                [N] -> { Stmt_bb2[i0] -> [i0, 0] : i0 <= N and N >= 1; Stmt_bb2[0] -> [0, 0] : N <= 0 }
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb2[i0] -> MemRef_j_0[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb2[i0] -> MemRef_j_0[] };
+; CHECK:      Stmt_bb4__TO__bb18
+; CHECK:            Domain :=
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] : i0 >= 0 and N >= 1 and i0 <= -1 + N };
+; CHECK:            Schedule :=
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> [i0, 1] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_j_0[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_j_2[] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK:            MayWriteAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_smax[] };
+; CHECK:            MayWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb4__TO__bb18[i0] -> MemRef_j_2[] };
+; CHECK:      Stmt_bb18
+; CHECK:            Domain :=
+; CHECK:                [N] -> { Stmt_bb18[i0] : i0 >= 0 and N >= 1 and i0 <= -1 + N };
+; CHECK:            Schedule :=
+; CHECK:                [N] -> { Stmt_bb18[i0] -> [i0, 2] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb18[i0] -> MemRef_j_2[] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb18[i0] -> MemRef_j_2[] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N] -> { Stmt_bb18[i0] -> MemRef_A[o0] : o0 >= -2147483648 and o0 <= 2147483645 };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N] -> { Stmt_bb18[i0] -> MemRef_A[i0] };
+; CHECK:      Stmt_bb23
+; CHECK:            Domain :=
+; CHECK:                [N] -> { Stmt_bb23[i0] : i0 >= 0 and N >= 1 and i0 <= -1 + N };
+; CHECK:            Schedule :=
+; CHECK:                [N] -> { Stmt_bb23[i0] -> [i0, 3] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb23[i0] -> MemRef_j_2[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N] -> { Stmt_bb23[i0] -> MemRef_j_0[] };
+; CHECK:    }
+;
+;    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..5bdd6c2
--- /dev/null
+++ b/final/test/ScopInfo/NonAffine/non_affine_parametric_loop.ll
@@ -0,0 +1,36 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: Domain
+; CHECK:   [n] -> { Stmt_for_body[i0] : i0 >= 0 and i0 <= -1 + n };
+; CHECK: Schedule
+; CHECK:   [n] -> { Stmt_for_body[i0] -> [i0] };
+; CHECK: ReadAccess
+; CHECK:   [n] -> { Stmt_for_body[i0] -> MemRef_INDEX[i0] };
+; CHECK: WriteAccess
+; CHECK:   [n] -> { Stmt_for_body[i0] -> MemRef_A[o0] : o0 >= -1152921504606846976 and o0 <= 1152921504606846973 };
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..6491e1e
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_conditional_alias_groups_1.ll
@@ -0,0 +1,56 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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..d25f17e
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_conditional_alias_groups_2.ll
@@ -0,0 +1,55 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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..42d3488
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_dead_access.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -analyze -polly-scops < %s | FileCheck %s
+;
+; Check that RTC generation does not die when accesses are dead.
+;
+; CHECK: Alias Groups (0):
+;
+;    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..cdc3a64
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_many_arrays_to_compare.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s --check-prefix=FOUND
+; RUN: opt %loadPolly -polly-scops -analyze -polly-rtc-max-arrays-per-group=3 < %s | FileCheck %s --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..c719ed9
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_many_parameters_not_all_involved.ll
@@ -0,0 +1,91 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-code-generator=isl -polly-rtc-max-parameters=8 -analyze < %s | FileCheck %s --check-prefix=MAX8
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-code-generator=isl -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:       Printing analysis 'Polly - Create polyhedral description of Scops' for region: 'for.cond => for.end' in function 'jd':
+; MAX8-NEXT:  Function: jd
+
+; MAX7:       Printing analysis 'Polly - Create polyhedral description of Scops' for region: 'for.cond => for.end' in function 'jd':
+; MAX7-NEXT:  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_multiple_alias_groups.ll b/final/test/ScopInfo/aliasing_multiple_alias_groups.ll
new file mode 100644
index 0000000..e16f023
--- /dev/null
+++ b/final/test/ScopInfo/aliasing_multiple_alias_groups.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -polly-scops -analyze          < %s | FileCheck %s --check-prefix=NOAA
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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/assume_gep_bounds.ll b/final/test/ScopInfo/assume_gep_bounds.ll
new file mode 100644
index 0000000..0571b07
--- /dev/null
+++ b/final/test/ScopInfo/assume_gep_bounds.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-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..0de5122
--- /dev/null
+++ b/final/test/ScopInfo/assume_gep_bounds_2.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-scops -analyze < %s | 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] -> { :
+; CHECK-DAG:                   (n >= 1 and m <= 20 and p <= 20)
+; CHECK-DAG:                    or
+; CHECK-DAG:                   (n <= 0 and p <= 20)
+; CHECK:                   }
+
+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/bug_2010_10_22.ll b/final/test/ScopInfo/bug_2010_10_22.ll
new file mode 100644
index 0000000..e0af9cf
--- /dev/null
+++ b/final/test/ScopInfo/bug_2010_10_22.ll
@@ -0,0 +1,45 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-analyze-ir < %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..98ea96d
--- /dev/null
+++ b/final/test/ScopInfo/bug_2011_1_5.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-analyze-ir -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..bd39a21
--- /dev/null
+++ b/final/test/ScopInfo/bug_scev_not_fully_eval.ll
@@ -0,0 +1,34 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/cond_constant_in_loop.ll b/final/test/ScopInfo/cond_constant_in_loop.ll
new file mode 100644
index 0000000..5afd5fa
--- /dev/null
+++ b/final/test/ScopInfo/cond_constant_in_loop.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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, N] -> { Stmt_bb1[i0] : i0 >= 0 and i0 <= -1 + M };
+; CHECK: Stmt_bb2
+; CHECK:   Domain :=
+; CHECK:     [M, N] -> { Stmt_bb2[i0] : 1 = 0 };
+
diff --git a/final/test/ScopInfo/cond_in_loop.ll b/final/test/ScopInfo/cond_in_loop.ll
new file mode 100644
index 0000000..d6bc6b3
--- /dev/null
+++ b/final/test/ScopInfo/cond_in_loop.ll
@@ -0,0 +1,47 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-analyze-ir  -analyze < %s | not 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: Scop!
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..e31b709
--- /dev/null
+++ b/final/test/ScopInfo/constant_factor_in_parameter.ll
@@ -0,0 +1,43 @@
+; RUN: opt %loadPolly -analyze -polly-scops -polly-detect-unprofitable < %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_start_integer.ll b/final/test/ScopInfo/constant_start_integer.ll
new file mode 100644
index 0000000..87135d1
--- /dev/null
+++ b/final/test/ScopInfo/constant_start_integer.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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[o0] : 4o0 = 4 + p_0 + 4i0 };
+; CHECK: MustWriteAccess
+; CHECK:   [p_0] -> { Stmt_for_body3[i0] -> MemRef_input[o0] : 4o0 = p_0 + 4i0 };
+
+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..446c951
--- /dev/null
+++ b/final/test/ScopInfo/delinearize-together-all-data-refs.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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][8] // Element size 8
+; CHECK: }
+
+; CHECK: [n, m, o] -> { Stmt_for_body6[i0, i1, i2] -> MemRef_A[3 + i0, i1, 7 + i2] };
+; CHECK: [n, m, o] -> { 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/escaping_empty_scop.ll b/final/test/ScopInfo/escaping_empty_scop.ll
new file mode 100644
index 0000000..d018d07
--- /dev/null
+++ b/final/test/ScopInfo/escaping_empty_scop.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/independent-blocks-never-stop-on-big-scop.ll b/final/test/ScopInfo/independent-blocks-never-stop-on-big-scop.ll
new file mode 100644
index 0000000..08687ca
--- /dev/null
+++ b/final/test/ScopInfo/independent-blocks-never-stop-on-big-scop.ll
@@ -0,0 +1,199 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-independent < %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 i32 @main() nounwind uwtable readnone {
+  %arr = alloca [100 x i32], align 16
+  br label %1
+
+; <label>:1                                       ; preds = %1, %0
+  %indvars.iv3 = phi i64 [ 0, %0 ], [ %indvars.iv.next4, %1 ]
+  %2 = getelementptr inbounds [100 x i32], [100 x i32]* %arr, i64 0, i64 %indvars.iv3
+  %3 = trunc i64 %indvars.iv3 to i32
+  store i32 %3, i32* %2, align 4, !tbaa !0
+  %indvars.iv.next4 = add i64 %indvars.iv3, 1
+  %lftr.wideiv5 = trunc i64 %indvars.iv.next4 to i32
+  %exitcond6 = icmp eq i32 %lftr.wideiv5, 100
+  br i1 %exitcond6, label %.preheader, label %1
+
+.preheader:                                       ; preds = %.preheader, %1
+  %indvars.iv = phi i64 [ %indvars.iv.next, %.preheader ], [ 0, %1 ]
+  %4 = getelementptr inbounds [100 x i32], [100 x i32]* %arr, i64 0, i64 %indvars.iv
+  %5 = load i32, i32* %4, align 4, !tbaa !0
+  %6 = xor i32 %5, -1
+  %7 = shl i32 %5, 15
+  %8 = add nsw i32 %7, %6
+  %9 = ashr i32 %8, 12
+  %10 = xor i32 %9, %8
+  %11 = mul i32 %10, 9
+  %12 = ashr i32 %11, 4
+  %13 = xor i32 %12, %11
+  %14 = mul nsw i32 %13, 20571
+  %15 = ashr i32 %14, 16
+  %16 = xor i32 %15, %14
+  %17 = xor i32 %16, -1
+  %18 = shl i32 %16, 15
+  %19 = add nsw i32 %18, %17
+  %20 = ashr i32 %19, 12
+  %21 = xor i32 %20, %19
+  %22 = mul i32 %21, 5
+  %23 = ashr i32 %22, 4
+  %24 = xor i32 %23, %22
+  %25 = mul nsw i32 %24, 20576
+  %26 = ashr i32 %25, 16
+  %27 = xor i32 %26, %25
+  %28 = xor i32 %27, -1
+  %29 = shl i32 %27, 15
+  %30 = add nsw i32 %29, %28
+  %31 = ashr i32 %30, 12
+  %32 = xor i32 %31, %30
+  %33 = mul i32 %32, 5
+  %34 = ashr i32 %33, 4
+  %35 = xor i32 %34, %33
+  %36 = mul nsw i32 %35, 2057
+  %37 = ashr i32 %36, 16
+  %38 = xor i32 %37, %36
+  %39 = xor i32 %38, -1
+  %40 = shl i32 %38, 15
+  %41 = add nsw i32 %40, %39
+  %42 = ashr i32 %41, 12
+  %43 = xor i32 %42, %41
+  %44 = mul i32 %43, 5
+  %45 = ashr i32 %44, 4
+  %46 = xor i32 %45, %44
+  %47 = mul nsw i32 %46, 20572
+  %48 = ashr i32 %47, 16
+  %49 = xor i32 %48, %47
+  %50 = xor i32 %49, -1
+  %51 = shl i32 %49, 15
+  %52 = add nsw i32 %51, %50
+  %53 = ashr i32 %52, 12
+  %54 = xor i32 %53, %52
+  %55 = mul i32 %54, 5
+  %56 = ashr i32 %55, 4
+  %57 = xor i32 %56, %55
+  %58 = mul nsw i32 %57, 2051
+  %59 = ashr i32 %58, 16
+  %60 = xor i32 %59, %58
+  %61 = xor i32 %60, -1
+  %62 = shl i32 %60, 15
+  %63 = add nsw i32 %62, %61
+  %64 = ashr i32 %63, 12
+  %65 = xor i32 %64, %63
+  %66 = mul i32 %65, 5
+  %67 = ashr i32 %66, 4
+  %68 = xor i32 %67, %66
+  %69 = mul nsw i32 %68, 2057
+  %70 = ashr i32 %69, 16
+  %71 = xor i32 %70, %69
+  %72 = xor i32 %71, -1
+  %73 = shl i32 %71, 15
+  %74 = add nsw i32 %73, %72
+  %75 = ashr i32 %74, 12
+  %76 = xor i32 %75, %74
+  %77 = mul i32 %76, 5
+  %78 = ashr i32 %77, 4
+  %79 = xor i32 %78, %77
+  %80 = mul nsw i32 %79, 205
+  %81 = ashr i32 %80, 17
+  %82 = xor i32 %81, %80
+  %83 = xor i32 %82, -1
+  %84 = shl i32 %82, 15
+  %85 = add nsw i32 %84, %83
+  %86 = ashr i32 %85, 12
+  %87 = xor i32 %86, %85
+  %88 = mul i32 %87, 5
+  %89 = ashr i32 %88, 4
+  %90 = xor i32 %89, %88
+  %91 = mul nsw i32 %90, 2057
+  %92 = ashr i32 %91, 16
+  %93 = xor i32 %92, %91
+  %94 = xor i32 %93, -1
+  %95 = shl i32 %93, 15
+  %96 = add nsw i32 %95, %94
+  %97 = ashr i32 %96, 12
+  %98 = xor i32 %97, %96
+  %99 = mul i32 %98, 5
+  %100 = ashr i32 %99, 3
+  %101 = xor i32 %100, %99
+  %102 = mul nsw i32 %101, 20571
+  %103 = ashr i32 %102, 16
+  %104 = xor i32 %103, %102
+  %105 = xor i32 %104, -1
+  %106 = shl i32 %104, 15
+  %107 = add nsw i32 %106, %105
+  %108 = ashr i32 %107, 12
+  %109 = xor i32 %108, %107
+  %110 = mul i32 %109, 5
+  %111 = ashr i32 %110, 4
+  %112 = xor i32 %111, %110
+  %113 = mul nsw i32 %112, 2057
+  %114 = ashr i32 %113, 16
+  %115 = xor i32 %114, %113
+  %116 = xor i32 %115, -1
+  %117 = shl i32 %115, 15
+  %118 = add nsw i32 %117, %116
+  %119 = ashr i32 %118, 12
+  %120 = xor i32 %119, %118
+  %121 = mul i32 %120, 5
+  %122 = ashr i32 %121, 4
+  %123 = xor i32 %122, %121
+  %124 = mul nsw i32 %123, 20572
+  %125 = ashr i32 %124, 16
+  %126 = xor i32 %125, %124
+  %127 = xor i32 %126, -1
+  %128 = shl i32 %126, 15
+  %129 = add nsw i32 %128, %127
+  %130 = ashr i32 %129, 12
+  %131 = xor i32 %130, %129
+  %132 = mul i32 %131, 5
+  %133 = ashr i32 %132, 4
+  %134 = xor i32 %133, %132
+  %135 = mul nsw i32 %134, 2057
+  %136 = ashr i32 %135, 16
+  %137 = xor i32 %136, %135
+  %138 = xor i32 %137, -1
+  %139 = shl i32 %137, 15
+  %140 = add nsw i32 %139, %138
+  %141 = ashr i32 %140, 12
+  %142 = xor i32 %141, %140
+  %143 = mul i32 %142, 5
+  %144 = ashr i32 %143, 4
+  %145 = xor i32 %144, %143
+  %146 = mul nsw i32 %145, 2057
+  %147 = ashr i32 %146, 16
+  %148 = xor i32 %147, %146
+  %149 = xor i32 %148, -1
+  %150 = shl i32 %148, 15
+  %151 = add nsw i32 %150, %149
+  %152 = ashr i32 %151, 12
+  %153 = xor i32 %152, %151
+  %154 = mul i32 %153, 5
+  %155 = ashr i32 %154, 4
+  %156 = xor i32 %155, %154
+  %157 = mul nsw i32 %156, 2057
+  %158 = ashr i32 %157, 16
+  %159 = xor i32 %158, %157
+  %160 = xor i32 %159, -1
+  %161 = shl i32 %159, 15
+  %162 = add nsw i32 %161, %160
+  %163 = ashr i32 %162, 12
+  %164 = xor i32 %163, %162
+  %165 = mul i32 %164, 5
+  %166 = ashr i32 %165, 4
+  %167 = xor i32 %166, %165
+  %168 = mul nsw i32 %167, 2057
+  %169 = ashr i32 %168, 16
+  %170 = xor i32 %169, %168
+  store i32 %170, i32* %4, align 4, !tbaa !0
+  %indvars.iv.next = add i64 %indvars.iv, 1
+  %lftr.wideiv = trunc i64 %indvars.iv.next to i32
+  %exitcond = icmp eq i32 %lftr.wideiv, 100
+  br i1 %exitcond, label %171, label %.preheader
+
+; <label>:171                                     ; preds = %.preheader
+  ret i32 0
+}
+
+!0 = !{!"int", !1}
+!1 = !{!"omnipotent char", !2}
+!2 = !{!"Simple C/C++ TBAA", null}
diff --git a/final/test/ScopInfo/integers.ll b/final/test/ScopInfo/integers.ll
new file mode 100644
index 0000000..3f57dc9
--- /dev/null
+++ b/final/test/ScopInfo/integers.ll
@@ -0,0 +1,122 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 ]
+  %scevgep = getelementptr i1024, i1024* %a, i1024 %indvar
+  store i1024 %indvar, i1024* %scevgep, align 8
+  %indvar.next = add nsw i1024 %indvar, 1
+  %exitcond = icmp eq i1024 %indvar, 123456000000000000000000000
+; CHECK:  'bb => return' in function 'f'
+; 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:  'bb => return' in function 'f2'
+; 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:  'bb => return' in function 'f3'
+; 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:  'bb => return' in function 'f4'
+; 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:  'bb => return' in function 'f5'
+; 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:  'bb => return' in function 'f6'
+; CHECK: -3
+  %exitcond = icmp eq i3 %indvar, %sub
+  br i1 %exitcond, label %return, label %bb
+
+return:
+  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..fa8a24e
--- /dev/null
+++ b/final/test/ScopInfo/isl_aff_out_of_bounds.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/loop_affine_bound_0.ll b/final/test/ScopInfo/loop_affine_bound_0.ll
new file mode 100644
index 0000000..3e42cf2
--- /dev/null
+++ b/final/test/ScopInfo/loop_affine_bound_0.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-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:  p1: %M
+; CHECK:  Statements {
+; CHECK:    Stmt_bb1
+; CHECK:          Domain :=
+; CHECK:              [N, M] -> { Stmt_bb1[i0, i1] : i0 >= 0 and i0 <= 2 + 4N + 7M and i1 >= 0 and i1 <= 1 + 5N and N >= 0 };
+; CHECK:          Schedule :=
+; CHECK:              [N, M] -> { Stmt_bb1[i0, i1] -> [i0, i1] };
+; CHECK:          MustWriteAccess := [Reduction Type: NONE]
+; CHECK:              [N, M] -> { Stmt_bb1[i0, i1] -> MemRef_a[i0 + 128i1] };
+; CHECK:  }
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..09fb652
--- /dev/null
+++ b/final/test/ScopInfo/loop_affine_bound_1.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-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 %4, 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 eq 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 eq 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: p1: %M
+; CHECK: Statements {
+; CHECK:   Stmt_bb1
+; CHECK:         Domain :=
+; CHECK:             [N, M] -> { Stmt_bb1[i0, i1] : i0 >= 0 and i0 <= 2 + 4N + 7M and i1 >= 0 and i1 <= 1 + 5N - i0 and i0 <= 1 + 5N };
+; CHECK:         Schedule :=
+; CHECK:             [N, M] -> { Stmt_bb1[i0, i1] -> [i0, i1] };
+; CHECK:         MustWriteAccess := [Reduction Type: NONE]
+; CHECK:             [N, M] -> { Stmt_bb1[i0, i1] -> MemRef_a[129i0 + 128i1] };
+; CHECK: }
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..5ba94fd
--- /dev/null
+++ b/final/test/ScopInfo/loop_affine_bound_2.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-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: p1: %M
+; CHECK: Statements {
+; CHECK:   Stmt_bb1
+; CHECK:         Domain :=
+; CHECK:             [N, M] -> { Stmt_bb1[i0, i1] : i0 >= 0 and i0 <= 2 + 4N + 7M and i1 >= 0 and i1 <= 10 + 5N - 6M - 4i0 and 4i0 <= 10 + 5N - 6M };
+; CHECK:         Schedule :=
+; CHECK:             [N, M] -> { Stmt_bb1[i0, i1] -> [i0, i1] };
+; CHECK:         MustWriteAccess := [Reduction Type: NONE]
+; CHECK:             [N, M] -> { Stmt_bb1[i0, i1] -> MemRef_a[-1152 + 768M + 897i0 + 128i1] };
+; CHECK: }
diff --git a/final/test/ScopInfo/loop_carry.ll b/final/test/ScopInfo/loop_carry.ll
new file mode 100644
index 0000000..5a4bf0d
--- /dev/null
+++ b/final/test/ScopInfo/loop_carry.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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
+  %1 = phi i64 [ %.pre, %bb.nph ], [ %2, %bb ]    ; <i64> [#uses=1]
+  %indvar = phi i64 [ 0, %bb.nph ], [ %tmp6, %bb ] ; <i64> [#uses=3]
+  %k.05 = phi i64 [ 1, %bb.nph ], [ %5, %bb ]     ; <i64> [#uses=1]
+  %tmp6 = add i64 %indvar, 1                      ; <i64> [#uses=3]
+  %scevgep = getelementptr i64, i64* %a, i64 %tmp6     ; <i64*> [#uses=1]
+  %2 = mul nsw i64 %1, %k.05                      ; <i64> [#uses=2]
+  store i64 %2, 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]
+  %3 = load i64, i64* %scevgep9, align 8               ; <i64> [#uses=1]
+  %4 = load i64, i64* %scevgep12, align 8              ; <i64> [#uses=1]
+  %5 = add nsw i64 %3, %4                         ; <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: Context:
+; CHECK: [n] -> { : }
+; CHECK:     Statements {
+; CHECK:     	Stmt_bb
+; CHECK:             Domain :=
+; CHECK:                 [n] -> { Stmt_bb[i0] : i0 >= 0 and i0 <= -2 + n };
+; CHECK:             Schedule :=
+; CHECK:                 [n] -> { Stmt_bb[i0] -> [i0] };
+; CHECK:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [n] -> { Stmt_bb[i0] -> MemRef_1[] };
+; CHECK:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [n] -> { Stmt_bb[i0] -> MemRef_k_05[] };
+; CHECK:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [n] -> { Stmt_bb[i0] -> MemRef_1[] };
+; CHECK:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [n] -> { Stmt_bb[i0] -> MemRef_k_05[] };
+; CHECK:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                 [n] -> { Stmt_bb[i0] -> MemRef_a[1 + i0] };
+; CHECK:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                 [n] -> { Stmt_bb[i0] -> MemRef_a[2 + 2i0] };
+; CHECK:             ReadAccess :=       [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                 [n] -> { Stmt_bb[i0] -> MemRef_a[4 + i0] };
+
diff --git a/final/test/ScopInfo/max-loop-depth.ll b/final/test/ScopInfo/max-loop-depth.ll
new file mode 100644
index 0000000..cbf121d
--- /dev/null
+++ b/final/test/ScopInfo/max-loop-depth.ll
@@ -0,0 +1,79 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/multi-scop.ll b/final/test/ScopInfo/multi-scop.ll
new file mode 100644
index 0000000..060ceb8
--- /dev/null
+++ b/final/test/ScopInfo/multi-scop.ll
@@ -0,0 +1,37 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-detect -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..2aa12ce
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d-diagonal-matrix.ll
@@ -0,0 +1,42 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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: Domain :=
+; CHECK:   [n] -> { Stmt_for_i[i0] : i0 >= 0 and i0 <= -1 + n };
+; 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..609eeac
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d_outer_parametric_offset.ll
@@ -0,0 +1,52 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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:  [m, p] -> {  : }
+; CHECK:  p0: %m
+; CHECK:  p1: %p
+; CHECK:  Statements {
+; CHECK:    Stmt_for_j
+; CHECK:          Domain :=
+; CHECK:              [m, p] -> { Stmt_for_j[i0, i1] : i0 >= 0 and i0 <= 99 and i1 >= 0 and i1 <= -1 + m };
+; CHECK:          Schedule :=
+; CHECK:              [m, p] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK:          MustWriteAccess := [Reduction Type: NONE]
+; CHECK:              [m, p] -> { Stmt_for_j[i0, i1] -> MemRef_A[p + i0, i1] };
+; CHECK:  }
+
+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..48db6b3
--- /dev/null
+++ b/final/test/ScopInfo/multidim_2d_parametric_array_static_loop_bounds.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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: [m] -> {  : m >= 150 }
+; CHECK: p0: %m
+; CHECK: Statements {
+; CHECK:   Stmt_for_j
+; CHECK:         Domain :=
+; CHECK:             [m] -> { Stmt_for_j[i0, i1] : i0 >= 0 and i0 <= 99 and i1 >= 0 and i1 <= 149 };
+; CHECK:         Schedule :=
+; CHECK:             [m] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK:         MustWriteAccess := [Reduction Type: NONE]
+; CHECK:             [m] -> { Stmt_for_j[i0, i1] -> MemRef_A[i0, i1] };
+
+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_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..e0271c4
--- /dev/null
+++ b/final/test/ScopInfo/multidim_3d_parametric_array_static_loop_bounds.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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:   [o, m] -> {  :
+; CHECK-DAG:               m >= 150
+; CHECK-DAG:               and
+; CHECK-DAG:               o >= 200
+; CHECK:             }
+; CHECK:   p0: %o
+; CHECK:   p1: %m
+; CHECK:   Statements {
+; CHECK:     Stmt_for_k
+; CHECK:           Domain :=
+; CHECK:               [o, m] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= 99 and i1 >= 0 and i1 <= 149 and i2 >= 0 and i2 <= 199 };
+; CHECK:           Schedule :=
+; CHECK:               [o, m] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK:           MustWriteAccess := [Reduction Type: NONE]
+; CHECK:               [o, m] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, 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 [ 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_ivs_and_integer_offsets_3d.ll b/final/test/ScopInfo/multidim_ivs_and_integer_offsets_3d.ll
new file mode 100644
index 0000000..bd414ce
--- /dev/null
+++ b/final/test/ScopInfo/multidim_ivs_and_integer_offsets_3d.ll
@@ -0,0 +1,71 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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: {  :  }
+
+; CHECK: p0: %n
+; CHECK: p1: %m
+; CHECK: p2: %o
+; CHECK-NOT: p3
+
+; CHECK: Domain
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= -4 + n and i1 >= 0 and i1 <= -5 + m and i2 >= 0 and i2 <= -8 + o };
+; CHECK: Schedule
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK: MustWriteAccess
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[3 + i0, i1, 7 + 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 [ 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..cb442b3
--- /dev/null
+++ b/final/test/ScopInfo/multidim_ivs_and_parameteric_offsets_3d.ll
@@ -0,0 +1,77 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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], 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: [n, m, o, p, q, r] -> { : (q <= 0 and q >= 1 - m and r <= -1 and r >= 1 - o) or (r = 0 and q <= 0 and q >= -m) or (r = -o and q <= 1 and q >= 1 - m) }
+;
+; CHECK: p0: %n
+; CHECK: p1: %m
+; CHECK: p2: %o
+; CHECK: p3: %p
+; CHECK: p4: %q
+; CHECK: p5: %r
+; CHECK-NOT: p6
+;
+; CHECK: Domain
+; CHECK:   [n, m, o, p, q, r] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= -1 + n and i1 >= 0 and i1 <= -1 + m and i2 >= 0 and i2 <= -1 + o };
+; CHECK: Schedule
+; CHECK:   [n, m, o, p, q, r] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK: MustWriteAccess
+; CHECK: [n, m, o, 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 <= -1 - r; Stmt_for_k[i0, i1, i2] -> MemRef_A[p + i0, -1 + q + i1, o + r + i2] : i1 >= 1 - q and i2 <= -1 - r; Stmt_for_k[i0, i1, i2] -> MemRef_A[-1 + p + i0, m + q + i1, r + i2] : i1 <= -1 - q and i2 >= -r; Stmt_for_k[i0, i1, i2] -> MemRef_A[p + i0, q + i1, r + i2] : i1 >= -q and i2 >= -r };
+
+
+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..d6f0f71
--- /dev/null
+++ b/final/test/ScopInfo/multidim_many_references.ll
@@ -0,0 +1,519 @@
+; RUN: opt %loadPolly -polly-scops -analyze -polly-delinearize -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..5bde3df
--- /dev/null
+++ b/final/test/ScopInfo/multidim_nested_start_integer.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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:   {  :  }
+; CHECK: p0: %n
+; CHECK: p1: %m
+; CHECK: p2: %o
+; CHECK-NOT: p3
+; CHECK: Domain
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= -4 + n and i1 >= 0 and i1 <= -5 + m and i2 >= 0 and i2 <= -8 + o };
+; CHECK: Schedule
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK: MustWriteAccess
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[3 + i0, i1, 7 + 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 [ 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..32c193e
--- /dev/null
+++ b/final/test/ScopInfo/multidim_nested_start_share_parameter.ll
@@ -0,0 +1,80 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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: %n
+; CHECK: p1: %m
+; CHECK: p2: %o
+; CHECK-NOT: p3
+;
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[3 + i0, 10 + i1, 7 + i2] };
+; CHECK:   [n, m, o] -> { 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..b275310
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_2d.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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:   [n, m] -> {  :  }
+; CHECK: p0: %n
+; CHECK: p1: %m
+; CHECK-NOT: p3
+
+; CHECK: Domain
+; CHECK:   [n, m] -> { Stmt_for_j[i0, i1] : i0 >= 0 and i0 <= -1 + n and i1 >= 0 and i1 <= -1 + m };
+; CHECK: Schedule
+; CHECK:   [n, m] -> { Stmt_for_j[i0, i1] -> [i0, i1] };
+; CHECK: MustWriteAccess
+; CHECK:   [n, m] -> { Stmt_for_j[i0, i1] -> MemRef_A[i0, i1] };
+
+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..e2806ac
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_3d.ll
@@ -0,0 +1,65 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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:   [n, m, o] -> {  :  }
+; CHECK: p0: %n
+; CHECK: p1: %m
+; CHECK: p2: %o
+; CHECK-NOT: p3
+;
+; CHECK: Domain
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= -1 + n and i1 >= 0 and i1 <= -1 + m and i2 >= 0 and i2 <= -1 + o };
+; CHECK: Schedule
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK: WriteAccess
+; CHECK:   [n, m, o] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, 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 [ 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..62b72c3
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_3d_cast.ll
@@ -0,0 +1,83 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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;
+; }
+
+; We currently fail to get the relation between the 32 and 64 bit versions of
+; m and o, such that we generate unnecessary run-time checks. This is not a
+; correctness issue, but could be improved.
+
+; CHECK: Assumed Context:
+; CHECK:  [n, m, o, p_3, p_4] -> { :
+; CHECK-DAG: p_3 >= o
+; CHECK-DAG: p_4 >= m
+; CHECK:  }
+; CHECK: p0: %n
+; CHECK: p1: %m
+; CHECK: p2: %o
+; CHECK: p3: (zext i32 %o to i64)
+; CHECK: p4: (zext i32 %m to i64)
+; CHECK-NOT: p5
+
+; CHECK: Domain
+; CHECK:   [n, m, o, p_3, p_4] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= -1 + n and i1 >= 0 and i1 <= -1 + m and i2 >= 0 and i2 <= -1 + o };
+; CHECK: Schedule
+; CHECK:   [n, m, o, p_3, p_4] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK: WriteAccess
+; CHECK:   [n, m, o, p_3, p_4] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, i2] };
+
+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..90fbda3
--- /dev/null
+++ b/final/test/ScopInfo/multidim_only_ivs_3d_reverse.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-delinearize < %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:   {  :  }
+; CHECK: p0: %n
+; CHECK: p1: %o
+; CHECK: p2: %m
+; CHECK-NOT: p3
+;
+; CHECK: Domain
+; CHECK:  [n, o, m] -> { Stmt_for_j[i0, i1, i2] : i0 >= 0 and i0 <= -1 + n and i1 >= 0 and i1 <= -1 + o and i2 >= 0 and i2 <= -1 + m };
+; CHECK: Schedule
+; CHECK:   [n, o, m] -> { Stmt_for_j[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK: WriteAccess
+; CHECK:   [n, o, m] -> { Stmt_for_j[i0, i1, i2] -> MemRef_A[i0, i2, i1] };
+
+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..303d913
--- /dev/null
+++ b/final/test/ScopInfo/multidim_param_in_subscript-2.ll
@@ -0,0 +1,88 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %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_single_and_multidim_array.ll b/final/test/ScopInfo/multidim_single_and_multidim_array.ll
new file mode 100644
index 0000000..b52cd29
--- /dev/null
+++ b/final/test/ScopInfo/multidim_single_and_multidim_array.ll
@@ -0,0 +1,68 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-delinearize=false -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-delinearize=false -polly-allow-nonaffine -analyze < %s | FileCheck %s --check-prefix=NONAFFINE
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-delinearize -analyze < %s | FileCheck %s --check-prefix=DELIN
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-delinearize -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: p1: ((-1 + %n) * %n)
+; NONAFFINE: Statements {
+; NONAFFINE:   Stmt_for_i_1
+; NONAFFINE:         MayWriteAccess :=   [Reduction Type: NONE]
+; NONAFFINE:             [n, p_1] -> { Stmt_for_i_1[i0] -> MemRef_X[o0] : o0 >= -2305843009213693952 and o0 <= 2305843009213693949 };
+; NONAFFINE:   Stmt_for_i_2
+; NONAFFINE:         MustWriteAccess :=  [Reduction Type: NONE]
+; NONAFFINE:             [n, p_1] -> { Stmt_for_i_2[i0] -> MemRef_X[p_1 + i0] };
+
+; DELIN: Stmt_for_i_1
+; DELIN:   MustWriteAccess :=
+; DELIN:      [n] -> { Stmt_for_i_1[i0] -> MemRef_X[i0, 0] };
+; DELIN: Stmt_for_i_2
+; DELIN:   MustWriteAccess :=
+; DELIN:      [n] -> { Stmt_for_i_2[i0] -> MemRef_X[-1 + n, i0] };
+
+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..7f181a0
--- /dev/null
+++ b/final/test/ScopInfo/multidim_srem.ll
@@ -0,0 +1,92 @@
+; 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: ReadAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [n] -> { Stmt_for_body_8[i0, i1, i2] -> MemRef_A[o0, i1, i2] : exists (e0 = floor((-i0 + o0)/2): 2e0 = -i0 + o0 and o0 >= 0 and o0 <= 1) };
+; CHECK: MustWriteAccess :=	[Reduction Type: NONE] [Scalar: 0]
+; CHECK:     [n] -> { Stmt_for_body_8[i0, i1, i2] -> MemRef_A[o0, i1, i2] : exists (e0 = floor((-i0 + o0)/2): 2e0 = -i0 + o0 and o0 >= 0 and o0 <= 1) };
+
+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/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..7e71189
--- /dev/null
+++ b/final/test/ScopInfo/no-scalar-deps-in-non-affine-subregion.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-scops -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..1bcebcc
--- /dev/null
+++ b/final/test/ScopInfo/non-affine-region-phi.ll
@@ -0,0 +1,73 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-allow-nonaffine -polly-no-early-exit -S < %s | FileCheck %s --check-prefix=CODE
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-allow-nonaffine -polly-no-early-exit -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_access.ll b/final/test/ScopInfo/non_affine_access.ll
new file mode 100644
index 0000000..d548707
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_access.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-delinearize -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-allow-nonaffine -analyze < %s | FileCheck %s -check-prefix=NONAFFINE
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-delinearize -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] :  o0 >= -1152921504606846976 and o0 <= 1152921504606846973 };
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..8e8752e
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_1.ll
@@ -0,0 +1,92 @@
+; RUN: opt %loadPolly -polly-allow-nonaffine -polly-detect-unprofitable -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:       Region: %bb1---%bb21
+; CHECK:       Stmt_bb3
+; CHECK:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [b] -> { Stmt_bb3[i0] -> MemRef_x_1[] };
+; CHECK:       Stmt_bb7
+; CHECK:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [b] -> { Stmt_bb7[i0] -> MemRef_x_1[] };
+; CHECK:       Stmt_bb8
+; CHECK:             MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                 [b] -> { Stmt_bb8[i0] -> MemRef_x_1[] };
+; CHECK:       Stmt_bb10__TO__bb18
+; CHECK-NEXT:        Domain :=
+; CHECK-NEXT:            [b] -> { Stmt_bb10__TO__bb18[i0] : i0 >= 0 and 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[] }
+; CHECK-NOT:   [Scalar: 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 = %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..b572bd4
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_2.ll
@@ -0,0 +1,110 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: Region: %bb2---%bb21
+; CHECK:   Stmt_bb3__TO__bb18
+; CHECK:         Domain :=
+; CHECK:             { Stmt_bb3__TO__bb18[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:         Schedule :=
+; CHECK:             { Stmt_bb3__TO__bb18[i0] -> [i0, 0] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_0[] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_1[] };
+; CHECK:         ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT:        { Stmt_bb3__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_0[] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_1[] };
+; CHECK:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:        { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2[] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_0[] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_1[] };
+; CHECK:         MayWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK-NEXT:        { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2[] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_0[] };
+; CHECK-NOT:         { Stmt_bb3__TO__bb18[i0] -> MemRef_x_1[] };
+; CHECK:   Stmt_bb18
+; CHECK:         Domain :=
+; CHECK:             { Stmt_bb18[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:         Schedule :=
+; CHECK:             { Stmt_bb18[i0] -> [i0, 1] };
+; CHECK:         ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:             { Stmt_bb18[i0] -> MemRef_x_2[] };
+; CHECK:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb18[i0] -> MemRef_A[i0] };
+;
+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..0ca2191
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_3.ll
@@ -0,0 +1,98 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 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: Region: %bb2---%bb21
+; CHECK:   Stmt_bb3__TO__bb18
+; CHECK:         Domain :=
+; CHECK:             { Stmt_bb3__TO__bb18[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:         Schedule :=
+; CHECK:             { Stmt_bb3__TO__bb18[i0] -> [i0, 0] };
+; CHECK:         ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb3__TO__bb18[i0] -> MemRef_A[i0] };
+; CHECK:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:             { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2[] };
+; CHECK:         MayWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:             { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2[] };
+; CHECK:         MayWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:             { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2[] };
+; CHECK:         MayWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:             { Stmt_bb3__TO__bb18[i0] -> MemRef_x_2[] };
+; CHECK:   Stmt_bb18
+; CHECK:         Domain :=
+; CHECK:             { Stmt_bb18[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:         Schedule :=
+; CHECK:             { Stmt_bb18[i0] -> [i0, 1] };
+; CHECK:         ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:             { Stmt_bb18[i0] -> MemRef_x_2[] };
+; CHECK:         MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:             { Stmt_bb18[i0] -> MemRef_A[i0] };
+;
+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..9052c4d
--- /dev/null
+++ b/final/test/ScopInfo/non_affine_region_4.ll
@@ -0,0 +1,76 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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:    Region: %bb1---%bb11
+; CHECK:      Stmt_bb2__TO__bb7
+; CHECK:            Domain :=
+; CHECK:                { Stmt_bb2__TO__bb7[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:            Schedule :=
+; CHECK:                { Stmt_bb2__TO__bb7[i0] -> [i0, 0] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb2__TO__bb7[i0] -> MemRef_A[i0] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb2__TO__bb7[i0] -> MemRef_x[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb2__TO__bb7[i0] -> MemRef_y[] };
+; CHECK:            MayWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb2__TO__bb7[i0] -> MemRef_y[] };
+; CHECK:      Stmt_bb7
+; CHECK:            Domain :=
+; CHECK:                { Stmt_bb7[i0] : i0 >= 0 and i0 <= 1023 };
+; CHECK:            Schedule :=
+; CHECK:                { Stmt_bb7[i0] -> [i0, 1] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb7[i0] -> MemRef_x[] };
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                { Stmt_bb7[i0] -> MemRef_y[] };
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                { Stmt_bb7[i0] -> MemRef_A[i0] };
+;
+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/parameter_product.ll b/final/test/ScopInfo/parameter_product.ll
new file mode 100644
index 0000000..c1c722a
--- /dev/null
+++ b/final/test/ScopInfo/parameter_product.ll
@@ -0,0 +1,30 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/phi_condition_modeling_1.ll b/final/test/ScopInfo/phi_condition_modeling_1.ll
new file mode 100644
index 0000000..a87f0f6
--- /dev/null
+++ b/final/test/ScopInfo/phi_condition_modeling_1.ll
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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[] };
+; 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[] };
+; 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[] };
+; 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..e78ed55
--- /dev/null
+++ b/final/test/ScopInfo/phi_condition_modeling_2.ll
@@ -0,0 +1,81 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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[] };
+; 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[] };
+; 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[] };
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb8[i0] -> MemRef_tmp_0[] };
+; CHECK-NOT: Access
+; CHECK-LABEL:      Stmt_bb8b
+; CHECK-NOT: Access
+; CHECK:            ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:                [N, c] -> { Stmt_bb8b[i0] -> MemRef_tmp_0[] };
+; CHECK-NOT: Access
+; CHECK:            MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:                [N, c] -> { Stmt_bb8b[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 ]
+  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..7b4592a
--- /dev/null
+++ b/final/test/ScopInfo/phi_conditional_simple_1.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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[] };
+; 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[] };
+; 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[] };
+; 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..22b7ede
--- /dev/null
+++ b/final/test/ScopInfo/phi_loop_carried_float.ll
@@ -0,0 +1,58 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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-LABEL:   Stmt_bb1
+; CHECK-NOT: Access
+; CHECK:              ReadAccess := [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb1[i0] -> MemRef_tmp_0[] };
+; CHECK-NOT: Access
+; CHECK:              MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb1[i0] -> MemRef_tmp_0[] };
+; CHECK-NOT: Access
+; CHECK-LABEL:   Stmt_bb4
+; CHECK-NOT: Access
+; CHECK:              MustWriteAccess :=  [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0[] };
+; CHECK-NOT: Access
+; CHECK:              ReadAccess := [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb4[i0] -> MemRef_tmp_0[] };
+; CHECK-NOT: Access
+; CHECK:              ReadAccess := [Reduction Type: NONE]
+; CHECK:                  [N] -> { Stmt_bb4[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(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..584a8b5
--- /dev/null
+++ b/final/test/ScopInfo/phi_not_grouped_at_top.ll
@@ -0,0 +1,28 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..8244568
--- /dev/null
+++ b/final/test/ScopInfo/phi_scalar_simple_1.ll
@@ -0,0 +1,105 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze < %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:
+  %tmp = sext i32 %N to i64
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc4, %entry
+; CHECK-LABEL: Stmt_for_cond
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+  %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: Stmt_for_body
+; CHECK:       ReadAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_body[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_body[i0] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+; CHECK-LABEL: Stmt_for_cond1
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1_lcssa[] };
+; CHECK-NOT: Access
+  %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
+; CHECK-LABEL: Stmt_for_inc
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:           [N] -> { Stmt_for_inc[i0, i1] -> MemRef_A[1 + i0] };
+; CHECK-NOT: Access
+  %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: Stmt_for_end
+; CHECK-NOT: Access
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_end[i0] -> MemRef_x_addr_1_lcssa[] };
+; CHECK-NOT: Access
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_end[i0] -> MemRef_x_addr_1_lcssa[] };
+; CHECK-NOT: Access
+  %x.addr.1.lcssa = phi i32 [ %x.addr.1, %for.cond1 ]
+  br label %for.inc4
+
+for.inc4:                                         ; preds = %for.end
+; CHECK-LABEL: Stmt_for_inc4
+; CHECK-NOT: Access
+; CHECK:       ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc4[i0] -> MemRef_x_addr_1_lcssa[] };
+; CHECK-NOT: Access
+; CHECK:       MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:           [N] -> { Stmt_for_inc4[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+  %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..5ba40e4
--- /dev/null
+++ b/final/test/ScopInfo/phi_scalar_simple_2.ll
@@ -0,0 +1,137 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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;
+;    }
+;
+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
+; CHECK-LABEL: Stmt_for_cond
+; CHECK-NOT: Access
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_A[i0] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+  %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
+; CHECK-LABEL: Stmt_for_body
+; CHECK-NOT: Access
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body[i0] -> MemRef_x_addr_0[] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body[i0] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+; CHECK-LABEL: Stmt_for_cond1
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_cond1[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+  %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: Stmt_for_body3
+; CHECK-NOT: Access
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body3[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_body3[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK-NOT: Access
+  %cmp4 = icmp slt i64 %indvars.iv, %tmp1
+  br i1 %cmp4, label %if.then, label %if.end
+
+if.then:                                          ; preds = %for.body3
+; CHECK-LABEL: Stmt_if_then
+; CHECK-NOT: Access
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_1[] };
+; CHECK-NOT: Access
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK:         [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_A[i0] };
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_then[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK-NOT: Access
+  %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
+; CHECK-LABEL: Stmt_if_end
+; CHECK-NOT: Access
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_end[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK-NOT: Access
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_if_end[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK-NOT: Access
+  %x.addr.2 = phi i32 [ %add, %if.then ], [ %x.addr.1, %for.body3 ]
+  br label %for.inc
+
+for.inc:                                          ; preds = %if.end
+; CHECK-LABEL: Stmt_for_inc
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_2[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc[i0, i1] -> MemRef_x_addr_1[] };
+  %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
+; CHECK-LABEL: Stmt_for_inc5
+; CHECK:     ReadAccess := [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc5[i0] -> MemRef_x_addr_1[] };
+; CHECK:     MustWriteAccess :=  [Reduction Type: NONE] [Scalar: 1]
+; CHECK:         [N, c] -> { Stmt_for_inc5[i0] -> MemRef_x_addr_0[] };
+  %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..b97f50d
--- /dev/null
+++ b/final/test/ScopInfo/phi_with_invoke_edge.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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-type-expressions.ll b/final/test/ScopInfo/pointer-type-expressions.ll
new file mode 100644
index 0000000..6fe2b82
--- /dev/null
+++ b/final/test/ScopInfo/pointer-type-expressions.ll
@@ -0,0 +1,48 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 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:   {  :  }
+
+; CHECK:  Stmt_store
+; CHECK:        Domain :=
+; CHECK:            [N, P] -> { Stmt_store[i0] :
+; CHECK:              (P <= -1 and i0 >= 0 and i0 <= -1 + N)
+; CHECK:                or
+; CHECK:              (P >= 1 and i0 >= 0 and i0 <= -1 + N)
+; CHECK:                   };
+; CHECK:        Schedule :=
+; CHECK:            [N, P] -> { Stmt_store[i0] -> [i0] : P <= -1 or P >= 1 };
+; CHECK:        MustWriteAccess := [Reduction Type: NONE]
+; CHECK:            [N, P] -> { Stmt_store[i0] -> MemRef_a[i0] };
diff --git a/final/test/ScopInfo/ranged_parameter.ll b/final/test/ScopInfo/ranged_parameter.ll
new file mode 100644
index 0000000..b46cb76
--- /dev/null
+++ b/final/test/ScopInfo/ranged_parameter.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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:   [p_0] -> {  : p_0 >= 0 and p_0 <= 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_wrap.ll b/final/test/ScopInfo/ranged_parameter_wrap.ll
new file mode 100644
index 0000000..f528ed0
--- /dev/null
+++ b/final/test/ScopInfo/ranged_parameter_wrap.ll
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that the contstraints on the paramater derived from the
+; __wrapping__ range metadata (see bottom of the file) are present:
+;
+; CHECK: Context:
+; CHECK:   [tmp] -> {  : tmp >= 256 or tmp <= -1 }
+;
+;    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/reduction_alternating_base.ll b/final/test/ScopInfo/reduction_alternating_base.ll
new file mode 100644
index 0000000..8d490e5
--- /dev/null
+++ b/final/test/ScopInfo/reduction_alternating_base.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..7b84b46
--- /dev/null
+++ b/final/test/ScopInfo/reduction_chain_partially_outside_the_scop.ll
@@ -0,0 +1,63 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..6843aac
--- /dev/null
+++ b/final/test/ScopInfo/reduction_disabled_multiplicative.ll
@@ -0,0 +1,52 @@
+; RUN: opt -basicaa %loadPolly -polly-detect-unprofitable -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..652e7c2
--- /dev/null
+++ b/final/test/ScopInfo/reduction_escaping_intermediate.ll
@@ -0,0 +1,62 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..b53a869
--- /dev/null
+++ b/final/test/ScopInfo/reduction_escaping_intermediate_2.ll
@@ -0,0 +1,72 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..a1e78bb
--- /dev/null
+++ b/final/test/ScopInfo/reduction_invalid_different_operators.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..0a97797
--- /dev/null
+++ b/final/test/ScopInfo/reduction_invalid_overlapping_accesses.ll
@@ -0,0 +1,59 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..c25a01f
--- /dev/null
+++ b/final/test/ScopInfo/reduction_multiple_loops_array_sum.ll
@@ -0,0 +1,78 @@
+; RUN: opt -basicaa %loadPolly -polly-detect-unprofitable -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..7d5bf04
--- /dev/null
+++ b/final/test/ScopInfo/reduction_multiple_loops_array_sum_1.ll
@@ -0,0 +1,72 @@
+; RUN: opt -basicaa %loadPolly -polly-detect-unprofitable -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..254fe45
--- /dev/null
+++ b/final/test/ScopInfo/reduction_multiple_simple_binary.ll
@@ -0,0 +1,98 @@
+; RUN: opt -basicaa %loadPolly -polly-detect-unprofitable -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..91eb488
--- /dev/null
+++ b/final/test/ScopInfo/reduction_non_overlapping_chains.ll
@@ -0,0 +1,60 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..78c1cd5
--- /dev/null
+++ b/final/test/ScopInfo/reduction_only_reduction_like_access.ll
@@ -0,0 +1,35 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..8afbb3a
--- /dev/null
+++ b/final/test/ScopInfo/reduction_simple_fp.ll
@@ -0,0 +1,64 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..8337655
--- /dev/null
+++ b/final/test/ScopInfo/reduction_simple_w_constant.ll
@@ -0,0 +1,26 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..99f64ec
--- /dev/null
+++ b/final/test/ScopInfo/reduction_simple_w_iv.ll
@@ -0,0 +1,27 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..5ffec70
--- /dev/null
+++ b/final/test/ScopInfo/reduction_two_identical_reads.ll
@@ -0,0 +1,66 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-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/run-time-check-many-parameters.ll b/final/test/ScopInfo/run-time-check-many-parameters.ll
new file mode 100644
index 0000000..0dea43e
--- /dev/null
+++ b/final/test/ScopInfo/run-time-check-many-parameters.ll
@@ -0,0 +1,129 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -polly-code-generator=isl -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..7d8153c
--- /dev/null
+++ b/final/test/ScopInfo/run-time-check-read-only-arrays.ll
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-code-generator=isl -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/scalar.ll b/final/test/ScopInfo/scalar.ll
new file mode 100644
index 0000000..425b13c
--- /dev/null
+++ b/final/test/ScopInfo/scalar.ll
@@ -0,0 +1,49 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: Stmt_S1
+; CHECK:       Domain :=
+; CHECK:           [N] -> { Stmt_S1[i0] : i0 >= 0 and i0 <= -1 + N };
+; CHECK:       Schedule :=
+; CHECK:           [N] -> { Stmt_S1[i0] -> [i0, 0] };
+; CHECK:       ReadAccess :=
+; CHECK:           [N] -> { Stmt_S1[i0] -> MemRef_a[i0] };
+; CHECK:       MustWriteAccess :=
+; CHECK:           [N] -> { Stmt_S1[i0] -> MemRef_val[] };
+; CHECK: Stmt_S2
+; CHECK:       Domain :=
+; CHECK:           [N] -> { Stmt_S2[i0] : i0 >= 0 and i0 <= -1 + N };
+; CHECK:       Schedule :=
+; CHECK:           [N] -> { Stmt_S2[i0] -> [i0, 1] };
+; CHECK:       ReadAccess :=
+; CHECK:           [N] -> { Stmt_S2[i0] -> MemRef_val[] };
+; CHECK:       MustWriteAccess :=
+; CHECK:           [N] -> { Stmt_S2[i0] -> MemRef_a[i0] };
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..2e81cb7
--- /dev/null
+++ b/final/test/ScopInfo/scalar_dependence_cond_br.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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]++;
+;    }
+;
+; We should move operands as close to their use as possible, hence in this case
+; there should not be any scalar dependence anymore after %cmp1 is moved to 
+; %for.body (%c and %indvar.iv are synthesis able).
+;
+; CHECK-NOT:      [Scalar: 1]
+;
+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/simple_loop_1.ll b/final/test/ScopInfo/simple_loop_1.ll
new file mode 100644
index 0000000..6146fd6
--- /dev/null
+++ b/final/test/ScopInfo/simple_loop_1.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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 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:   {  :  }
+; CHECK: Arrays {
+; CHECK:     i64 MemRef_a[*][8] // Element size 8
+; CHECK: }
+
+; CHECK:  Stmt_bb
+; CHECK:        Domain :=
+; CHECK:            [N] -> { Stmt_bb[i0] : i0 >= 0 and i0 <= -1 + N };
+; CHECK:        Schedule :=
+; CHECK:            [N] -> { Stmt_bb[i0] -> [i0] };
+; CHECK:        MustWriteAccess := [Reduction Type: NONE]
+; CHECK:            [N] -> { Stmt_bb[i0] -> MemRef_a[i0] };
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..3a0e694
--- /dev/null
+++ b/final/test/ScopInfo/simple_nonaffine_loop_not.ll
@@ -0,0 +1,39 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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..bea6ca1
--- /dev/null
+++ b/final/test/ScopInfo/smax.ll
@@ -0,0 +1,25 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/undef_in_cond.ll b/final/test/ScopInfo/undef_in_cond.ll
new file mode 100644
index 0000000..6b802da
--- /dev/null
+++ b/final/test/ScopInfo/undef_in_cond.ll
@@ -0,0 +1,22 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: Invalid Scop!
diff --git a/final/test/ScopInfo/unsigned-condition.ll b/final/test/ScopInfo/unsigned-condition.ll
new file mode 100644
index 0000000..759022e
--- /dev/null
+++ b/final/test/ScopInfo/unsigned-condition.ll
@@ -0,0 +1,46 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-scops -analyze -polly-allow-unsigned < %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;
+; }
+
+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 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:   {  :  }
+
+; CHECK:  Stmt_store
+; CHECK:        Domain :=
+; CHECK:            [N, P] -> { Stmt_store[i0] :
+; CHECK:              i0 >= 0 and i0 <= -1 + N and P >= 42
+; CHECK:                   };
+; CHECK:        Schedule :=
+; CHECK:            [N, P] -> { Stmt_store[i0] -> [i0] };
+; CHECK:        MustWriteAccess := [Reduction Type: NONE]
+; CHECK:            [N, P] -> { Stmt_store[i0] -> MemRef_a[i0] };
diff --git a/final/test/TempScop/inter_bb_scalar_dep.ll b/final/test/TempScop/inter_bb_scalar_dep.ll
new file mode 100644
index 0000000..8cd924e
--- /dev/null
+++ b/final/test/TempScop/inter_bb_scalar_dep.ll
@@ -0,0 +1,53 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir  -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
+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: BB: entry.next
+; CHECK: Read init_ptr[0]
+; CHECK: Write init[0]
+  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: Read init[0]
+; CHECK: Write A[{0,+,8}<%for.j>]
+  %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/TempScop/intra_and_inter_bb_scalar_dep.ll b/final/test/TempScop/intra_and_inter_bb_scalar_dep.ll
new file mode 100644
index 0000000..c3d6c06
--- /dev/null
+++ b/final/test/TempScop/intra_and_inter_bb_scalar_dep.ll
@@ -0,0 +1,57 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir -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) {
+;       init2 = *init_ptr;
+;       A[i] = init + init2;
+;     }
+;   }
+; }
+
+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
+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: BB: entry.next
+; CHECK: Read init_ptr[0]
+; CHECK: Write init[0]
+  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
+; CHECK: BB: for.j
+; CHECK: Read init[0]
+; CHECK: Read init_ptr[0]
+; CHECK: Write A[{0,+,8}<%for.j>]
+  %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/TempScop/intra_bb_scalar_dep.ll b/final/test/TempScop/intra_bb_scalar_dep.ll
new file mode 100644
index 0000000..f95cd59
--- /dev/null
+++ b/final/test/TempScop/intra_bb_scalar_dep.ll
@@ -0,0 +1,51 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir  -analyze < %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
+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: BB: for.j
+; CHECK: Read init_ptr[0]
+; CHECK: Write A[{0,+,8}<%for.j>]
+  %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/TempScop/nested-loops.ll b/final/test/TempScop/nested-loops.ll
new file mode 100644
index 0000000..e5b2181
--- /dev/null
+++ b/final/test/TempScop/nested-loops.ll
@@ -0,0 +1,32 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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: body
+; CHECK:        Domain :=
+; CHECK:           { Stmt_body[i0, i1] : i0 >= 0 and i0 <= 2046 and i1 >= 0 and i1 <= 1022 }
diff --git a/final/test/TempScop/not-a-reduction.ll b/final/test/TempScop/not-a-reduction.ll
new file mode 100644
index 0000000..f675223
--- /dev/null
+++ b/final/test/TempScop/not-a-reduction.ll
@@ -0,0 +1,50 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -polly-analyze-ir -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
+}
+
+; CHECK:     Reduction
diff --git a/final/test/TempScop/scalar_to_array.ll b/final/test/TempScop/scalar_to_array.ll
new file mode 100644
index 0000000..a4f1277
--- /dev/null
+++ b/final/test/TempScop/scalar_to_array.ll
@@ -0,0 +1,185 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir -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
+
+; CHECK: 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: 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: BB: for.body
+; CHECK-NOT: Read
+; CHECK: Write A[{0,+,4}<%for.cond>]
+
+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: 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: BB: for.body.a
+; CHECK: Read A[{0,+,4}<%for.cond>]
+; CHECK: Write scalar[0]
+
+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: BB: for.body.b
+; CHECK: Read scalar[0]
+; CHECK: Write A[{0,+,4}<%for.cond>]
+
+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: 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: BB: for.body
+; CHECK: Read A[{0,+,4}<%for.head>]
+; CHECK: Write scalar.s2a[0]
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body
+  %indvar.next = add i64 %indvar, 1
+  %exitcond = icmp ne i64 %indvar, 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: 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: BB: for.body
+; CHECK: Write A[{0,+,4}<%for.cond>]
+
+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/TempScop/tempscop-printing.ll b/final/test/TempScop/tempscop-printing.ll
new file mode 100644
index 0000000..fa1f967
--- /dev/null
+++ b/final/test/TempScop/tempscop-printing.ll
@@ -0,0 +1,85 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -basicaa -polly-analyze-ir -analyze < %s | FileCheck %s -check-prefix=SCALARACCESS
+
+; 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:
+; SCALARACCESS: BB: entry.next
+  %init = load i64, i64* %init_ptr
+; SCALARACCESS: Read init_ptr[0]
+; SCALARACCESS:  Write init[0]
+  br label %for.j
+
+for.j:
+  %indvar.j = phi i64 [ 0, %entry.next ], [ %indvar.j.next, %for.j ]
+; SCALARACCESS: BB: for.j
+; SCALARACCESS: Read init
+; SCALARACCESS: Write A[{0,+,8}<%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:
+; SCALARACCESS: BB: entry.next
+  %init = load i64, i64* %init_ptr
+; SCALARACCESS: Read init_ptr[0]
+; SCALARACCESS:  Write init[0]
+  br label %for.j
+
+for.j:
+; SCALARACCESS: BB: 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
+; SCALARACCESS: Read init
+; SCALARACCESS: Write A[{0,+,8}<%for.j>]
+  %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/create_ll.sh b/final/test/create_ll.sh
new file mode 100755
index 0000000..f6d8aee
--- /dev/null
+++ b/final/test/create_ll.sh
@@ -0,0 +1,33 @@
+#!/bin/sh -e
+
+LLFILE=`echo $1 | sed -e 's/\.c/.ll/g'`
+LLFILE_TMP=${LLFILE}.tmp
+
+# The number of lines to cut of the LLVM-IR file clang produces.
+CUT_N_LINES=6
+
+clang -c -S -emit-llvm -O0 $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} | sed -e 's/ \#0//' >> ${LLFILE}
+sed -i".tmp" '/; Function Attrs:/d' ${LLFILE}
+sed -i".tmp" '/; ModuleID =/d' ${LLFILE}
+sed -i".tmp" '/target triple/d' ${LLFILE}
+
+head --lines=-${CUT_N_LINES} ${LLFILE} > ${LLFILE_TMP}
+
+mv ${LLFILE_TMP} ${LLFILE}
diff --git a/final/test/lit.cfg b/final/test/lit.cfg
new file mode 100644
index 0000000..0d7eb3b
--- /dev/null
+++ b/final/test/lit.cfg
@@ -0,0 +1,126 @@
+# -*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'
+
+# 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.
+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 include the tools dir and the scripts dir.
+if polly_obj_root is not None:
+    llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
+    if not llvm_tools_dir:
+        lit_config.fatal('No LLVM tools dir set!')
+    path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
+    config.environment['PATH'] = path
+
+    llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
+    if not llvm_libs_dir:
+        lit_config.fatal('No LLVM libs dir set!')
+    path = os.path.pathsep.join((llvm_libs_dir,
+                                 config.environment.get('LD_LIBRARY_PATH','')))
+    config.environment['LD_LIBRARY_PATH'] = path
+
+###
+
+# Check that the object root is known.
+if config.test_exec_root is None:
+    # Otherwise, we haven't loaded the site specific configuration (the user is
+    # probably trying to run on a test file directly, and either the site
+    # configuration hasn't been created by the build system, or we are in an
+    # out-of-tree build situation).
+
+    # Check for 'polly_site_config' user parameter, and use that if available.
+    site_cfg = lit_config.params.get('polly_site_config', None)
+    if site_cfg and os.path.exists(site_cfg):
+        lit_config.load_config(config, site_cfg)
+        raise SystemExit
+
+    # Try to detect the situation where we are using an out-of-tree build by
+    # looking for 'llvm-config'.
+    #
+    # FIXME: I debated (i.e., wrote and threw away) adding logic to
+    # automagically generate the lit.site.cfg if we are in some kind of fresh
+    # build situation. This means knowing how to invoke the build system though,
+    # and I decided it was too much magic. We should solve this by just having
+    # the .cfg files generated during the configuration step.
+
+    llvm_config = lit.util.which('llvm-config', config.environment['PATH'])
+    if not llvm_config:
+        lit_config.fatal('No site specific configuration available!')
+
+    # Get the source and object roots.
+    llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip()
+    llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip()
+    polly_src_root = os.path.join(llvm_src_root, "tools", "polly")
+    polly_obj_root = os.path.join(llvm_obj_root, "tools", "polly")
+
+    # Validate that we got a tree which points to here, using the standard
+    # tools/polly layout.
+    this_src_root = os.path.dirname(config.test_source_root)
+    if os.path.realpath(polly_src_root) != os.path.realpath(this_src_root):
+        lit_config.fatal('No site specific configuration available!')
+
+    # Check that the site specific configuration exists.
+    site_cfg = os.path.join(polly_obj_root, 'test', 'lit.site.cfg')
+    if not os.path.exists(site_cfg):
+        lit_config.fatal('No site specific configuration available!')
+
+    # Okay, that worked. Notify the user of the automagic, and reconfigure.
+    lit_config.note('using out-of-tree build at %r' % polly_obj_root)
+    lit_config.load_config(config, site_cfg)
+    raise SystemExit
+
+# opt knows whether it is compiled with -DNDEBUG.
+import subprocess
+try:
+    opt_cmd = subprocess.Popen([os.path.join(llvm_tools_dir, 'opt'), '-version'],
+                           stdout = subprocess.PIPE)
+except OSError, why:
+    print "Could not find opt in " + llvm_tools_dir
+    exit(42)
+
+if re.search(r'with assertions', opt_cmd.stdout.read()):
+    config.available_features.add('asserts')
+opt_cmd.wait()
+
+try:
+    llvm_config_cmd = subprocess.Popen([os.path.join(llvm_tools_dir,
+                                                     'llvm-config'),
+                                        '--targets-built'],
+                                       stdout = subprocess.PIPE)
+except OSError, why:
+    print "Could not find llvm-config in " + llvm_tools_dir
+    exit(42)
+
+if re.search(r'NVPTX', llvm_config_cmd.stdout.read()):
+    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..7088789
--- /dev/null
+++ b/final/test/lit.site.cfg.in
@@ -0,0 +1,44 @@
+## 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 = "@CUDALIB_FOUND@"
+config.link_polly_into_tools = "@LINK_POLLY_INTO_TOOLS@"
+
+## 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\"'
+
+# 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:
+    key, = e.args
+    lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
+
+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@'))
+else:
+    config.substitutions.append(('%loadPolly', ''))
+
+config.substitutions.append(('%polybenchOpts', ' -O3 -loop-simplify -indvars '))
+
+# 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..0c36765
--- /dev/null
+++ b/final/test/polly.ll
@@ -0,0 +1,11 @@
+; RUN: opt %loadPolly -polly-detect-unprofitable -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/tools/CMakeLists.txt b/final/tools/CMakeLists.txt
new file mode 100644
index 0000000..4ce60e1
--- /dev/null
+++ b/final/tools/CMakeLists.txt
@@ -0,0 +1,5 @@
+if (CUDALIB_FOUND)
+  add_subdirectory(GPURuntime)
+endif (CUDALIB_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..bbfd1b5
--- /dev/null
+++ b/final/tools/GPURuntime/CMakeLists.txt
@@ -0,0 +1,14 @@
+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(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=default")
diff --git a/final/tools/GPURuntime/GPUJIT.c b/final/tools/GPURuntime/GPUJIT.c
new file mode 100644
index 0000000..ece53e7
--- /dev/null
+++ b/final/tools/GPURuntime/GPUJIT.c
@@ -0,0 +1,430 @@
+/******************** 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"
+#include <cuda.h>
+#include <cuda_runtime.h>
+#include <dlfcn.h>
+#include <stdio.h>
+
+/* Define Polly's GPGPU data types. */
+struct PollyGPUContextT {
+  CUcontext Cuda;
+};
+
+struct PollyGPUModuleT {
+  CUmodule Cuda;
+};
+
+struct PollyGPUFunctionT {
+  CUfunction Cuda;
+};
+
+struct PollyGPUDeviceT {
+  CUdevice Cuda;
+};
+
+struct PollyGPUDevicePtrT {
+  CUdeviceptr Cuda;
+};
+
+struct PollyGPUEventT {
+  cudaEvent_t 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 CuFuncSetBlockShapeFcnTy(CUfunction, int, int, int);
+static CuFuncSetBlockShapeFcnTy *CuFuncSetBlockShapeFcnPtr;
+
+typedef CUresult CUDAAPI
+CuParamSetvFcnTy(CUfunction, int, void *, unsigned int);
+static CuParamSetvFcnTy *CuParamSetvFcnPtr;
+
+typedef CUresult CUDAAPI CuParamSetSizeFcnTy(CUfunction, unsigned int);
+static CuParamSetSizeFcnTy *CuParamSetSizeFcnPtr;
+
+typedef CUresult CUDAAPI CuLaunchGridFcnTy(CUfunction, int, int);
+static CuLaunchGridFcnTy *CuLaunchGridFcnPtr;
+
+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 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 CuDeviceGetFcnTy(CUdevice *, int);
+static CuDeviceGetFcnTy *CuDeviceGetFcnPtr;
+
+typedef CUresult CUDAAPI CuModuleLoadDataExFcnTy(
+    CUmodule *, const void *, unsigned int, CUjit_option *, void **);
+static CuModuleLoadDataExFcnTy *CuModuleLoadDataExFcnPtr;
+
+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;
+
+/* Type-defines of function pointer ot CUDA runtime APIs. */
+typedef cudaError_t CUDARTAPI CudaEventCreateFcnTy(cudaEvent_t *);
+static CudaEventCreateFcnTy *CudaEventCreateFcnPtr;
+
+typedef cudaError_t CUDARTAPI CudaEventRecordFcnTy(cudaEvent_t, cudaStream_t);
+static CudaEventRecordFcnTy *CudaEventRecordFcnPtr;
+
+typedef cudaError_t CUDARTAPI CudaEventSynchronizeFcnTy(cudaEvent_t);
+static CudaEventSynchronizeFcnTy *CudaEventSynchronizeFcnPtr;
+
+typedef cudaError_t CUDARTAPI
+CudaEventElapsedTimeFcnTy(float *, cudaEvent_t, cudaEvent_t);
+static CudaEventElapsedTimeFcnTy *CudaEventElapsedTimeFcnPtr;
+
+typedef cudaError_t CUDARTAPI CudaEventDestroyFcnTy(cudaEvent_t);
+static CudaEventDestroyFcnTy *CudaEventDestroyFcnPtr;
+
+typedef cudaError_t CUDARTAPI CudaThreadSynchronizeFcnTy(void);
+static CudaThreadSynchronizeFcnTy *CudaThreadSynchronizeFcnPtr;
+
+static void *getAPIHandle(void *Handle, const char *FuncName) {
+  char *Err;
+  void *FuncPtr;
+  dlerror();
+  FuncPtr = dlsym(Handle, FuncName);
+  if ((Err = dlerror()) != 0) {
+    fprintf(stdout, "Load CUDA driver API failed: %s. \n", Err);
+    return 0;
+  }
+  return FuncPtr;
+}
+
+static int initialDeviceAPILibraries() {
+  HandleCuda = dlopen("libcuda.so", RTLD_LAZY);
+  if (!HandleCuda) {
+    printf("Cannot open library: %s. \n", dlerror());
+    return 0;
+  }
+
+  HandleCudaRT = dlopen("libcudart.so", RTLD_LAZY);
+  if (!HandleCudaRT) {
+    printf("Cannot open library: %s. \n", dlerror());
+    return 0;
+  }
+
+  return 1;
+}
+
+static int initialDeviceAPIs() {
+  if (initialDeviceAPILibraries() == 0)
+    return 0;
+
+  /* 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.
+   */
+  CuFuncSetBlockShapeFcnPtr = (CuFuncSetBlockShapeFcnTy *)getAPIHandle(
+      HandleCuda, "cuFuncSetBlockShape");
+
+  CuParamSetvFcnPtr =
+      (CuParamSetvFcnTy *)getAPIHandle(HandleCuda, "cuParamSetv");
+
+  CuParamSetSizeFcnPtr =
+      (CuParamSetSizeFcnTy *)getAPIHandle(HandleCuda, "cuParamSetSize");
+
+  CuLaunchGridFcnPtr =
+      (CuLaunchGridFcnTy *)getAPIHandle(HandleCuda, "cuLaunchGrid");
+
+  CuMemAllocFcnPtr =
+      (CuMemAllocFcnTy *)getAPIHandle(HandleCuda, "cuMemAlloc_v2");
+
+  CuMemFreeFcnPtr = (CuMemFreeFcnTy *)getAPIHandle(HandleCuda, "cuMemFree_v2");
+
+  CuMemcpyDtoHFcnPtr =
+      (CuMemcpyDtoHFcnTy *)getAPIHandle(HandleCuda, "cuMemcpyDtoH_v2");
+
+  CuMemcpyHtoDFcnPtr =
+      (CuMemcpyHtoDFcnTy *)getAPIHandle(HandleCuda, "cuMemcpyHtoD_v2");
+
+  CuModuleUnloadFcnPtr =
+      (CuModuleUnloadFcnTy *)getAPIHandle(HandleCuda, "cuModuleUnload");
+
+  CuCtxDestroyFcnPtr =
+      (CuCtxDestroyFcnTy *)getAPIHandle(HandleCuda, "cuCtxDestroy");
+
+  CuInitFcnPtr = (CuInitFcnTy *)getAPIHandle(HandleCuda, "cuInit");
+
+  CuDeviceGetCountFcnPtr =
+      (CuDeviceGetCountFcnTy *)getAPIHandle(HandleCuda, "cuDeviceGetCount");
+
+  CuDeviceGetFcnPtr =
+      (CuDeviceGetFcnTy *)getAPIHandle(HandleCuda, "cuDeviceGet");
+
+  CuCtxCreateFcnPtr =
+      (CuCtxCreateFcnTy *)getAPIHandle(HandleCuda, "cuCtxCreate_v2");
+
+  CuModuleLoadDataExFcnPtr =
+      (CuModuleLoadDataExFcnTy *)getAPIHandle(HandleCuda, "cuModuleLoadDataEx");
+
+  CuModuleGetFunctionFcnPtr = (CuModuleGetFunctionFcnTy *)getAPIHandle(
+      HandleCuda, "cuModuleGetFunction");
+
+  CuDeviceComputeCapabilityFcnPtr =
+      (CuDeviceComputeCapabilityFcnTy *)getAPIHandle(
+          HandleCuda, "cuDeviceComputeCapability");
+
+  CuDeviceGetNameFcnPtr =
+      (CuDeviceGetNameFcnTy *)getAPIHandle(HandleCuda, "cuDeviceGetName");
+
+  /* Get function pointer to CUDA Runtime APIs. */
+  CudaEventCreateFcnPtr =
+      (CudaEventCreateFcnTy *)getAPIHandle(HandleCudaRT, "cudaEventCreate");
+
+  CudaEventRecordFcnPtr =
+      (CudaEventRecordFcnTy *)getAPIHandle(HandleCudaRT, "cudaEventRecord");
+
+  CudaEventSynchronizeFcnPtr = (CudaEventSynchronizeFcnTy *)getAPIHandle(
+      HandleCudaRT, "cudaEventSynchronize");
+
+  CudaEventElapsedTimeFcnPtr = (CudaEventElapsedTimeFcnTy *)getAPIHandle(
+      HandleCudaRT, "cudaEventElapsedTime");
+
+  CudaEventDestroyFcnPtr =
+      (CudaEventDestroyFcnTy *)getAPIHandle(HandleCudaRT, "cudaEventDestroy");
+
+  CudaThreadSynchronizeFcnPtr = (CudaThreadSynchronizeFcnTy *)getAPIHandle(
+      HandleCudaRT, "cudaThreadSynchronize");
+
+  return 1;
+}
+
+void polly_initDevice(PollyGPUContext **Context, PollyGPUDevice **Device) {
+  int Major = 0, Minor = 0, DeviceID = 0;
+  char DeviceName[256];
+  int DeviceCount = 0;
+
+  /* Get API handles. */
+  if (initialDeviceAPIs() == 0) {
+    fprintf(stdout, "Getting the \"handle\" for the CUDA driver API failed.\n");
+    exit(-1);
+  }
+
+  if (CuInitFcnPtr(0) != CUDA_SUCCESS) {
+    fprintf(stdout, "Initializing the CUDA driver API failed.\n");
+    exit(-1);
+  }
+
+  /* Get number of devices that supports CUDA. */
+  CuDeviceGetCountFcnPtr(&DeviceCount);
+  if (DeviceCount == 0) {
+    fprintf(stdout, "There is no device supporting CUDA.\n");
+    exit(-1);
+  }
+
+  /* We select the 1st device as default. */
+  *Device = malloc(sizeof(PollyGPUDevice));
+  if (*Device == 0) {
+    fprintf(stdout, "Allocate memory for Polly GPU device failed.\n");
+    exit(-1);
+  }
+  CuDeviceGetFcnPtr(&((*Device)->Cuda), 0);
+
+  /* Get compute capabilities and the device name. */
+  CuDeviceComputeCapabilityFcnPtr(&Major, &Minor, (*Device)->Cuda);
+  CuDeviceGetNameFcnPtr(DeviceName, 256, (*Device)->Cuda);
+  fprintf(stderr, "> Running on GPU device %d : %s.\n", DeviceID, DeviceName);
+
+  /* Create context on the device. */
+  *Context = malloc(sizeof(PollyGPUContext));
+  if (*Context == 0) {
+    fprintf(stdout, "Allocate memory for Polly GPU context failed.\n");
+    exit(-1);
+  }
+  CuCtxCreateFcnPtr(&((*Context)->Cuda), 0, (*Device)->Cuda);
+}
+
+void polly_getPTXModule(void *PTXBuffer, PollyGPUModule **Module) {
+  *Module = malloc(sizeof(PollyGPUModule));
+  if (*Module == 0) {
+    fprintf(stdout, "Allocate memory for Polly GPU module failed.\n");
+    exit(-1);
+  }
+
+  if (CuModuleLoadDataExFcnPtr(&((*Module)->Cuda), PTXBuffer, 0, 0, 0) !=
+          CUDA_SUCCESS) {
+    fprintf(stdout, "Loading ptx assembly text failed.\n");
+    exit(-1);
+  }
+}
+
+void polly_getPTXKernelEntry(const char *KernelName, PollyGPUModule *Module,
+                             PollyGPUFunction **Kernel) {
+  *Kernel = malloc(sizeof(PollyGPUFunction));
+  if (*Kernel == 0) {
+    fprintf(stdout, "Allocate memory for Polly GPU kernel failed.\n");
+    exit(-1);
+  }
+
+  /* Locate the kernel entry point. */
+  if (CuModuleGetFunctionFcnPtr(&((*Kernel)->Cuda), Module->Cuda, KernelName) !=
+          CUDA_SUCCESS) {
+    fprintf(stdout, "Loading kernel function failed.\n");
+    exit(-1);
+  }
+}
+
+void polly_startTimerByCudaEvent(PollyGPUEvent **Start, PollyGPUEvent **Stop) {
+  *Start = malloc(sizeof(PollyGPUEvent));
+  if (*Start == 0) {
+    fprintf(stdout, "Allocate memory for Polly GPU start timer failed.\n");
+    exit(-1);
+  }
+  CudaEventCreateFcnPtr(&((*Start)->Cuda));
+
+  *Stop = malloc(sizeof(PollyGPUEvent));
+  if (*Stop == 0) {
+    fprintf(stdout, "Allocate memory for Polly GPU stop timer failed.\n");
+    exit(-1);
+  }
+  CudaEventCreateFcnPtr(&((*Stop)->Cuda));
+
+  /* Record the start time. */
+  CudaEventRecordFcnPtr((*Start)->Cuda, 0);
+}
+
+void polly_stopTimerByCudaEvent(PollyGPUEvent *Start, PollyGPUEvent *Stop,
+                                float *ElapsedTimes) {
+  /* Record the end time. */
+  CudaEventRecordFcnPtr(Stop->Cuda, 0);
+  CudaEventSynchronizeFcnPtr(Start->Cuda);
+  CudaEventSynchronizeFcnPtr(Stop->Cuda);
+  CudaEventElapsedTimeFcnPtr(ElapsedTimes, Start->Cuda, Stop->Cuda);
+  CudaEventDestroyFcnPtr(Start->Cuda);
+  CudaEventDestroyFcnPtr(Stop->Cuda);
+  fprintf(stderr, "Processing time: %f (ms).\n", *ElapsedTimes);
+
+  free(Start);
+  free(Stop);
+}
+
+void polly_allocateMemoryForHostAndDevice(
+    void **HostData, PollyGPUDevicePtr **DevData, int MemSize) {
+  if ((*HostData = (int *)malloc(MemSize)) == 0) {
+    fprintf(stdout, "Could not allocate host memory.\n");
+    exit(-1);
+  }
+
+  *DevData = malloc(sizeof(PollyGPUDevicePtr));
+  if (*DevData == 0) {
+    fprintf(stdout, "Allocate memory for GPU device memory pointer failed.\n");
+    exit(-1);
+  }
+  CuMemAllocFcnPtr(&((*DevData)->Cuda), MemSize);
+}
+
+void polly_copyFromHostToDevice(PollyGPUDevicePtr *DevData, void *HostData,
+                                int MemSize) {
+  CUdeviceptr CuDevData = DevData->Cuda;
+  CuMemcpyHtoDFcnPtr(CuDevData, HostData, MemSize);
+}
+
+void polly_copyFromDeviceToHost(void *HostData, PollyGPUDevicePtr *DevData,
+                                int MemSize) {
+  if (CuMemcpyDtoHFcnPtr(HostData, DevData->Cuda, MemSize) != CUDA_SUCCESS) {
+    fprintf(stdout, "Copying results from device to host memory failed.\n");
+    exit(-1);
+  }
+}
+
+void polly_setKernelParameters(PollyGPUFunction *Kernel, int BlockWidth,
+                               int BlockHeight, PollyGPUDevicePtr *DevData) {
+  int ParamOffset = 0;
+
+  CuFuncSetBlockShapeFcnPtr(Kernel->Cuda, BlockWidth, BlockHeight, 1);
+  CuParamSetvFcnPtr(Kernel->Cuda, ParamOffset, &(DevData->Cuda),
+                    sizeof(DevData->Cuda));
+  ParamOffset += sizeof(DevData->Cuda);
+  CuParamSetSizeFcnPtr(Kernel->Cuda, ParamOffset);
+}
+
+void polly_launchKernel(PollyGPUFunction *Kernel, int GridWidth,
+                        int GridHeight) {
+  if (CuLaunchGridFcnPtr(Kernel->Cuda, GridWidth, GridHeight) != CUDA_SUCCESS) {
+    fprintf(stdout, "Launching CUDA kernel failed.\n");
+    exit(-1);
+  }
+  CudaThreadSynchronizeFcnPtr();
+  fprintf(stdout, "CUDA kernel launched.\n");
+}
+
+void polly_cleanupGPGPUResources(
+    void *HostData, PollyGPUDevicePtr *DevData, PollyGPUModule *Module,
+    PollyGPUContext *Context, PollyGPUFunction *Kernel) {
+  if (HostData) {
+    free(HostData);
+    HostData = 0;
+  }
+
+  if (DevData->Cuda) {
+    CuMemFreeFcnPtr(DevData->Cuda);
+    free(DevData);
+  }
+
+  if (Module->Cuda) {
+    CuModuleUnloadFcnPtr(Module->Cuda);
+    free(Module);
+  }
+
+  if (Context->Cuda) {
+    CuCtxDestroyFcnPtr(Context->Cuda);
+    free(Context);
+  }
+
+  if (Kernel) {
+    free(Kernel);
+  }
+
+  dlclose(HandleCuda);
+  dlclose(HandleCudaRT);
+}
diff --git a/final/tools/GPURuntime/GPUJIT.h b/final/tools/GPURuntime/GPUJIT.h
new file mode 100644
index 0000000..5ed41ce
--- /dev/null
+++ b/final/tools/GPURuntime/GPUJIT.h
@@ -0,0 +1,106 @@
+/******************************************************************************/
+/*                                                                            */
+/*                     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_
+
+/*
+ * 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() {
+ *   PollyGPUContext *Context;
+ *   PollyGPUModule *Module;
+ *   PollyGPUFunction *Kernel;
+ *   PollyGPUDevice *Device;
+ *   PollyGPUDevicePtr *PtrDevData;
+ *   int *HostData;
+ *   PollyGPUEvent *Start;
+ *   PollyGPUEvent *Stop;
+ *   float *ElapsedTime;
+ *   int MemSize;
+ *   int BlockWidth = 16;
+ *   int BlockHeight = 16;
+ *   int GridWidth = 8;
+ *   int GridHeight = 8;
+ *
+ *   MemSize = 256*64*sizeof(int);
+ *   polly_initDevice(&Context, &Device);
+ *   polly_getPTXModule(KernelString, &Module);
+ *   polly_getPTXKernelEntry(Entry, Module, &Kernel);
+ *   polly_allocateMemoryForHostAndDevice(&HostData, &DevData, MemSize);
+ *   polly_setKernelParameters(Kernel, BlockWidth, BlockHeight, DevData);
+ *   polly_startTimerByCudaEvent(&Start, &Stop);
+ *   polly_launchKernel(Kernel, GridWidth, GridHeight);
+ *   polly_copyFromDeviceToHost(HostData, DevData, MemSize);
+ *   polly_stopTimerByCudaEvent(Start, Stop, ElapsedTime);
+ *   polly_cleanupGPGPUResources(HostData, DevData, Module, Context, Kernel);
+ * }
+ *
+ */
+
+typedef struct PollyGPUContextT PollyGPUContext;
+typedef struct PollyGPUModuleT PollyGPUModule;
+typedef struct PollyGPUFunctionT PollyGPUFunction;
+typedef struct PollyGPUDeviceT PollyGPUDevice;
+typedef struct PollyGPUDevicePtrT PollyGPUDevicePtr;
+typedef struct PollyGPUEventT PollyGPUEvent;
+
+void polly_initDevice(PollyGPUContext **Context, PollyGPUDevice **Device);
+void polly_getPTXModule(void *PTXBuffer, PollyGPUModule **Module);
+void polly_getPTXKernelEntry(const char *KernelName, PollyGPUModule *Module,
+                             PollyGPUFunction **Kernel);
+void polly_startTimerByCudaEvent(PollyGPUEvent **Start, PollyGPUEvent **Stop);
+void polly_stopTimerByCudaEvent(PollyGPUEvent *Start, PollyGPUEvent *Stop,
+                                float *ElapsedTimes);
+void polly_copyFromHostToDevice(PollyGPUDevicePtr *DevData, void *HostData,
+                                int MemSize);
+void polly_copyFromDeviceToHost(void *HostData, PollyGPUDevicePtr *DevData,
+                                int MemSize);
+void polly_allocateMemoryForHostAndDevice(void **HostData,
+                                          PollyGPUDevicePtr **DevData,
+                                          int MemSize);
+void polly_setKernelParameters(PollyGPUFunction *Kernel, int BlockWidth,
+                               int BlockHeight, PollyGPUDevicePtr *DevData);
+void polly_launchKernel(PollyGPUFunction *Kernel, int GridWidth,
+                        int GridHeight);
+void polly_cleanupGPGPUResources(void *HostData, PollyGPUDevicePtr *DevData,
+                                 PollyGPUModule *Module,
+                                 PollyGPUContext *Context,
+                                 PollyGPUFunction *Kernel);
+#endif /* GPUJIT_H_ */
diff --git a/final/tools/GPURuntime/LICENSE.TXT b/final/tools/GPURuntime/LICENSE.TXT
new file mode 100644
index 0000000..e2461ab
--- /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-2014 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-2014 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/tools/GPURuntime/Makefile b/final/tools/GPURuntime/Makefile
new file mode 100644
index 0000000..4822f70
--- /dev/null
+++ b/final/tools/GPURuntime/Makefile
@@ -0,0 +1,16 @@
+##===- polly/lib/GPURuntime/Makefile -----------------------*- Makefile -*-===##
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+
+LIBRARYNAME = libGPURuntime
+LOADABLE_MODULE = 1
+
+include $(LEVEL)/Makefile.config
+CPP.Flags += $(POLLY_INC)
+include $(LEVEL)/Makefile.common
diff --git a/final/tools/Makefile b/final/tools/Makefile
new file mode 100644
index 0000000..21b6a42
--- /dev/null
+++ b/final/tools/Makefile
@@ -0,0 +1,20 @@
+##===- tools/Makefile --------------------------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ..
+DIRS :=
+
+include $(LEVEL)/Makefile.config
+
+# GPU Runtime Support
+ifeq ($(CUDALIB_FOUND), yes)
+ DIRS += GPURuntime
+endif
+
+include $(LEVEL)/Makefile.common
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..eb495be
--- /dev/null
+++ b/final/utils/arcanist/LitTestEngine/src/LitTestEngine.php
@@ -0,0 +1,268 @@
+<?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);
+        print "Using build directory '$buildDir'\n";
+        $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, $buildDir."/test");
+        $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."Makefile") &&
+                (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/check_format.sh b/final/utils/check_format.sh
new file mode 100755
index 0000000..4d7b033
--- /dev/null
+++ b/final/utils/check_format.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+CLANG_FORMAT=${CLANG_FORMAT}
+
+if [ "${CLANG_FORMAT}x" = "x" ]; then
+  CLANG_FORMAT=`which clang-format`
+  if [ "${CLANG_FORMAT}x" = "x" ]; then
+     echo "Error: cannot find clang-format in your path"
+     exit 1
+  fi
+fi
+
+OK=0
+
+for ARG in "$@"
+  do
+    ${CLANG_FORMAT} -style=llvm $ARG | diff -u $ARG - >&2
+
+    if [[ $? -eq 1 ]]; then
+      OK=1
+    fi
+  done
+
+if [[ $OK -eq "1" ]]; then
+  echo "Error: clang-format reported formatting differences"
+  exit 1
+else
+  echo "OK: clang-format reported no formatting differences"
+  exit 0
+fi
+
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/utils/update_format.sh b/final/utils/update_format.sh
new file mode 100755
index 0000000..9226fc6
--- /dev/null
+++ b/final/utils/update_format.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+CLANG_FORMAT=${CLANG_FORMAT}
+
+if [ "${CLANG_FORMAT}x" = "x" ]; then
+  CLANG_FORMAT=`which clang-format`
+  if [ "${CLANG_FORMAT}x" = "x" ]; then
+     echo "Error: cannot find clang-format in your path"
+     exit 1
+  fi
+fi
+
+for ARG in "$@"
+  do
+    ${CLANG_FORMAT} -i $ARG
+  done
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..87254a8
--- /dev/null
+++ b/final/www/bugs.html
@@ -0,0 +1,37 @@
+<!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.
+
+<h3>File a  Bug</h3>
+
+If a problem appears, please <a
+href="http://llvm.org/bugs/enter_bug.cgi?product=Projects&component=Polly">
+report a bug</a> to the LLVM bugzilla. Polly bugs are tracked under product
+'Projects' and component 'Polly'.
+
+
+<h3>Open Bugs</h3>
+A list of the <a
+href="http://llvm.org/bugs/buglist.cgi?query_format=advanced&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&component=Polly&product=Projects">open
+bugs</a> in Polly is also available.
+
+</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..549b2a9
--- /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; margin-bottom: -0.25em; 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..eddf1cf
--- /dev/null
+++ b/final/www/documentation.html
@@ -0,0 +1,40 @@
+<!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_load_Polly_into_dragonegg.html">Use Polly in dragonegg</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="documentation/memaccess.html">Polly - Memory access optimizations
+</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/memaccess.html b/final/www/documentation/memaccess.html
new file mode 100644
index 0000000..fa48771
--- /dev/null
+++ b/final/www/documentation/memaccess.html
@@ -0,0 +1,128 @@
+<!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 - Memory access optimizations</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>Memory access optimizations</h1>
+  <!--*********************************************************************-->
+<p><em>WARNING: This project was part of the Google Summer of Code 2011.
+Tt 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 be
+changed during the actual implementation.</em></p>
+
+This project adds memory access transformations to Polly. In many cases
+changing the memory access pattern yields to better data locality or removes
+dependences that would otherwise block transformations.
+
+<p>An examples which uses this feature is given below.</p>
+
+Consider the following loop
+<pre>
+for (i = 0; i < 8; i++)
+  sum += A[i];
+</pre>
+Through memory access transformations this loop can be executed in parallel.
+It can be transformed to
+<pre>
+<em>// Create and initialize an array 'tmp' with size 4</em>
+for (i = 0; i < 8; i++)
+  tmp[i % 4] += A[i];
+sum = tmp[0] + tmp[1] + tmp[2] + tmp[3];
+</pre>
+
+Optimizers like PluTo can schedule the code such that an outer, parallel
+loop is created:
+<pre>
+parfor (ii = 0; ii < 4; ii++) {
+  tmp[ii] = 0;
+  for (i = ii * 2; i < (ii+1) * 2; i++)
+    tmp[ii] += A[i];
+  }
+sum = tmp[0] + tmp[1] + tmp[2] + tmp[3];
+</pre>
+
+<h2>TODO</h2>
+<h3>Step 1</h3>
+Polly exports its polyhedral description in a JSCoP file. Define how memory
+layout transformations are expressed in Polly and in the JSCOP file. 
+Example:
+
+<p>Consider the following loop.</p>
+<pre>
+for (i = 0; i < 12; i++)
+  A[i] = 0;
+</pre>
+In the JSCOP file the memory accesses are represented as follows.
+<pre>
+"accesses": [{
+        "kind": "write",
+                "relation": "{ Stmt[i] -> A[i] }"
+}]
+</pre>
+To perform a transformation we generate the following code:
+<pre>
+for (i = 0; i < 12; i++)
+  A[0] = i;
+</pre>
+The representation in the JSCoP file is:
+<pre>
+"accesses": [{
+        "kind": "read",
+                "relation": "{ Stmt[i] -> A[0] }"
+}]
+</pre>
+We need to detect this access function change.
+
+<h3>Step 2</h3>
+Update the code generation module to reflect the access function change made
+in Step 1.
+<h3>Step 2.1 Code generation for a constant</h3>
+In the JSCOP file an access function which has variables is changed to a
+constant. Code is generated to reflect this change. Let the content of original
+JSCOP file be:
+<pre>
+"accesses" : [{
+        "kind" : "read",
+                 "relation" : "{ Stmt_for_body[i0] -> MemRef_A[i0] }"
+}]
+</pre>
+The transformed JSCOP file is:
+<pre>
+"accesses" : [{
+        "kind" : "read",
+                 "relation" : "{ Stmt_for_body[i0] -> MemRef_A[10] }"
+}]
+</pre>
+Code is generated for this change.
+<h3>Step 2.2 Code generation for coefficients</h3>
+The coefficients of induction variables are changed here. Let the original
+JSCOP file be:
+<pre>
+"accesses" : [{
+      "kind" : "read",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_A[32i0+i1] }"
+}]
+</pre>
+The transformed JSCOP file is:
+<pre>
+"accesses" : [{
+      "kind" : "read",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_A[16i0+2i1+5] }"
+}]
+</pre>
+Code is generated for this change.
+</div>
+</div>
+</body>
+</html>
+
diff --git a/final/www/documentation/passes.html b/final/www/documentation/passes.html
new file mode 100644
index 0000000..8d22c41
--- /dev/null
+++ b/final/www/documentation/passes.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 - 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-prepare</em> Prepare code for Polly</li>
+<li><em>polly-detect</em> Detect SCoPs in functions</li>
+<li><em>polly-analyze-ir</em> Analyse the LLVM-IR in the detected SCoPs</li>
+<li><em>polly-independent</em> Create independent blocks</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-pocc</em> Optimize the SCoP using PoCC [removed after <a href="http://llvm.org/releases/download.html#3.4.2">LLVM 3.4.2</a>]</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/example_load_Polly_into_clang.html b/final/www/example_load_Polly_into_clang.html
new file mode 100644
index 0000000..5e6514f
--- /dev/null
+++ b/final/www/example_load_Polly_into_clang.html
@@ -0,0 +1,143 @@
+<!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 - Load Polly into clang</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>Load Polly into clang and automatically run it at -O3</h1>
+<!--=====================================================================-->
+
+<p><b>Warning:</b> Even though this example makes it very easy to use Polly,
+you should be aware that Polly is a young research project. It is expected
+to crash, produce invalid code or to hang in complex calculations even for
+simple examples. In case you see such a problem, please check the <a
+href="bugs.html">Bug database</a> and consider reporting a bug.
+<p>
+<b>Warning II:</b> clang/LLVM/Polly need to be in sync. This means
+            you need to compile them yourself from a recent svn/git checkout</b>
+<h2>Load Polly into clang</h2>
+
+By default Polly is configured as a shared library plugin that is loaded in
+tools like clang, opt, and bugpoint when they start their execution.
+
+By loading Polly into clang (or opt) the Polly options become automatically
+available. You can load Polly either by adding the relevant commands to
+the CPPFLAGS or by creating an alias.
+
+<pre class="code">
+$ export CPPFLAGS="-Xclang -load -Xclang ${POLLY_BUILD_DIR}/lib/LLVMPolly.so"
+</pre>
+
+or
+<pre class="code">
+$ alias pollycc clang -Xclang -load -Xclang ${POLLY_BUILD_DIR}/lib/LLVMPolly.so
+</pre>
+
+To avoid having to load Polly in the tools, Polly can optionally be configured
+with cmake to be statically linked in the tools:
+
+<pre class="code">
+$ cmake -D LINK_POLLY_INTO_TOOLS:Bool=ON
+</pre>
+
+<h2>Optimizing with Polly</h2>
+
+Optimizing with Polly is as easy as adding <b>-O3 -mllvm -polly</b> to your
+compiler flags (Polly is only available at -O3).
+
+<pre class="code">pollycc -O3 -mllvm -polly file.c</pre>
+
+<h2>Automatic OpenMP code generation</h2>
+
+To automatically detect parallel loops and generate OpenMP code for them you
+also need to add <b>-mllvm -polly-parallel -lgomp</b> to your CFLAGS.
+
+<pre class="code">pollycc -O3 -mllvm -polly -mllvm -polly-parallel -lgomp file.c</pre>
+
+<h2>Automatic Vector code generation</h2>
+
+Automatic vector code generation can be enabled by adding <b>-mllvm
+-polly-vectorizer=stripmine</b> to your CFLAGS.
+
+<pre class="code">pollycc -O3 -mllvm -polly -mllvm -polly-vectorizer=stripmine file.c</pre>
+
+<h2>Extract a preoptimized LLVM-IR file</h2>
+
+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'.
+
+<pre class="code">pollycc -O0 -mllvm -polly -S -emit-llvm file.c</pre>
+
+<h2>Further options</h2>
+
+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
+<b>-mllvm -option-name</b> to the CFLAGS or the clang
+command line.
+
+<h3>Limit Polly to a single function</h3>
+To limit the execution of Polly to a single function, use the option
+<b>-polly-only-func=functionname</b>.
+
+<h3>Disable LLVM-IR generation</h3>
+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 <b>polly-no-codegen</b>.
+
+<h3>Graphical view of the SCoPs</h3>
+
+Polly can use graphviz to show the SCoPs it detects in a program. The relevant
+options are <b>-polly-show</b>, <b>-polly-show-only</b>, <b>-polly-dot</b> and
+<b>-polly-dot-only</b>. 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.
+
+<h3>Change/Disable the Optimizer</h3>
+Polly uses by default the isl scheduling optimizer. The isl optimizer optimizes
+for data-locality and parallelism using the <a
+href="http://pluto-compiler.sf.net">Pluto</a> algorithm. For research it is also
+possible to run <a
+href="http://www-rocq.inria.fr/~pouchet/software/pocc/">PoCC</a> as external
+optimizer. PoCC provides access to the original Pluto implementation. To use
+PoCC add <b>-polly-optimizer=pocc</b> to the command line (only available if
+Polly was compiled with scoplib support) [removed after <a href="http://llvm.org/releases/download.html#3.4.2">LLVM 3.4.2</a>].
+To disable the optimizer entirely use the option <b>-polly-optimizer=none</b>.
+
+<h3>Disable tiling in the optimizer</h3>
+By default both optimizers perform tiling, if possible. In case this is not
+wanted the option <b>-polly-no-tiling</b> can be used to disable it. (This
+option disables tiling for both optimizers).
+
+<h3>Ignore possible aliasing</h3>
+By default we only detect scops, if we can prove that the different array bases
+can not alias. This is correct do if we optimize automatically.  However,
+without special user annotations like 'restrict' we can often not prove that
+no aliasing is possible. In case the user knows no aliasing can happen in the
+code the <b>-polly-ignore-aliasing</b> can be used to disable the check for
+possible aliasing.
+
+<h3>Import / Export</h3>
+The flags <b>-polly-import</b> and <b>-polly-export</b> 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.
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/example_load_Polly_into_dragonegg.html b/final/www/example_load_Polly_into_dragonegg.html
new file mode 100644
index 0000000..ef9f68b
--- /dev/null
+++ b/final/www/example_load_Polly_into_dragonegg.html
@@ -0,0 +1,71 @@
+<!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 - Load Polly into dragonegg</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>Load Polly into dragonegg and automatically run it at -O3</h1>
+<!--=====================================================================-->
+
+<p><b>Note:</b>This is a quick note on how to load Polly into
+  dragonegg. The choice of front-end does not affect the passes
+  available with Polly, only the syntax is different.
+  The <a href="example_load_Polly_into_clang.html">examples for use
+  with clang</a> can also be performed with Polly, with suitable
+  corrections in the syntax.
+
+<h2>Compile dragonegg with support for LLVM plugins</h2>
+
+The support for LLVM plugins in dragonegg is still experimental, and
+hence protected by a build option. You must rebuild dragonegg with the
+following options:
+
+<pre class="code">
+$ GCC=${PATH_TO_GCC} LLVM_CONFIG=${PATH_TO_LLVM_CONFIG} ENABLE_LLVM_PLUGINS=1 make
+</pre>
+
+<h2>Load Polly into dragonegg</h2>
+
+By loading Polly into dragonegg, the Polly options become automatically
+available. You can load Polly either by adding the relevant commands to
+the CPPFLAGS or by creating an alias.
+
+<pre class="code">
+$ export CPPFLAGS="-fplugin=/path/to/dragonegg.so -fplugin-arg-dragonegg-llvm-option=-load:${POLLY_BUILD_DIR}/lib/LLVMPolly.so"
+</pre>
+
+or
+
+<pre class="code">
+$ alias pollycc gcc -fplugin=/path/to/dragonegg.so -fplugin-arg-dragonegg-llvm-option=-load:${POLLY_BUILD_DIR}/lib/LLVMPolly.so
+</pre>
+
+<h2>Optimizing with Polly</h2>
+
+Optimizing with Polly is as easy as adding <b>-O3 -fplugin-arg-dragonegg-llvm-option=-polly</b> to your
+compiler flags (Polly is only available at -O3).
+
+<pre class="code">pollycc -O3 -fplugin-arg-dragonegg-llvm-option=-polly file.c</pre>
+
+<h2>Passing various options to Polly</h2>
+
+As must be evident from the examples so far, options to LLVM and its
+plugins are passed via the <b>-fplugin-arg-dragonegg-llvm-option</b>
+commandline argment.
+The <a href="example_load_Polly_into_clang.html">examples for use with
+clang</a> can be executed with dragonegg by replacing
+the <b>-mllvm</b> syntax with the dragonegg syntax.
+
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/example_manual_matmul.html b/final/www/example_manual_matmul.html
new file mode 100644
index 0000000..50faa6d
--- /dev/null
+++ b/final/www/example_manual_matmul.html
@@ -0,0 +1,454 @@
+<!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 - Examples</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>Execute the individual Polly passes manually</h1>
+<!--=====================================================================-->
+
+<p>
+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.</p>
+
+The files used and created in this example are available in the Polly checkout
+in the folder <em>www/experiments/matmul</em>. They can be created automatically
+by running the <em>www/experiments/matmul/runall.sh</em> script.
+
+<ol>
+<li><h4>Create LLVM-IR from the C code</h4>
+
+Polly works on LLVM-IR. Hence it is necessary to translate the source files into
+LLVM-IR. If more than on file should be optimized the files can be combined into
+a single file with llvm-link.
+
+<pre class="code">clang -S -emit-llvm matmul.c -o matmul.s</pre>
+</li>
+
+
+<li><h4>Load Polly automatically when calling the 'opt' tool</h4>
+
+Polly is not built into opt or bugpoint, but it is a shared library that needs
+to be loaded into these tools explicitally. The Polly library is called
+LVMPolly.so. For a cmake build it is available in the build/lib/ directory,
+autoconf creates the same file in
+build/tools/polly/{Release+Asserts|Asserts|Debug}/lib. For convenience we create
+an alias that automatically loads Polly if 'opt' is called.
+<pre class="code">
+export PATH_TO_POLLY_LIB="~/polly/build/lib/"
+alias opt="opt -load ${PATH_TO_POLLY_LIB}/LLVMPolly.so"</pre>
+</li>
+
+<li><h4>Prepare the LLVM-IR for Polly</h4>
+
+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'.
+<pre class="code">opt -S -polly-canonicalize matmul.s &gt; matmul.preopt.ll</pre></li>
+
+<li><h4>Show the SCoPs detected by Polly (optional)</h4>
+
+To understand if Polly was able to detect SCoPs, we print the
+structure of the detected SCoPs. In our example two SCoPs were detected. One in
+'init_array' the other in 'main'.
+
+<pre class="code">opt -basicaa -polly-ast -analyze -q matmul.preopt.ll</pre>
+
+<pre>
+init_array():
+for (c2=0;c2&lt;=1023;c2++) {
+  for (c4=0;c4&lt;=1023;c4++) {
+    Stmt_5(c2,c4);
+  }
+}
+
+main():
+for (c2=0;c2&lt;=1023;c2++) {
+  for (c4=0;c4&lt;=1023;c4++) {
+    Stmt_4(c2,c4);
+    for (c6=0;c6&lt;=1023;c6++) {
+      Stmt_6(c2,c4,c6);
+    }
+  }
+}
+</pre>
+</li>
+<li><h4>Highlight the detected SCoPs in the CFGs of the program (requires graphviz/dotty)</h4>
+
+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.
+
+<pre class="code">opt -basicaa -view-scops -disable-output matmul.preopt.ll
+opt -basicaa -view-scops-only -disable-output matmul.preopt.ll</pre>
+The output for the different functions<br />
+view-scops:
+<a href="experiments/matmul/scops.main.dot.png">main</a>,
+<a href="experiments/matmul/scops.init_array.dot.png">init_array</a>,
+<a href="experiments/matmul/scops.print_array.dot.png">print_array</a><br />
+view-scops-only:
+<a href="experiments/matmul/scopsonly.main.dot.png">main</a>,
+<a href="experiments/matmul/scopsonly.init_array.dot.png">init_array</a>,
+<a href="experiments/matmul/scopsonly.print_array.dot.png">print_array</a>
+</li>
+
+<li><h4>View the polyhedral representation of the SCoPs</h4>
+<pre class="code">opt -basicaa -polly-scops -analyze matmul.preopt.ll</pre>
+<pre>
+[...]
+Printing analysis 'Polly - Create polyhedral description of Scops' for region:
+'for.cond =&gt; for.end19' in function 'init_array':
+   Context:
+   { [] }
+   Statements {
+   	Stmt_5
+           Domain&nbsp;:=
+               { Stmt_5[i0, i1]&nbsp;: i0 &gt;= 0 and i0 &lt;= 1023 and i1 &gt;= 0 and i1 &lt;= 1023 };
+           Schedule&nbsp;:=
+               { Stmt_5[i0, i1] -&gt; schedule[0, i0, 0, i1, 0] };
+           WriteAccess&nbsp;:=
+               { Stmt_5[i0, i1] -&gt; MemRef_A[1037i0 + i1] };
+           WriteAccess&nbsp;:=
+               { Stmt_5[i0, i1] -&gt; MemRef_B[1047i0 + i1] };
+   	FinalRead
+           Domain&nbsp;:=
+               { FinalRead[0] };
+           Schedule&nbsp;:=
+               { FinalRead[i0] -&gt; schedule[200000000, o1, o2, o3, o4] };
+           ReadAccess&nbsp;:=
+               { FinalRead[i0] -&gt; MemRef_A[o0] };
+           ReadAccess&nbsp;:=
+               { FinalRead[i0] -&gt; MemRef_B[o0] };
+   }
+[...]
+Printing analysis 'Polly - Create polyhedral description of Scops' for region:
+'for.cond =&gt; for.end30' in function 'main':
+   Context:
+   { [] }
+   Statements {
+   	Stmt_4
+           Domain&nbsp;:=
+               { Stmt_4[i0, i1]&nbsp;: i0 &gt;= 0 and i0 &lt;= 1023 and i1 &gt;= 0 and i1 &lt;= 1023 };
+           Schedule&nbsp;:=
+               { Stmt_4[i0, i1] -&gt; schedule[0, i0, 0, i1, 0, 0, 0] };
+           WriteAccess&nbsp;:=
+               { Stmt_4[i0, i1] -&gt; MemRef_C[1067i0 + i1] };
+   	Stmt_6
+           Domain&nbsp;:=
+               { Stmt_6[i0, i1, i2]&nbsp;: i0 &gt;= 0 and i0 &lt;= 1023 and i1 &gt;= 0 and i1 &lt;= 1023 and i2 &gt;= 0 and i2 &lt;= 1023 };
+           Schedule&nbsp;:=
+               { Stmt_6[i0, i1, i2] -&gt; schedule[0, i0, 0, i1, 1, i2, 0] };
+           ReadAccess&nbsp;:=
+               { Stmt_6[i0, i1, i2] -&gt; MemRef_C[1067i0 + i1] };
+           ReadAccess&nbsp;:=
+               { Stmt_6[i0, i1, i2] -&gt; MemRef_A[1037i0 + i2] };
+           ReadAccess&nbsp;:=
+               { Stmt_6[i0, i1, i2] -&gt; MemRef_B[i1 + 1047i2] };
+           WriteAccess&nbsp;:=
+               { Stmt_6[i0, i1, i2] -&gt; MemRef_C[1067i0 + i1] };
+   	FinalRead
+           Domain&nbsp;:=
+               { FinalRead[0] };
+           Schedule&nbsp;:=
+               { FinalRead[i0] -&gt; schedule[200000000, o1, o2, o3, o4, o5, o6] };
+           ReadAccess&nbsp;:=
+               { FinalRead[i0] -&gt; MemRef_C[o0] };
+           ReadAccess&nbsp;:=
+               { FinalRead[i0] -&gt; MemRef_A[o0] };
+           ReadAccess&nbsp;:=
+               { FinalRead[i0] -&gt; MemRef_B[o0] };
+   }
+[...]
+</pre>
+</li>
+
+<li><h4>Show the dependences for the SCoPs</h4>
+<pre class="code">opt -basicaa -polly-dependences -analyze matmul.preopt.ll</pre>
+<pre>Printing analysis 'Polly - Calculate dependences for SCoP' for region:
+'for.cond =&gt; for.end19' in function 'init_array':
+   Must dependences:
+       {  }
+   May dependences:
+       {  }
+   Must no source:
+       {  }
+   May no source:
+       {  }
+Printing analysis 'Polly - Calculate dependences for SCoP' for region:
+'for.cond =&gt; for.end30' in function 'main':
+   Must dependences:
+       {  Stmt_4[i0, i1] -&gt; Stmt_6[i0, i1, 0]&nbsp;:
+              i0 &gt;= 0 and i0 &lt;= 1023 and i1 &gt;= 0 and i1 &lt;= 1023;
+          Stmt_6[i0, i1, i2] -&gt; Stmt_6[i0, i1, 1 + i2]&nbsp;:
+              i0 &gt;= 0 and i0 &lt;= 1023 and i1 &gt;= 0 and i1 &lt;= 1023 and i2 &gt;= 0 and i2 &lt;= 1022;
+          Stmt_6[i0, i1, 1023] -&gt; FinalRead[0]&nbsp;:
+              i1 &lt;= 1091540 - 1067i0 and i1 &gt;= -1067i0 and i1 &gt;= 0 and i1 &lt;= 1023;
+          Stmt_6[1023, i1, 1023] -&gt; FinalRead[0]&nbsp;:
+              i1 &gt;= 0 and i1 &lt;= 1023
+       }
+   May dependences:
+       {  }
+   Must no source:
+       {  Stmt_6[i0, i1, i2] -&gt; MemRef_A[1037i0 + i2]&nbsp;:
+              i0 &gt;= 0 and i0 &lt;= 1023 and i1 &gt;= 0 and i1 &lt;= 1023 and i2 &gt;= 0 and i2 &lt;= 1023;
+          Stmt_6[i0, i1, i2] -&gt; MemRef_B[i1 + 1047i2]&nbsp;:
+              i0 &gt;= 0 and i0 &lt;= 1023 and i1 &gt;= 0 and i1 &lt;= 1023 and i2 &gt;= 0 and i2 &lt;= 1023;
+          FinalRead[0] -&gt; MemRef_A[o0];
+          FinalRead[0] -&gt; MemRef_B[o0]
+          FinalRead[0] -&gt; MemRef_C[o0]&nbsp;:
+              o0 &gt;= 1092565 or (exists (e0 = [(o0)/1067]: o0 &lt;= 1091540 and o0 &gt;= 0
+              and 1067e0 &lt;= -1024 + o0 and 1067e0 &gt;= -1066 + o0)) or o0 &lt;= -1;
+       }
+   May no source:
+       {  }
+</pre></li>
+
+<li><h4>Export jscop files</h4>
+
+Polly can export the polyhedral representation in so called jscop files. Jscop
+files contain the polyhedral representation stored in a JSON file.
+<pre class="code">opt -basicaa -polly-export-jscop matmul.preopt.ll</pre>
+<pre>Writing SCoP 'for.cond =&gt; for.end19' in function 'init_array' to './init_array___%for.cond---%for.end19.jscop'.
+Writing SCoP 'for.cond =&gt; for.end30' in function 'main' to './main___%for.cond---%for.end30.jscop'.
+</pre></li>
+
+<li><h4>Import the changed jscop files and print the updated SCoP structure
+(optional)</h4>
+<p>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.</p>
+<p> We apply three different transformations on the SCoP in the main function.
+The jscop files describing these transformations are hand written (and available
+in <em>www/experiments/matmul</em>).
+
+<h5>No Polly</h5>
+
+<p>As a baseline we do not call any Polly code generation, but only apply the
+normal -O3 optimizations.</p>
+
+<pre class="code">
+opt matmul.preopt.ll -basicaa \
+    -polly-import-jscop \
+    -polly-ast -analyze
+</pre>
+<pre>
+[...]
+main():
+for (c2=0;c2&ltg;=1535;c2++) {
+  for (c4=0;c4&ltg;=1535;c4++) {
+    Stmt_4(c2,c4);
+    for (c6=0;c6&ltg;=1535;c6++) {
+      Stmt_6(c2,c4,c6);
+    }
+  }
+}
+[...]
+</pre>
+<h5>Interchange (and Fission to allow the interchange)</h5>
+<p>We split the loops and can now apply an interchange of the loop dimensions that
+enumerate Stmt_6.</p>
+<pre class="code">
+opt matmul.preopt.ll -basicaa \
+    -polly-import-jscop -polly-import-jscop-postfix=interchanged \
+    -polly-ast -analyze
+</pre>
+<pre>
+[...]
+Reading JScop 'for.cond =&gt; for.end30' in function 'main' from './main___%for.cond---%for.end30.jscop.interchanged+tiled'.
+[...]
+main():
+for (c2=0;c2&lt;=1535;c2++) {
+  for (c4=0;c4&lt;=1535;c4++) {
+    Stmt_4(c2,c4);
+  }
+}
+for (c2=0;c2&lt;=1535;c2++) {
+  for (c4=0;c4&lt;=1535;c4++) {
+    for (c6=0;c6&lt;=1535;c6++) {
+      Stmt_6(c2,c6,c4);
+    }
+  }
+}
+[...]
+</pre>
+<h5>Interchange + Tiling</h5>
+<p>In addition to the interchange we tile now the second loop nest.</p>
+
+<pre class="code">
+opt matmul.preopt.ll -basicaa \
+    -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled \
+    -polly-ast -analyze
+</pre>
+<pre>
+[...]
+Reading JScop 'for.cond =&gt; for.end30' in function 'main' from './main___%for.cond---%for.end30.jscop.interchanged+tiled'.
+[...]
+main():
+for (c2=0;c2&lt;=1535;c2++) {
+  for (c4=0;c4&lt;=1535;c4++) {
+    Stmt_4(c2,c4);
+  }
+}
+for (c2=0;c2&lt;=1535;c2+=64) {
+  for (c3=0;c3&lt;=1535;c3+=64) {
+    for (c4=0;c4&lt;=1535;c4+=64) {
+      for (c5=c2;c5&lt;=c2+63;c5++) {
+        for (c6=c4;c6&lt;=c4+63;c6++) {
+          for (c7=c3;c7&lt;=c3+63;c7++) {
+            Stmt_6(c5,c7,c6);
+          }
+        }
+      }
+    }
+  }
+}
+[...]
+</pre>
+<h5>Interchange + Tiling + Strip-mining to prepare vectorization</h5>
+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.
+<pre class="code">
+opt matmul.preopt.ll -basicaa \
+    -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled+vector \
+    -polly-ast -analyze </pre>
+
+<pre>
+[...]
+Reading JScop 'for.cond =&gt; for.end30' in function 'main' from './main___%for.cond---%for.end30.jscop.interchanged+tiled+vector'.
+[...]
+main():
+for (c2=0;c2&lt;=1535;c2++) {
+  for (c4=0;c4&lt;=1535;c4++) {
+    Stmt_4(c2,c4);
+  }
+}
+for (c2=0;c2&lt;=1535;c2+=64) {
+  for (c3=0;c3&lt;=1535;c3+=64) {
+    for (c4=0;c4&lt;=1535;c4+=64) {
+      for (c5=c2;c5&lt;=c2+63;c5++) {
+        for (c6=c4;c6&lt;=c4+63;c6++) {
+          for (c7=c3;c7&lt;=c3+63;c7+=4) {
+            for (c8=c7;c8&lt;=c7+3;c8++) {
+              Stmt_6(c5,c8,c6);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+[...]
+</pre>
+
+</li>
+
+<li><h4>Codegenerate the SCoPs</h4>
+<p>
+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.</p>
+<pre class="code">opt matmul.preopt.ll | opt -O3 &gt; matmul.normalopt.ll</pre>
+<pre class="code">
+opt -basicaa \
+    -polly-import-jscop -polly-import-jscop-postfix=interchanged \
+    -polly-codegen matmul.preopt.ll \
+   | opt -O3 &gt; matmul.polly.interchanged.ll</pre>
+<pre>
+Reading JScop 'for.cond =&gt; for.end19' in function 'init_array' from
+    './init_array___%for.cond---%for.end19.jscop.interchanged'.
+File could not be read: No such file or directory
+Reading JScop 'for.cond =&gt; for.end30' in function 'main' from
+    './main___%for.cond---%for.end30.jscop.interchanged'.
+</pre>
+<pre class="code">
+opt -basicaa \
+    -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled \
+    -polly-codegen matmul.preopt.ll \
+   | opt -O3 &gt; matmul.polly.interchanged+tiled.ll</pre>
+<pre>
+Reading JScop 'for.cond =&gt; for.end19' in function 'init_array' from
+    './init_array___%for.cond---%for.end19.jscop.interchanged+tiled'.
+File could not be read: No such file or directory
+Reading JScop 'for.cond =&gt; for.end30' in function 'main' from
+    './main___%for.cond---%for.end30.jscop.interchanged+tiled'.
+</pre>
+<pre class="code">
+opt -basicaa \
+    -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled+vector \
+    -polly-codegen -polly-vectorizer=polly matmul.preopt.ll \
+   | opt -O3 &gt; matmul.polly.interchanged+tiled+vector.ll</pre>
+<pre>
+Reading JScop 'for.cond =&gt; for.end19' in function 'init_array' from
+    './init_array___%for.cond---%for.end19.jscop.interchanged+tiled+vector'.
+File could not be read: No such file or directory
+Reading JScop 'for.cond =&gt; for.end30' in function 'main' from
+    './main___%for.cond---%for.end30.jscop.interchanged+tiled+vector'.
+</pre>
+<pre class="code">
+opt -basicaa \
+    -polly-import-jscop -polly-import-jscop-postfix=interchanged+tiled+vector \
+    -polly-codegen -polly-vectorizer=polly -polly-parallel matmul.preopt.ll \
+  | opt -O3 &gt; matmul.polly.interchanged+tiled+openmp.ll</pre>
+<pre>
+Reading JScop 'for.cond =&gt; for.end19' in function 'init_array' from
+    './init_array___%for.cond---%for.end19.jscop.interchanged+tiled+vector'.
+File could not be read: No such file or directory
+Reading JScop 'for.cond =&gt; for.end30' in function 'main' from
+    './main___%for.cond---%for.end30.jscop.interchanged+tiled+vector'.
+</pre>
+
+<li><h4>Create the executables</h4>
+
+Create one executable optimized with plain -O3 as well as a set of executables
+optimized in different ways with Polly. One changes only the loop structure, the
+other adds tiling, the next adds vectorization and finally we use OpenMP
+parallelism.
+<pre class="code">
+llc matmul.normalopt.ll -o matmul.normalopt.s &amp;&amp; \
+    gcc matmul.normalopt.s -o matmul.normalopt.exe
+llc matmul.polly.interchanged.ll -o matmul.polly.interchanged.s &amp;&amp; \
+    gcc matmul.polly.interchanged.s -o matmul.polly.interchanged.exe
+llc matmul.polly.interchanged+tiled.ll -o matmul.polly.interchanged+tiled.s &amp;&amp; \
+    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 &amp;&amp; \
+    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 &amp;&amp; \
+    gcc -lgomp matmul.polly.interchanged+tiled+vector+openmp.s -o matmul.polly.interchanged+tiled+vector+openmp.exe </pre>
+
+<li><h4>Compare the runtime of the executables</h4>
+
+By comparing the runtimes of the different code snippets we see that a simple
+loop interchange gives here the largest performance boost. However by adding
+vectorization and by using OpenMP we can further improve the performance
+significantly.
+<pre class="code">time ./matmul.normalopt.exe</pre>
+<pre>42.68 real, 42.55 user, 0.00 sys</pre>
+<pre class="code">time ./matmul.polly.interchanged.exe</pre>
+<pre>04.33 real, 4.30 user, 0.01 sys</pre>
+<pre class="code">time ./matmul.polly.interchanged+tiled.exe</pre>
+<pre>04.11 real, 4.10 user, 0.00 sys</pre>
+<pre class="code">time ./matmul.polly.interchanged+tiled+vector.exe</pre>
+<pre>01.39 real, 1.36 user, 0.01 sys</pre>
+<pre class="code">time ./matmul.polly.interchanged+tiled+vector+openmp.exe</pre>
+<pre>00.66 real, 2.58 user, 0.02 sys</pre>
+</li>
+</ol>
+
+</div>
+</div>
+</body>
+</html>
diff --git a/final/www/examples.html b/final/www/examples.html
new file mode 100644
index 0000000..c8ceb65
--- /dev/null
+++ b/final/www/examples.html
@@ -0,0 +1,22 @@
+<!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 - Examples</title>
+  <link type="text/css" rel="stylesheet" href="menu.css">
+  <link type="text/css" rel="stylesheet" href="content.css">
+  <meta http-equiv="REFRESH"
+  content="0;url=documentation.html"></HEAD>
+</head>
+<body>
+<!--#include virtual="menu.html.incl"-->
+<div id="content">
+<!--=====================================================================-->
+<h1>Polly: Examples</h1>
+<!--=====================================================================-->
+
+</div>
+</body>
+</html>
diff --git a/final/www/experiments/matmul/init_array___%for.cond---%for.end19.jscop b/final/www/experiments/matmul/init_array___%for.cond---%for.end19.jscop
new file mode 100644
index 0000000..8caaab4
--- /dev/null
+++ b/final/www/experiments/matmul/init_array___%for.cond---%for.end19.jscop
@@ -0,0 +1,21 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end19",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_A[1536i0 + i1] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_B[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= 1535 and i1 >= 0 and i1 <= 1535 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> schedule[0, i0, 0, i1, 0] }"
+      }
+   ]
+}
diff --git a/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop
new file mode 100644
index 0000000..e7c5250
--- /dev/null
+++ b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop
@@ -0,0 +1,40 @@
+{
+   "context" : "{  :  }",
+   "name" : "for.cond => for.end30",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body3[i0, i1] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body3[i0, i1] : i0 >= 0 and i0 <= 1535 and i1 >= 0 and i1 <= 1535 }",
+         "name" : "Stmt_for_body3",
+         "schedule" : "{ Stmt_for_body3[i0, i1] -> schedule[0, i0, 0, i1, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_A[1536i0 + i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_B[i1 + 1536i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_for_body8[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_for_body8[i0, i1, i2] : i0 >= 0 and i0 <= 1535 and i1 >= 0 and i1 <= 1535 and i2 >= 0 and i2 <= 1535 }",
+         "name" : "Stmt_for_body8",
+         "schedule" : "{ Stmt_for_body8[i0, i1, i2] -> schedule[0, i0, 0, i1, 1, i2, 0] }"
+      }
+   ]
+}
diff --git a/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged
new file mode 100644
index 0000000..a94dcc9
--- /dev/null
+++ b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged
@@ -0,0 +1,40 @@
+{
+   "context" : "{ [] }",
+   "name" : "%1 => %17",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_4[i0, i1] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_4[i0, i1] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_4",
+         "schedule" : "{ Stmt_4[i0, i1] -> schedule[0, i0, 0, i1, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_A[1536i0 + i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_B[i1 + 1536i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_6[i0, i1, i2] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 and i2 >= 0 and i2 <= 1023 }",
+         "name" : "Stmt_6",
+         "schedule" : "{ Stmt_6[i0, i1, i2] -> schedule[1, i0, 0, i2, 0, i1, 0] }"
+      }
+   ]
+}
diff --git a/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged+tiled b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged+tiled
new file mode 100644
index 0000000..4bfd792
--- /dev/null
+++ b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged+tiled
@@ -0,0 +1,40 @@
+{
+   "context" : "{ [] }",
+   "name" : "%1 => %17",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_4[i0, i1] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_4[i0, i1] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_4",
+         "schedule" : "{ Stmt_4[i0, i1] -> schedule[0, i0, 0, i1, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_A[1536i0 + i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_B[i1 + 1536i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_6[i0, i1, i2] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 and i2 >= 0 and i2 <= 1023 }",
+         "name" : "Stmt_6",
+         "schedule" : "{ Stmt_6[i0, i1, i2] -> schedule[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/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged+tiled+vector b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged+tiled+vector
new file mode 100644
index 0000000..f5d0b84
--- /dev/null
+++ b/final/www/experiments/matmul/main___%for.cond---%for.end30.jscop.interchanged+tiled+vector
@@ -0,0 +1,40 @@
+{
+   "context" : "{ [] }",
+   "name" : "%1 => %17",
+   "statements" : [
+      {
+         "accesses" : [
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_4[i0, i1] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_4[i0, i1] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 }",
+         "name" : "Stmt_4",
+         "schedule" : "{ Stmt_4[i0, i1] -> schedule[0, i0, 0, i1, 0, 0, 0, 0] }"
+      },
+      {
+         "accesses" : [
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_A[1536i0 + i2] }"
+            },
+            {
+               "kind" : "read",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_B[i1 + 1536i2] }"
+            },
+            {
+               "kind" : "write",
+               "relation" : "{ Stmt_6[i0, i1, i2] -> MemRef_C[1536i0 + i1] }"
+            }
+         ],
+         "domain" : "{ Stmt_6[i0, i1, i2] : i0 >= 0 and i0 <= 1023 and i1 >= 0 and i1 <= 1023 and i2 >= 0 and i2 <= 1023 }",
+         "name" : "Stmt_6",
+         "schedule" : "{ Stmt_6[i0, i1, i2] -> schedule[1, o0, o1, o2, i0, i2, ii1, 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 and ii1 % 4 = 0 and ii1 <= i1 < ii1 + 4}"
+      }
+   ]
+}
diff --git a/final/www/experiments/matmul/matmul.c b/final/www/experiments/matmul/matmul.c
new file mode 100644
index 0000000..edb2455
--- /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..3931716
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.preopt.ll
@@ -0,0 +1,186 @@
+; ModuleID = 'matmul.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"
+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*
+@.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
+
+; Function Attrs: nounwind uwtable
+define void @init_array() #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc17, %entry
+  %0 = phi i64 [ %indvar.next2, %for.inc17 ], [ 0, %entry ]
+  %exitcond3 = icmp ne i64 %0, 1536
+  br i1 %exitcond3, label %for.body, label %for.end19
+
+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 ]
+  %arrayidx6 = getelementptr [1536 x [1536 x float]]* @A, i64 0, i64 %0, i64 %indvar
+  %arrayidx16 = getelementptr [1536 x [1536 x float]]* @B, i64 0, i64 %0, i64 %indvar
+  %1 = mul i64 %0, %indvar
+  %mul = trunc i64 %1 to i32
+  %exitcond = icmp ne i64 %indvar, 1536
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %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
+  store float %conv4, float* %arrayidx6, align 4
+  %rem8 = srem i32 %mul, 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
+  store float %conv12, float* %arrayidx16, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  br label %for.inc17
+
+for.inc17:                                        ; preds = %for.end
+  %indvar.next2 = add i64 %0, 1
+  br label %for.cond
+
+for.end19:                                        ; preds = %for.cond
+  ret void
+}
+
+; Function Attrs: nounwind uwtable
+define void @print_array() #0 {
+entry:
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %indvar1 = phi i64 [ %indvar.next2, %for.inc10 ], [ 0, %entry ]
+  %exitcond3 = icmp ne i64 %indvar1, 1536
+  br i1 %exitcond3, label %for.body, label %for.end12
+
+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 ]
+  %arrayidx5 = getelementptr [1536 x [1536 x float]]* @C, i64 0, i64 %indvar1, i64 %indvar
+  %j.0 = trunc i64 %indvar to i32
+  %exitcond = icmp ne i64 %indvar, 1536
+  br i1 %exitcond, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %0 = load %struct._IO_FILE** @stdout, align 8
+  %1 = load 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]* @.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** @stdout, align 8
+  %call8 = call i32 (%struct._IO_FILE*, i8*, ...)* @fprintf(%struct._IO_FILE* %2, i8* getelementptr inbounds ([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
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %3 = load %struct._IO_FILE** @stdout, align 8
+  %call9 = call i32 (%struct._IO_FILE*, i8*, ...)* @fprintf(%struct._IO_FILE* %3, i8* getelementptr inbounds ([2 x i8]* @.str1, i32 0, i32 0))
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %indvar.next2 = add i64 %indvar1, 1
+  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:
+  call void @init_array()
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc28, %entry
+  %indvar3 = phi i64 [ %indvar.next4, %for.inc28 ], [ 0, %entry ]
+  %exitcond6 = icmp ne i64 %indvar3, 1536
+  br i1 %exitcond6, label %for.body, label %for.end30
+
+for.body:                                         ; preds = %for.cond
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc25, %for.body
+  %indvar1 = phi i64 [ %indvar.next2, %for.inc25 ], [ 0, %for.body ]
+  %arrayidx5 = getelementptr [1536 x [1536 x float]]* @C, i64 0, i64 %indvar3, i64 %indvar1
+  %exitcond5 = icmp ne i64 %indvar1, 1536
+  br i1 %exitcond5, label %for.body3, label %for.end27
+
+for.body3:                                        ; preds = %for.cond1
+  store float 0.000000e+00, float* %arrayidx5, align 4
+  br label %for.cond6
+
+for.cond6:                                        ; preds = %for.inc, %for.body3
+  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %for.body3 ]
+  %arrayidx16 = getelementptr [1536 x [1536 x float]]* @A, i64 0, i64 %indvar3, i64 %indvar
+  %arrayidx20 = getelementptr [1536 x [1536 x float]]* @B, i64 0, i64 %indvar, i64 %indvar1
+  %exitcond = icmp ne i64 %indvar, 1536
+  br i1 %exitcond, label %for.body8, label %for.end
+
+for.body8:                                        ; preds = %for.cond6
+  %0 = load float* %arrayidx5, align 4
+  %1 = load float* %arrayidx16, align 4
+  %2 = load float* %arrayidx20, align 4
+  %mul = fmul float %1, %2
+  %add = fadd float %0, %mul
+  store float %add, float* %arrayidx5, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body8
+  %indvar.next = add i64 %indvar, 1
+  br label %for.cond6
+
+for.end:                                          ; preds = %for.cond6
+  br label %for.inc25
+
+for.inc25:                                        ; preds = %for.end
+  %indvar.next2 = add i64 %indvar1, 1
+  br label %for.cond1
+
+for.end27:                                        ; preds = %for.cond1
+  br label %for.inc28
+
+for.inc28:                                        ; preds = %for.end27
+  %indvar.next4 = add i64 %indvar3, 1
+  br label %for.cond
+
+for.end30:                                        ; preds = %for.cond
+  ret i32 0
+}
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
diff --git a/final/www/experiments/matmul/matmul.s b/final/www/experiments/matmul/matmul.s
new file mode 100644
index 0000000..22ea57b
--- /dev/null
+++ b/final/www/experiments/matmul/matmul.s
@@ -0,0 +1,264 @@
+; ModuleID = 'matmul.c'
+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"
+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*
+@.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
+
+; 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* %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* %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* %i, align 4
+  %3 = load 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* %j, align 4
+  %idxprom = sext i32 %4 to i64
+  %5 = load i32* %i, align 4
+  %idxprom5 = sext i32 %5 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]]* @A, i32 0, i64 %idxprom5
+  %arrayidx6 = getelementptr inbounds [1536 x float]* %arrayidx, i32 0, i64 %idxprom
+  store float %conv4, float* %arrayidx6, align 4
+  %6 = load i32* %i, align 4
+  %7 = load 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* %j, align 4
+  %idxprom13 = sext i32 %8 to i64
+  %9 = load i32* %i, align 4
+  %idxprom14 = sext i32 %9 to i64
+  %arrayidx15 = getelementptr inbounds [1536 x [1536 x float]]* @B, i32 0, i64 %idxprom14
+  %arrayidx16 = getelementptr inbounds [1536 x float]* %arrayidx15, i32 0, i64 %idxprom13
+  store float %conv12, float* %arrayidx16, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %10 = load 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* %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* %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* %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** @stdout, align 8
+  %3 = load i32* %j, align 4
+  %idxprom = sext i32 %3 to i64
+  %4 = load i32* %i, align 4
+  %idxprom4 = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom4
+  %arrayidx5 = getelementptr inbounds [1536 x float]* %arrayidx, i32 0, i64 %idxprom
+  %5 = load 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]* @.str, i32 0, i32 0), double %conv)
+  %6 = load 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** @stdout, align 8
+  %call8 = call i32 (%struct._IO_FILE*, i8*, ...)* @fprintf(%struct._IO_FILE* %7, i8* getelementptr inbounds ([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
+  %8 = load 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** @stdout, align 8
+  %call9 = call i32 (%struct._IO_FILE*, i8*, ...)* @fprintf(%struct._IO_FILE* %9, i8* getelementptr inbounds ([2 x i8]* @.str1, i32 0, i32 0))
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %10 = load 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
+  call void @init_array()
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc28, %entry
+  %0 = load 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* %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* %j, align 4
+  %idxprom = sext i32 %2 to i64
+  %3 = load i32* %i, align 4
+  %idxprom4 = sext i32 %3 to i64
+  %arrayidx = getelementptr inbounds [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom4
+  %arrayidx5 = getelementptr inbounds [1536 x float]* %arrayidx, i32 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* %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* %j, align 4
+  %idxprom9 = sext i32 %5 to i64
+  %6 = load i32* %i, align 4
+  %idxprom10 = sext i32 %6 to i64
+  %arrayidx11 = getelementptr inbounds [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom10
+  %arrayidx12 = getelementptr inbounds [1536 x float]* %arrayidx11, i32 0, i64 %idxprom9
+  %7 = load float* %arrayidx12, align 4
+  %8 = load i32* %k, align 4
+  %idxprom13 = sext i32 %8 to i64
+  %9 = load i32* %i, align 4
+  %idxprom14 = sext i32 %9 to i64
+  %arrayidx15 = getelementptr inbounds [1536 x [1536 x float]]* @A, i32 0, i64 %idxprom14
+  %arrayidx16 = getelementptr inbounds [1536 x float]* %arrayidx15, i32 0, i64 %idxprom13
+  %10 = load float* %arrayidx16, align 4
+  %11 = load i32* %j, align 4
+  %idxprom17 = sext i32 %11 to i64
+  %12 = load i32* %k, align 4
+  %idxprom18 = sext i32 %12 to i64
+  %arrayidx19 = getelementptr inbounds [1536 x [1536 x float]]* @B, i32 0, i64 %idxprom18
+  %arrayidx20 = getelementptr inbounds [1536 x float]* %arrayidx19, i32 0, i64 %idxprom17
+  %13 = load float* %arrayidx20, align 4
+  %mul = fmul float %10, %13
+  %add = fadd float %7, %mul
+  %14 = load i32* %j, align 4
+  %idxprom21 = sext i32 %14 to i64
+  %15 = load i32* %i, align 4
+  %idxprom22 = sext i32 %15 to i64
+  %arrayidx23 = getelementptr inbounds [1536 x [1536 x float]]* @C, i32 0, i64 %idxprom22
+  %arrayidx24 = getelementptr inbounds [1536 x float]* %arrayidx23, i32 0, i64 %idxprom21
+  store float %add, float* %arrayidx24, align 4
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body8
+  %16 = load 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* %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* %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 "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="false" "use-soft-float"="false" }
diff --git a/final/www/experiments/matmul/runall.sh b/final/www/experiments/matmul/runall.sh
new file mode 100755
index 0000000..81b921e
--- /dev/null
+++ b/final/www/experiments/matmul/runall.sh
@@ -0,0 +1,94 @@
+#!/bin/sh -a
+
+echo "--> 1. Create LLVM-IR from C"
+clang -S -emit-llvm matmul.c -o matmul.s
+
+echo "--> 2. Load Polly automatically when calling the 'opt' tool"
+export PATH_TO_POLLY_LIB="~/polly/build/lib/"
+alias opt="opt -load ${PATH_TO_POLLY_LIB}/LLVMPolly.so"
+
+echo "--> 3. Prepare the LLVM-IR for Polly"
+opt -S -polly-canonicalize matmul.s > matmul.preopt.ll
+
+echo "--> 4. Show the SCoPs detected by Polly"
+opt -basicaa -polly-ast -analyze -q matmul.preopt.ll
+
+echo "--> 5.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 "--> 5.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 "--> 5.3 Create .png files from the .dot files"
+for i in `ls *.dot`; do dot -Tpng $i > $i.png; done
+
+echo "--> 6. View the polyhedral representation of the SCoPs"
+opt -basicaa -polly-scops -analyze matmul.preopt.ll
+
+echo "--> 7. Show the dependences for the SCoPs"
+opt -basicaa -polly-dependences -analyze matmul.preopt.ll
+
+echo "--> 8. Export jscop files"
+opt -basicaa -polly-export-jscop matmul.preopt.ll
+
+echo "--> 9. Import the updated jscop files and print the new SCoPs. (optional)"
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll \
+    -polly-import-jscop-postfix=interchanged
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll \
+    -polly-import-jscop-postfix=interchanged+tiled
+opt -basicaa -polly-import-jscop -polly-ast -analyze matmul.preopt.ll \
+    -polly-import-jscop-postfix=interchanged+tiled+vector
+
+echo "--> 10. Codegenerate the SCoPs"
+opt -basicaa -polly-import-jscop -polly-import-jscop-postfix=interchanged \
+    -polly-codegen \
+    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 | opt -O3 > matmul.polly.interchanged+tiled.ll
+opt -basicaa -polly-import-jscop \
+    -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-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 "--> 11. 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 "--> 12. 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..10a0add
--- /dev/null
+++ b/final/www/experiments/matmul/scops.init_array.dot
@@ -0,0 +1,47 @@
+digraph "Scop Graph for 'init_array' function" {
+	label="Scop Graph for 'init_array' function";
+
+	Node0x17d4370 [shape=record,label="{entry:\l  br label %for.cond\l}"];
+	Node0x17d4370 -> Node0x17da5d0;
+	Node0x17da5d0 [shape=record,label="{for.cond:                                         \l  %0 = phi i64 [ %indvar.next2, %for.inc17 ], [ 0, %entry ]\l  %exitcond3 = icmp ne i64 %0, 1536\l  br i1 %exitcond3, label %for.body, label %for.end19\l}"];
+	Node0x17da5d0 -> Node0x17da5f0;
+	Node0x17da5d0 -> Node0x17da650;
+	Node0x17da5f0 [shape=record,label="{for.body:                                         \l  br label %for.cond1\l}"];
+	Node0x17da5f0 -> Node0x17da900;
+	Node0x17da900 [shape=record,label="{for.cond1:                                        \l  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %for.body ]\l  %arrayidx6 = getelementptr [1536 x [1536 x float]]* @A, i64 0, i64 %0, i64 %indvar\l  %arrayidx16 = getelementptr [1536 x [1536 x float]]* @B, i64 0, i64 %0, i64 %indvar\l  %1 = mul i64 %0, %indvar\l  %mul = trunc i64 %1 to i32\l  %exitcond = icmp ne i64 %indvar, 1536\l  br i1 %exitcond, label %for.body3, label %for.end\l}"];
+	Node0x17da900 -> Node0x17da670;
+	Node0x17da900 -> Node0x17da9a0;
+	Node0x17da670 [shape=record,label="{for.body3:                                        \l  %rem = srem i32 %mul, 1024\l  %add = add nsw i32 1, %rem\l  %conv = sitofp i32 %add to double\l  %div = fdiv double %conv, 2.000000e+00\l  %conv4 = fptrunc double %div to float\l  store float %conv4, float* %arrayidx6, align 4\l  %rem8 = srem i32 %mul, 1024\l  %add9 = add nsw i32 1, %rem8\l  %conv10 = sitofp i32 %add9 to double\l  %div11 = fdiv double %conv10, 2.000000e+00\l  %conv12 = fptrunc double %div11 to float\l  store float %conv12, float* %arrayidx16, align 4\l  br label %for.inc\l}"];
+	Node0x17da670 -> Node0x17da8e0;
+	Node0x17da8e0 [shape=record,label="{for.inc:                                          \l  %indvar.next = add i64 %indvar, 1\l  br label %for.cond1\l}"];
+	Node0x17da8e0 -> Node0x17da900[constraint=false];
+	Node0x17da9a0 [shape=record,label="{for.end:                                          \l  br label %for.inc17\l}"];
+	Node0x17da9a0 -> Node0x17d9e70;
+	Node0x17d9e70 [shape=record,label="{for.inc17:                                        \l  %indvar.next2 = add i64 %0, 1\l  br label %for.cond\l}"];
+	Node0x17d9e70 -> Node0x17da5d0[constraint=false];
+	Node0x17da650 [shape=record,label="{for.end19:                                        \l  ret void\l}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x17d3a30 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x17d4ec0 {
+            label = "";
+            style = filled;
+            color = 3            subgraph cluster_0x17d4180 {
+              label = "";
+              style = solid;
+              color = 5
+              Node0x17da900;
+              Node0x17da670;
+              Node0x17da8e0;
+            }
+            Node0x17da5d0;
+            Node0x17da5f0;
+            Node0x17da9a0;
+            Node0x17d9e70;
+          }
+          Node0x17d4370;
+          Node0x17da650;
+        }
+}
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..2a1fc50
--- /dev/null
+++ b/final/www/experiments/matmul/scops.main.dot
@@ -0,0 +1,65 @@
+digraph "Scop Graph for 'main' function" {
+	label="Scop Graph for 'main' function";
+
+	Node0x17d21a0 [shape=record,label="{entry:\l  call void @init_array()\l  br label %for.cond\l}"];
+	Node0x17d21a0 -> Node0x17d2020;
+	Node0x17d2020 [shape=record,label="{for.cond:                                         \l  %indvar3 = phi i64 [ %indvar.next4, %for.inc28 ], [ 0, %entry ]\l  %exitcond6 = icmp ne i64 %indvar3, 1536\l  br i1 %exitcond6, label %for.body, label %for.end30\l}"];
+	Node0x17d2020 -> Node0x17d3950;
+	Node0x17d2020 -> Node0x17da500;
+	Node0x17d3950 [shape=record,label="{for.body:                                         \l  br label %for.cond1\l}"];
+	Node0x17d3950 -> Node0x17da760;
+	Node0x17da760 [shape=record,label="{for.cond1:                                        \l  %indvar1 = phi i64 [ %indvar.next2, %for.inc25 ], [ 0, %for.body ]\l  %arrayidx5 = getelementptr [1536 x [1536 x float]]* @C, i64 0, i64 %indvar3, i64 %indvar1\l  %exitcond5 = icmp ne i64 %indvar1, 1536\l  br i1 %exitcond5, label %for.body3, label %for.end27\l}"];
+	Node0x17da760 -> Node0x17db1e0;
+	Node0x17da760 -> Node0x17db250;
+	Node0x17db1e0 [shape=record,label="{for.body3:                                        \l  store float 0.000000e+00, float* %arrayidx5, align 4\l  br label %for.cond6\l}"];
+	Node0x17db1e0 -> Node0x17da740;
+	Node0x17da740 [shape=record,label="{for.cond6:                                        \l  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %for.body3 ]\l  %arrayidx16 = getelementptr [1536 x [1536 x float]]* @A, i64 0, i64 %indvar3, i64 %indvar\l  %arrayidx20 = getelementptr [1536 x [1536 x float]]* @B, i64 0, i64 %indvar, i64 %indvar1\l  %exitcond = icmp ne i64 %indvar, 1536\l  br i1 %exitcond, label %for.body8, label %for.end\l}"];
+	Node0x17da740 -> Node0x17da5a0;
+	Node0x17da740 -> Node0x17da800;
+	Node0x17da5a0 [shape=record,label="{for.body8:                                        \l  %0 = load float* %arrayidx5, align 4\l  %1 = load float* %arrayidx16, align 4\l  %2 = load float* %arrayidx20, align 4\l  %mul = fmul float %1, %2\l  %add = fadd float %0, %mul\l  store float %add, float* %arrayidx5, align 4\l  br label %for.inc\l}"];
+	Node0x17da5a0 -> Node0x17da5c0;
+	Node0x17da5c0 [shape=record,label="{for.inc:                                          \l  %indvar.next = add i64 %indvar, 1\l  br label %for.cond6\l}"];
+	Node0x17da5c0 -> Node0x17da740[constraint=false];
+	Node0x17da800 [shape=record,label="{for.end:                                          \l  br label %for.inc25\l}"];
+	Node0x17da800 -> Node0x17dae20;
+	Node0x17dae20 [shape=record,label="{for.inc25:                                        \l  %indvar.next2 = add i64 %indvar1, 1\l  br label %for.cond1\l}"];
+	Node0x17dae20 -> Node0x17da760[constraint=false];
+	Node0x17db250 [shape=record,label="{for.end27:                                        \l  br label %for.inc28\l}"];
+	Node0x17db250 -> Node0x17dae80;
+	Node0x17dae80 [shape=record,label="{for.inc28:                                        \l  %indvar.next4 = add i64 %indvar3, 1\l  br label %for.cond\l}"];
+	Node0x17dae80 -> Node0x17d2020[constraint=false];
+	Node0x17da500 [shape=record,label="{for.end30:                                        \l  ret i32 0\l}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x17d3f30 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x17d38d0 {
+            label = "";
+            style = filled;
+            color = 3            subgraph cluster_0x17d3850 {
+              label = "";
+              style = solid;
+              color = 5
+              subgraph cluster_0x17d37d0 {
+                label = "";
+                style = solid;
+                color = 7
+                Node0x17da740;
+                Node0x17da5a0;
+                Node0x17da5c0;
+              }
+              Node0x17da760;
+              Node0x17db1e0;
+              Node0x17da800;
+              Node0x17dae20;
+            }
+            Node0x17d2020;
+            Node0x17d3950;
+            Node0x17db250;
+            Node0x17dae80;
+          }
+          Node0x17d21a0;
+          Node0x17da500;
+        }
+}
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..59f02e7
--- /dev/null
+++ b/final/www/experiments/matmul/scops.print_array.dot
@@ -0,0 +1,60 @@
+digraph "Scop Graph for 'print_array' function" {
+	label="Scop Graph for 'print_array' function";
+
+	Node0x17d2200 [shape=record,label="{entry:\l  br label %for.cond\l}"];
+	Node0x17d2200 -> Node0x17d4f20;
+	Node0x17d4f20 [shape=record,label="{for.cond:                                         \l  %indvar1 = phi i64 [ %indvar.next2, %for.inc10 ], [ 0, %entry ]\l  %exitcond3 = icmp ne i64 %indvar1, 1536\l  br i1 %exitcond3, label %for.body, label %for.end12\l}"];
+	Node0x17d4f20 -> Node0x17d3680;
+	Node0x17d4f20 -> Node0x17d9fc0;
+	Node0x17d3680 [shape=record,label="{for.body:                                         \l  br label %for.cond1\l}"];
+	Node0x17d3680 -> Node0x17da220;
+	Node0x17da220 [shape=record,label="{for.cond1:                                        \l  %indvar = phi i64 [ %indvar.next, %for.inc ], [ 0, %for.body ]\l  %arrayidx5 = getelementptr [1536 x [1536 x float]]* @C, i64 0, i64 %indvar1, i64 %indvar\l  %j.0 = trunc i64 %indvar to i32\l  %exitcond = icmp ne i64 %indvar, 1536\l  br i1 %exitcond, label %for.body3, label %for.end\l}"];
+	Node0x17da220 -> Node0x17d9ea0;
+	Node0x17da220 -> Node0x17da0f0;
+	Node0x17d9ea0 [shape=record,label="{for.body3:                                        \l  %0 = load %struct._IO_FILE** @stdout, align 8\l  %1 = load float* %arrayidx5, align 4\l  %conv = fpext float %1 to double\l  %call = call i32 (%struct._IO_FILE*, i8*, ...)* @fprintf(%struct._IO_FILE* %0, i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), double %conv)\l  %rem = srem i32 %j.0, 80\l  %cmp6 = icmp eq i32 %rem, 79\l  br i1 %cmp6, label %if.then, label %if.end\l}"];
+	Node0x17d9ea0 -> Node0x17d9ec0;
+	Node0x17d9ea0 -> Node0x17da060;
+	Node0x17d9ec0 [shape=record,label="{if.then:                                          \l  %2 = load %struct._IO_FILE** @stdout, align 8\l  %call8 = call i32 (%struct._IO_FILE*, i8*, ...)* @fprintf(%struct._IO_FILE* %2, i8* getelementptr inbounds ([2 x i8]* @.str1, i32 0, i32 0))\l  br label %if.end\l}"];
+	Node0x17d9ec0 -> Node0x17da060;
+	Node0x17da060 [shape=record,label="{if.end:                                           \l  br label %for.inc\l}"];
+	Node0x17da060 -> Node0x17da200;
+	Node0x17da200 [shape=record,label="{for.inc:                                          \l  %indvar.next = add i64 %indvar, 1\l  br label %for.cond1\l}"];
+	Node0x17da200 -> Node0x17da220[constraint=false];
+	Node0x17da0f0 [shape=record,label="{for.end:                                          \l  %3 = load %struct._IO_FILE** @stdout, align 8\l  %call9 = call i32 (%struct._IO_FILE*, i8*, ...)* @fprintf(%struct._IO_FILE* %3, i8* getelementptr inbounds ([2 x i8]* @.str1, i32 0, i32 0))\l  br label %for.inc10\l}"];
+	Node0x17da0f0 -> Node0x17da080;
+	Node0x17da080 [shape=record,label="{for.inc10:                                        \l  %indvar.next2 = add i64 %indvar1, 1\l  br label %for.cond\l}"];
+	Node0x17da080 -> Node0x17d4f20[constraint=false];
+	Node0x17d9fc0 [shape=record,label="{for.end12:                                        \l  ret void\l}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x17d38f0 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x17d4030 {
+            label = "Non affine branch in BB 'for.body3' with LHS: %rem and RHS: 79";
+            style = solid;
+            color = 6
+            subgraph cluster_0x17d3fb0 {
+              label = "Non affine branch in BB 'for.body3' with LHS: %rem and RHS: 79";
+              style = solid;
+              color = 5
+              subgraph cluster_0x17d3f30 {
+                label = "Non affine branch in BB 'for.body3' with LHS: %rem and RHS: 79";
+                style = solid;
+                color = 7
+                Node0x17d9ea0;
+                Node0x17d9ec0;
+              }
+              Node0x17da220;
+              Node0x17da060;
+              Node0x17da200;
+            }
+            Node0x17d4f20;
+            Node0x17d3680;
+            Node0x17da0f0;
+            Node0x17da080;
+          }
+          Node0x17d2200;
+          Node0x17d9fc0;
+        }
+}
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..4685c5b
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.init_array.dot
@@ -0,0 +1,47 @@
+digraph "Scop Graph for 'init_array' function" {
+	label="Scop Graph for 'init_array' function";
+
+	Node0x17d4370 [shape=record,label="{entry}"];
+	Node0x17d4370 -> Node0x17d9de0;
+	Node0x17d9de0 [shape=record,label="{for.cond}"];
+	Node0x17d9de0 -> Node0x17d9e40;
+	Node0x17d9de0 -> Node0x17d9ea0;
+	Node0x17d9e40 [shape=record,label="{for.body}"];
+	Node0x17d9e40 -> Node0x17d9f90;
+	Node0x17d9f90 [shape=record,label="{for.cond1}"];
+	Node0x17d9f90 -> Node0x17d9ff0;
+	Node0x17d9f90 -> Node0x17da050;
+	Node0x17d9ff0 [shape=record,label="{for.body3}"];
+	Node0x17d9ff0 -> Node0x17d9f00;
+	Node0x17d9f00 [shape=record,label="{for.inc}"];
+	Node0x17d9f00 -> Node0x17d9f90[constraint=false];
+	Node0x17da050 [shape=record,label="{for.end}"];
+	Node0x17da050 -> Node0x17da200;
+	Node0x17da200 [shape=record,label="{for.inc17}"];
+	Node0x17da200 -> Node0x17d9de0[constraint=false];
+	Node0x17d9ea0 [shape=record,label="{for.end19}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x17d3a30 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x17d4ec0 {
+            label = "";
+            style = filled;
+            color = 3            subgraph cluster_0x17d4180 {
+              label = "";
+              style = solid;
+              color = 5
+              Node0x17d9f90;
+              Node0x17d9ff0;
+              Node0x17d9f00;
+            }
+            Node0x17d9de0;
+            Node0x17d9e40;
+            Node0x17da050;
+            Node0x17da200;
+          }
+          Node0x17d4370;
+          Node0x17d9ea0;
+        }
+}
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..3b3f328
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.main.dot
@@ -0,0 +1,65 @@
+digraph "Scop Graph for 'main' function" {
+	label="Scop Graph for 'main' function";
+
+	Node0x17d3950 [shape=record,label="{entry}"];
+	Node0x17d3950 -> Node0x17d21a0;
+	Node0x17d21a0 [shape=record,label="{for.cond}"];
+	Node0x17d21a0 -> Node0x17db9a0;
+	Node0x17d21a0 -> Node0x17da4f0;
+	Node0x17db9a0 [shape=record,label="{for.body}"];
+	Node0x17db9a0 -> Node0x17da5e0;
+	Node0x17da5e0 [shape=record,label="{for.cond1}"];
+	Node0x17da5e0 -> Node0x17da640;
+	Node0x17da5e0 -> Node0x17da6a0;
+	Node0x17da640 [shape=record,label="{for.body3}"];
+	Node0x17da640 -> Node0x17da550;
+	Node0x17da550 [shape=record,label="{for.cond6}"];
+	Node0x17da550 -> Node0x17da5b0;
+	Node0x17da550 -> Node0x17da850;
+	Node0x17da5b0 [shape=record,label="{for.body8}"];
+	Node0x17da5b0 -> Node0x17da8b0;
+	Node0x17da8b0 [shape=record,label="{for.inc}"];
+	Node0x17da8b0 -> Node0x17da550[constraint=false];
+	Node0x17da850 [shape=record,label="{for.end}"];
+	Node0x17da850 -> Node0x17db930;
+	Node0x17db930 [shape=record,label="{for.inc25}"];
+	Node0x17db930 -> Node0x17da5e0[constraint=false];
+	Node0x17da6a0 [shape=record,label="{for.end27}"];
+	Node0x17da6a0 -> Node0x17dada0;
+	Node0x17dada0 [shape=record,label="{for.inc28}"];
+	Node0x17dada0 -> Node0x17d21a0[constraint=false];
+	Node0x17da4f0 [shape=record,label="{for.end30}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x17d3f30 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x17d38d0 {
+            label = "";
+            style = filled;
+            color = 3            subgraph cluster_0x17d3850 {
+              label = "";
+              style = solid;
+              color = 5
+              subgraph cluster_0x17d37d0 {
+                label = "";
+                style = solid;
+                color = 7
+                Node0x17da550;
+                Node0x17da5b0;
+                Node0x17da8b0;
+              }
+              Node0x17da5e0;
+              Node0x17da640;
+              Node0x17da850;
+              Node0x17db930;
+            }
+            Node0x17d21a0;
+            Node0x17db9a0;
+            Node0x17da6a0;
+            Node0x17dada0;
+          }
+          Node0x17d3950;
+          Node0x17da4f0;
+        }
+}
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..c900d0f
--- /dev/null
+++ b/final/www/experiments/matmul/scopsonly.print_array.dot
@@ -0,0 +1,60 @@
+digraph "Scop Graph for 'print_array' function" {
+	label="Scop Graph for 'print_array' function";
+
+	Node0x17d2200 [shape=record,label="{entry}"];
+	Node0x17d2200 -> Node0x17d4f20;
+	Node0x17d4f20 [shape=record,label="{for.cond}"];
+	Node0x17d4f20 -> Node0x17d9fd0;
+	Node0x17d4f20 -> Node0x17da030;
+	Node0x17d9fd0 [shape=record,label="{for.body}"];
+	Node0x17d9fd0 -> Node0x17da120;
+	Node0x17da120 [shape=record,label="{for.cond1}"];
+	Node0x17da120 -> Node0x17da180;
+	Node0x17da120 -> Node0x17da1e0;
+	Node0x17da180 [shape=record,label="{for.body3}"];
+	Node0x17da180 -> Node0x17da090;
+	Node0x17da180 -> Node0x17da0f0;
+	Node0x17da090 [shape=record,label="{if.then}"];
+	Node0x17da090 -> Node0x17da0f0;
+	Node0x17da0f0 [shape=record,label="{if.end}"];
+	Node0x17da0f0 -> Node0x17da390;
+	Node0x17da390 [shape=record,label="{for.inc}"];
+	Node0x17da390 -> Node0x17da120[constraint=false];
+	Node0x17da1e0 [shape=record,label="{for.end}"];
+	Node0x17da1e0 -> Node0x17d9e40;
+	Node0x17d9e40 [shape=record,label="{for.inc10}"];
+	Node0x17d9e40 -> Node0x17d4f20[constraint=false];
+	Node0x17da030 [shape=record,label="{for.end12}"];
+	colorscheme = "paired12"
+        subgraph cluster_0x17d38f0 {
+          label = "";
+          style = solid;
+          color = 1
+          subgraph cluster_0x17d4030 {
+            label = "Non affine branch in BB 'for.body3' with LHS: %rem and RHS: 79";
+            style = solid;
+            color = 6
+            subgraph cluster_0x17d3fb0 {
+              label = "Non affine branch in BB 'for.body3' with LHS: %rem and RHS: 79";
+              style = solid;
+              color = 5
+              subgraph cluster_0x17d3f30 {
+                label = "Non affine branch in BB 'for.body3' with LHS: %rem and RHS: 79";
+                style = solid;
+                color = 7
+                Node0x17da180;
+                Node0x17da090;
+              }
+              Node0x17da120;
+              Node0x17da0f0;
+              Node0x17da390;
+            }
+            Node0x17d4f20;
+            Node0x17d9fd0;
+            Node0x17da1e0;
+            Node0x17d9e40;
+          }
+          Node0x17d2200;
+          Node0x17da030;
+        }
+}
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..92299fb
--- /dev/null
+++ b/final/www/get_started.html
@@ -0,0 +1,273 @@
+<!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>Getting Started: 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 [after 3.6]</h2>
+<h3 id="source"> Get the code </h3>
+
+The Polly source code is available in the LLVM SVN repository as well as through
+an official git mirror. It is added to the <em>tools</em>
+directory of the llvm sources.
+<b>Polly and LLVM need to be checked out at the same time. Checkouts
+   from different dates may not work!</b>
+<h4>Set the directory layout:</h4>
+<pre>
+export BASE=`pwd`
+export LLVM_SRC=${BASE}/llvm
+export POLLY_SRC=${LLVM_SRC}/tools/polly
+
+# Also build the matching clang-version (optional)
+export CLANG_SRC=${LLVM_SRC}/tools/clang
+</pre>
+
+<h4>SVN</h4>
+<pre>
+svn checkout http://llvm.org/svn/llvm-project/llvm/trunk ${LLVM_SRC}
+svn checkout http://llvm.org/svn/llvm-project/polly/trunk ${POLLY_SRC}
+
+# Also build the matching clang-version (optional)
+svn checkout http://llvm.org/svn/llvm-project/cfe/trunk ${CLANG_SRC}
+</pre>
+<h4>GIT</h4>
+<pre>
+git clone http://llvm.org/git/llvm.git ${LLVM_SRC}
+git clone http://llvm.org/git/polly.git ${POLLY_SRC}
+
+# Also build the matching clang-version (optional)
+git clone http://llvm.org/git/clang.git ${CLANG_SRC}
+</pre>
+<h3 id="build">Build Polly</h3>
+
+To build Polly you can either use the autoconf or the cmake build system. At the
+moment only the autoconf build system allows to run the llvm test-suite and only
+the cmake build system allows to run 'make check-polly'.
+
+<h4>Set the directory layout:</h4>
+<pre>
+export LLVM_BUILD=${BASE}/llvm_build
+mkdir ${LLVM_BUILD}
+cd ${LLVM_BUILD}
+</pre>
+
+<h4>CMake</h4>
+
+<pre>
+cmake ${LLVM_SRC} && make
+</pre>
+
+<h4> Autoconf </h4>
+
+<pre>
+${LLVM_SRC}/configure && make
+</pre>
+
+<h3> Test Polly</h3>
+
+<p>To check if Polly works correctly you can run <em>make check-polly</em> for the
+cmake build or <em>make check-polly -C tools/polly/test/</em> for the autoconf
+build.
+
+<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>
+
+<h2> Manual [before and including 3.6]</h2>
+<h3 id="source"> Get the code </h3>
+
+The Polly source code is available in the LLVM SVN repository as well as through
+an official git mirror. It is added to the <em>tools</em>
+directory of the llvm sources.
+<b>Polly and LLVM need to be checked out at the same time. Checkouts
+   from different dates may not work!</b>
+<h4>Set the directory layout:</h4>
+<pre>
+export BASE=`pwd`
+export LLVM_SRC=${BASE}/llvm
+export POLLY_SRC=${LLVM_SRC}/tools/polly
+
+# Also build the matching clang-version (optional)
+export CLANG_SRC=${LLVM_SRC}/tools/clang
+</pre>
+
+<h4>SVN</h4>
+<pre>
+svn checkout http://llvm.org/svn/llvm-project/llvm/trunk ${LLVM_SRC}
+svn checkout http://llvm.org/svn/llvm-project/polly/trunk ${POLLY_SRC}
+
+# Also build the matching clang-version (optional)
+svn checkout http://llvm.org/svn/llvm-project/cfe/trunk ${CLANG_SRC}
+</pre>
+<h4>GIT</h4>
+<pre>
+git clone http://llvm.org/git/llvm.git ${LLVM_SRC}
+git clone http://llvm.org/git/polly.git ${POLLY_SRC}
+
+# Also build the matching clang-version (optional)
+git clone http://llvm.org/git/clang.git ${CLANG_SRC}
+</pre>
+<h3 id="prerequisites"> Prerequisites </h3>
+<ul>
+<li>libgmp</li>
+<li>isl</li>
+</ul>
+
+<h4> libgmp </h4>
+Install libgmp (library + developer package) through the package management
+system of your operating system.
+
+<h4> isl</h4>
+
+Polly is tested with a fixed version of isl. To obtain the source code of isl
+use checkout_isl.sh as available in ${POLLY_SRC}/utils/checkout_isl.sh.
+
+<h4>Set the directory layout:</h4>
+<pre>
+export ISL_SRC=${BASE}/isl_src
+export ISL_INSTALL=${BASE}/isl_install
+</pre>
+
+<h4> First installation</h4>
+<pre>
+${POLLY_SRC}/utils/checkout_isl.sh ${ISL_SRC}
+cd ${ISL_SRC}
+./configure --prefix=${ISL_INSTALL}
+make
+make install
+cd ${BASE}
+</pre>
+
+<h4> Update the installation</h4>
+
+Updating isl may become necessary, if Polly uses a feature
+only available in a recent version of isl.
+<pre>
+${POLLY_SRC}/utils/checkout_isl.sh ${ISL_SRC}
+cd ${ISL_SRC}
+make
+make install
+cd ${BASE}
+</pre>
+
+<h3 id="build">Build Polly</h3>
+
+To build Polly you can either use the autoconf or the cmake build system. At the
+moment only the autoconf build system allows to run the llvm test-suite and only
+the cmake build system allows to run 'make check-polly'.
+
+<h4>Set the directory layout:</h4>
+<pre>
+export LLVM_BUILD=${BASE}/llvm_build
+mkdir ${LLVM_BUILD}
+cd ${LLVM_BUILD}
+</pre>
+
+<h4>CMake</h4>
+
+<pre>
+cmake -DCMAKE_PREFIX_PATH=${ISL_INSTALL} ${LLVM_SRC}
+make
+</pre>
+
+<h4> Autoconf </h4>
+
+<pre>
+${LLVM_SRC}/configure --with-isl=${ISL_INSTALL}
+make
+</pre>
+
+<h3> Test Polly</h3>
+
+<p>To check if Polly works correctly you can run <em>make check-polly</em> for the
+cmake build or <em>make check-polly -C tools/polly/test/</em> for the autoconf
+build.
+
+<p>If you get something like <em>"... libisl.so.9: cannot open shared object file .."</em>,
+it is because you installed isl to a non-standard path, and libisl
+could not be found. To solve this issue, you need to append the path of parent
+directory of libisl, i.e. ${ISL_INSTALL}/lib, to LD_LIBRARY_PATH by:
+
+<pre>export LD_LIBRARY_PATH=${ISL_INSTALL}/lib:$LD_LIBRARY_PATH</pre>
+
+<p>Also try the above command if you get errors such as:
+<code>undefined symbol: isl_ctx_get_max_operations</code>
+
+<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>
+
+<h2> Optional Features </h2>
+
+<h3> Pocc [Supported until <a href="http://llvm.org/releases/download.html#3.4.2">LLVM 3.4.2</a>]</h3>
+
+<p>Polly can use <a href="http://www.cse.ohio-state.edu/~pouchet/software/pocc">
+PoCC</a> as an external optimizer. PoCC is a research project that provides
+an integrated version of <a href="http://pluto-compiler.sf.net">Pluto</a>, an
+advanced data-locality and tileability optimizer. Polly includes internally
+already a similar optimizer, such that in general PoCC is not needed. It is
+only recommended for people who want to compare against a different
+optimizer.</a>
+<br/>
+To use it install PoCC 1.0-rc3.1 (the one with Polly support) and add it to your PATH.
+
+<pre>
+wget <a
+href="http://www.cse.ohio-state.edu/~pouchet/software/pocc/download/pocc-1.0-rc3.1-full.tar.gz">http://www.cse.ohio-state.edu/~pouchet/software/pocc/download/pocc-1.0-rc3.1-full.tar.gz</a>
+tar xzf pocc-1.0-rc3.1-full.tar.gz
+cd pocc-1.0-rc3.1
+./install.sh
+export PATH=$PATH:`pwd`/bin
+</pre>
+
+You also need to install scoplib-0.2.0 and provide its location to
+Polly's cmake or configure call.
+
+<pre>
+wget <a
+href="http://www.cse.ohio-state.edu/~pouchet/software/pocc/download/modules/scoplib-0.2.0.tar.gz"
+>http://www.cse.ohio-state.edu/~pouchet/software/pocc/download/modules/scoplib-0.2.0.tar.gz</a>
+tar xzf  scoplib-0.2.0.tar.gz
+cd scoplib-0.2.0
+./configure --enable-mp-version --prefix=/path/to/scoplib/installation
+make && make install
+</pre>
+</div>
+</div>
+
+</body>
+</html>
diff --git a/final/www/images/architecture.png b/final/www/images/architecture.png
new file mode 100644
index 0000000..fdd26a0
--- /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/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..c4ca186
--- /dev/null
+++ b/final/www/index.html
@@ -0,0 +1,367 @@
+<!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>2015</b></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..a3e3ad7
--- /dev/null
+++ b/final/www/menu.css
@@ -0,0 +1,87 @@
+/***************/
+/* 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;
+}
+
+#menu a:visited {
+}
+
+#menu .submenu2 {
+        margin-top: 2em;
+}
+
+#menu .submenu2 label {
+	background-color: #f35555;
+}
+
+.rss-box {
+  padding: 0em;
+}
+
+li.rss-item {
+  padding-bottom: 0em;
+  height: 1.3em;
+}
+
+.rss_item {
+  line-height: 0.5em;
+  padding-top: 1em;
+}
+
+.rss_date {
+  font-size: 0.8em;
+  color: #f35555;
+  padding-left: 0.4em;
+}
diff --git a/final/www/menu.html.incl b/final/www/menu.html.incl
new file mode 100644
index 0000000..a776359
--- /dev/null
+++ b/final/www/menu.html.incl
@@ -0,0 +1,77 @@
+<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">
+  <div class="submenu">
+    <label>LLVM</label>
+    <a href="http://llvm.org">llvm.org</a>
+  </div>
+  <div class="submenu">
+    <label>Information</label>
+    <a href="/index.html">About Polly</a>
+    <a href="/documentation.html">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>
+  </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://buildd-clang.debian.net/coverage/">Code Coverage</a>
+    <a href="http://buildd-clang.debian.net/scan-build/">Static analysis</a>
+  </div>
+
+  <div class="submenu">
+    <label>The Code</label>
+    <a href="/get_started.html">Get and Install</a>
+    <a href="http://llvm.org/viewvc/llvm-project/polly/trunk/">
+      Browse (ViewVC)
+    </a>
+    <a href="http://repo.or.cz/w/polly-mirror.git">Browse (GitWeb)</a>
+  </div>
+
+  <div class="submenu2">
+  <label>polyhedral.info news</label>
+  <script language="JavaScript"
+  src="http://feed2js.org//feed2js.php?src=http%3A%2F%2Fpolyhedral.info%2Frss.xml&num=5&utf=y"
+  charset="UTF-8" type="text/javascript"></script>
+
+  <noscript>
+  <a
+  href="http://feed2js.org//feed2js.php?src=http%3A%2F%2Fpolyhedral.info%2Frss.xml&num=5&utf=y&html=y">View
+  RSS feed</a>
+  </noscript>
+ </div>
+</div>
+
+<script type="text/javascript">
+  var _paq = _paq || [];
+  _paq.push(["trackPageView"]);
+  _paq.push(["enableLinkTracking"]);
+
+  (function() {
+    var u=(("https:" == document.location.protocol) ? "https" : "http") + "://www.grosser.es/piwik/piwik/";
+    _paq.push(["setTrackerUrl", u+"piwik.php"]);
+    _paq.push(["setSiteId", "3"]);
+    var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript";
+    g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s);
+  })();
+</script>
+<noscript>
+<img src="http://www.grosser.es/piwik/piwik/piwik.php?idsite=3&amp;rec=1" style="border:0" alt="" />
+</noscript>
+
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..af4e747
--- /dev/null
+++ b/final/www/polly.sh
@@ -0,0 +1,38 @@
+#!/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}
+
+if which cmake ; then
+    cmake ${LLVM_SRC}
+    make -j$procs -l$procs
+    make check-polly
+else
+    ${LLVM_SRC}/configure
+    make -j$procs -l$procs
+    make check-polly -C tools/polly/test/
+fi
diff --git a/final/www/publications.html b/final/www/publications.html
new file mode 100644
index 0000000..bb96b1f
--- /dev/null
+++ b/final/www/publications.html
@@ -0,0 +1,203 @@
+<!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.worldscientific.com/doi/abs/10.1142/S0129626412500107?af=R">
+Online Issue</a>
+</p>
+
+  <h2> Publications involving Polly </h2>
+  <h3> 2015 </h3>
+  <ul>
+  <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/">Impact2015</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/">Impact2015</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..517b55b
--- /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>
+</td></tr>
+<tr>
+<th align="left">
+Boolean Combinations
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Unsigned Integers
+</th><td align="center" class='open'> Open
+</td><td>
+</td></tr>
+<tr>
+<th align="left">
+Pointer Comparisions
+</th><td align="center" class='done'> Done
+</td><td>
+</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='open'> Open
+</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='open'> Open
+</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="open"> Open
+</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='open'> Open
+</td><td>
+</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='open'> Open
+</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='open'> Open
+</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