Add initial version of Polly

This version is equivalent to commit ba26ebece8f5be84e9bd6315611d412af797147e
in the old git repository.

llvm-svn: 130476
This commit is contained in:
Tobias Grosser 2011-04-29 06:27:02 +00:00
parent 011eae7512
commit 758053788b
319 changed files with 43125 additions and 0 deletions

164
polly/CMakeLists.txt Normal file
View File

@ -0,0 +1,164 @@
# 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)
# 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} )
# 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})
endif(NOT DEFINED LLVM_MAIN_SRC_DIR)
set(POLLY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(POLLY_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
# 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 ()
# Add path for custom modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${POLLY_SOURCE_DIR}/cmake")
FIND_PACKAGE(Cloog REQUIRED)
FIND_PACKAGE(Isl REQUIRED)
FIND_PACKAGE(Gmp REQUIRED)
option(POLLY_ENABLE_OPENSCOP "Enable Openscop library for scop import/export" ON)
if (POLLY_ENABLE_OPENSCOP)
FIND_PACKAGE(OpenScop)
endif(POLLY_ENABLE_OPENSCOP)
option(POLLY_ENABLE_SCOPLIB "Enable SCoPLib library for scop import/export" ON)
if (POLLY_ENABLE_SCOPLIB)
FIND_PACKAGE(SCoPLib)
endif(POLLY_ENABLE_SCOPLIB)
INCLUDE_DIRECTORIES( ${CLOOG_INCLUDE_DIR} )
INCLUDE_DIRECTORIES( ${ISL_INCLUDE_DIR} )
INCLUDE_DIRECTORIES( ${GMP_INCLUDE_DIR} )
# Support OpenScop export/import if the library is available.
if (OPENSCOP_FOUND)
INCLUDE_DIRECTORIES( ${OPENSCOP_INCLUDE_DIR} )
endif(OPENSCOP_FOUND)
if (SCOPLIB_FOUND)
INCLUDE_DIRECTORIES( ${SCOPLIB_INCLUDE_DIR} )
endif(SCOPLIB_FOUND)
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 )
target_link_libraries( ${name} ${CLOOG_LIBRARY} ${ISL_LIBRARY} ${GMP_LIBRARY})
if (OPENSCOP_FOUND)
target_link_libraries( ${name} ${OPENSCOP_LIBRARY})
endif(OPENSCOP_FOUND)
if (SCOPLIB_FOUND)
target_link_libraries( ${name} ${SCOPLIB_LIBRARY})
endif(SCOPLIB_FOUND)
if( LLVM_LINK_COMPONENTS )
llvm_config(${name} ${LLVM_LINK_COMPONENTS})
endif( LLVM_LINK_COMPONENTS )
get_system_libs(llvm_system_libs)
if( llvm_system_libs )
target_link_libraries(${name} ${llvm_system_libs})
endif( llvm_system_libs )
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}
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
endmacro(add_polly_library)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/lib/JSON/include
${CMAKE_CURRENT_BINARY_DIR}/include
)
install(DIRECTORY include
DESTINATION .
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 )

31
polly/CREDITS.txt Normal file
View File

@ -0,0 +1,31 @@
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
LLVM, 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: Andreas Simbuerger
E: simbuerg@fim.uni-passau.de
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

61
polly/LICENSE.txt Normal file
View File

@ -0,0 +1,61 @@
==============================================================================
Polly Release License
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2009-2011 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

17
polly/Makefile Normal file
View File

@ -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

34
polly/Makefile.common.in Executable file
View File

@ -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

40
polly/Makefile.config.in Executable file
View File

@ -0,0 +1,40 @@
#===-- 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
# Do us work with scoplib?
OPENSCOP_FOUND := @openscop_found@
SCOPLIB_FOUND := @scoplib_found@
# Set include directroys
POLLY_INC := @gmp_inc@ @isl_inc@ \
@cloog_inc@ @openscop_inc@ @scoplib_inc@ \
-I$(POLLY_SRC_ROOT)/lib/JSON/include
POLLY_LD := @gmp_ld@ @isl_ld@ @cloog_ld@ @openscop_ld@ @scoplib_ld@ @scoplib_rpath@
POLLY_LIB := @gmp_lib@ @isl_lib@ @cloog_lib@ @openscop_lib@ @scoplib_lib@

12
polly/README Normal file
View File

@ -0,0 +1,12 @@
Polly - Polyhedral optimizations for LLVM
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.

33
polly/autoconf/AutoRegen.sh Executable file
View File

@ -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

View File

@ -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.

75
polly/autoconf/aclocal.m4 vendored Normal file
View File

@ -0,0 +1,75 @@
# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007, 2008, 2009 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.
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 in $given_inc_path, $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}"])
])

1388
polly/autoconf/config.guess vendored Normal file

File diff suppressed because it is too large Load Diff

1489
polly/autoconf/config.sub vendored Normal file

File diff suppressed because it is too large Load Diff

114
polly/autoconf/configure.ac Normal file
View File

@ -0,0 +1,114 @@
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 auxilliary 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
AC_DEFINE([CLOOG_INT_GMP], [1], [Use gmp for isl])
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 Find Gmp
find_lib_and_headers([gmp], [gmp.h], [gmp], [required])
dnl Find Isl
find_lib_and_headers([isl], [isl/config.h], [isl], [required])
dnl Find cloog
saved_CXXFLAGS=$CXXFLAGS
CXXFLAGS="$CXXFLAGS $isl_inc"
find_lib_and_headers([cloog], [cloog/isl/cloog.h], [cloog-isl], [required])
CXXFLAGS=$saved_CXXFLAGS
dnl Check if Scoplib there
find_lib_and_headers([openscop], [openscop/scop.h], [openscop])
AS_IF([test "x$openscop_found" = "xyes"],
[AC_DEFINE([OPENSCOP_FOUND],[1],[Define if openscop found])])
dnl Check if Scoplib there
find_lib_and_headers([scoplib], [scoplib/scop.h], [scoplib])
AS_IF([test "x$scoplib_found" = "xyes"],
[AC_DEFINE([SCOPLIB_FOUND],[1],[Define if scoplib found])])
if test "x$scoplib_found" = "xyes"; then :
scoplib_rpath="-Wl,-rpath=$given_lib_path"
else
scoplib_rpath=""
fi
AC_SUBST(scoplib_rpath)
dnl **************************************************************************
dnl * Create the output files
dnl **************************************************************************
dnl This must be last
AC_CONFIG_HEADERS(include/polly/Config/config.h)
AC_OUTPUT

View File

@ -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 auxilliary 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

View File

@ -0,0 +1,46 @@
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 in $given_inc_path, $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++)
])

View File

@ -0,0 +1,19 @@
FIND_PATH(CLOOG_INCLUDE_DIR cloog/isl/cloog.h)
FIND_LIBRARY(CLOOG_LIBRARY NAMES cloog-isl)
IF (CLOOG_INCLUDE_DIR AND CLOOG_LIBRARY)
SET(CLOOG_FOUND TRUE)
ENDIF (CLOOG_INCLUDE_DIR AND CLOOG_LIBRARY)
IF (CLOOG_FOUND)
IF (NOT CLOOG_FIND_QUIETLY)
MESSAGE(STATUS "Found Cloog: ${CLOOG_LIBRARY}")
ENDIF (NOT CLOOG_FIND_QUIETLY)
ELSE (CLOOG_FOUND)
IF (CLOOG_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Cloog")
ENDIF (CLOOG_FIND_REQUIRED)
ENDIF (CLOOG_FOUND)

19
polly/cmake/FindGmp.cmake Normal file
View File

@ -0,0 +1,19 @@
FIND_PATH(GMP_INCLUDE_DIR gmp.h)
FIND_LIBRARY(GMP_LIBRARY NAMES gmp)
IF (GMP_INCLUDE_DIR AND GMP_LIBRARY)
SET(GMP_FOUND TRUE)
ENDIF (GMP_INCLUDE_DIR AND GMP_LIBRARY)
IF (GMP_FOUND)
IF (NOT GMP_FIND_QUIETLY)
MESSAGE(STATUS "Found GMP: ${GMP_LIBRARY}")
ENDIF (NOT GMP_FIND_QUIETLY)
ELSE (GMP_FOUND)
IF (GMP_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find GMP")
ENDIF (GMP_FIND_REQUIRED)
ENDIF (GMP_FOUND)

19
polly/cmake/FindIsl.cmake Normal file
View File

@ -0,0 +1,19 @@
FIND_PATH(ISL_INCLUDE_DIR isl/set.h)
FIND_LIBRARY(ISL_LIBRARY NAMES isl)
IF (ISL_INCLUDE_DIR AND ISL_LIBRARY)
SET(ISL_FOUND TRUE)
ENDIF (ISL_INCLUDE_DIR AND ISL_LIBRARY)
IF (ISL_FOUND)
IF (NOT Isl_FIND_QUIETLY)
MESSAGE(STATUS "Found Isl: ${ISL_LIBRARY}")
ENDIF (NOT Isl_FIND_QUIETLY)
ELSE (ISL_FOUND)
IF (Isl_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Isl")
ENDIF (Isl_FIND_REQUIRED)
ENDIF (ISL_FOUND)

View File

@ -0,0 +1,19 @@
FIND_PATH(OPENSCOP_INCLUDE_DIR openscop/scop.h)
FIND_LIBRARY(OPENSCOP_LIBRARY NAMES openscop)
IF (OPENSCOP_INCLUDE_DIR AND OPENSCOP_LIBRARY)
SET(OPENSCOP_FOUND TRUE)
ENDIF (OPENSCOP_INCLUDE_DIR AND OPENSCOP_LIBRARY)
IF (OPENSCOP_FOUND)
IF (NOT Isl_FIND_QUIETLY)
MESSAGE(STATUS "Found OpenScop: ${OPENSCOP_LIBRARY}")
ENDIF (NOT Isl_FIND_QUIETLY)
ELSE (OPENSCOP_FOUND)
IF (Isl_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find OpenScop")
ENDIF (Isl_FIND_REQUIRED)
ENDIF (OPENSCOP_FOUND)

View File

@ -0,0 +1,19 @@
FIND_PATH(SCOPLIB_INCLUDE_DIR scoplib/scop.h)
FIND_LIBRARY(SCOPLIB_LIBRARY NAMES scoplib)
IF (SCOPLIB_INCLUDE_DIR AND SCOPLIB_LIBRARY)
SET(SCOPLIB_FOUND TRUE)
ENDIF (SCOPLIB_INCLUDE_DIR AND SCOPLIB_LIBRARY)
IF (SCOPLIB_FOUND)
IF (NOT Isl_FIND_QUIETLY)
MESSAGE(STATUS "Found SCoPLib: ${SCOPLIB_LIBRARY}")
ENDIF (NOT Isl_FIND_QUIETLY)
ELSE (SCOPLIB_FOUND)
IF (Isl_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find SCoPLib")
ENDIF (Isl_FIND_REQUIRED)
ENDIF (SCOPLIB_FOUND)

4088
polly/configure vendored Executable file

File diff suppressed because it is too large Load Diff

6
polly/docs/index.html Normal file
View File

@ -0,0 +1,6 @@
<html>
<body>
<h1>SAMPLE PROJECT DOCUMENTATION</h1>
<p>This is just a placeholder</p>
</body>
</html>

BIN
polly/docs/polly.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

149
polly/docs/polly.svg Normal file
View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="401.6861"
height="238.80142"
id="svg2"
version="1.1"
inkscape:version="0.48.0 r9654"
sodipodi:docname="polly.png">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.32759489"
inkscape:cx="105.19472"
inkscape:cy="-140.99869"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="862"
inkscape:window-height="879"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-180.51353,-120.73426)">
<flowRoot
xml:space="preserve"
id="flowRoot3053"
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"><flowRegion
id="flowRegion3055"><rect
id="rect3057"
width="234.05714"
height="123.29796"
x="115.98367"
y="215.39891" /></flowRegion><flowPara
id="flowPara3059"></flowPara></flowRoot> <text
xml:space="preserve"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:OpenSymbol;-inkscape-font-specification:OpenSymbol"
x="173.45306"
y="355.41525"
id="text3061"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3063"
x="173.45306"
y="355.41525"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:URW Bookman L;-inkscape-font-specification:URW Bookman L" /></text>
<g
id="g3981">
<g
id="g3971">
<text
xml:space="preserve"
style="font-size:188.40333557px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#253ba3;fill-opacity:1;stroke:none;font-family:Sans"
x="166.2375"
y="263.02325"
id="text3069"
sodipodi:linespacing="125%"
transform="scale(0.97718415,1.0233486)"><tspan
sodipodi:role="line"
id="tspan3071"
x="166.2375"
y="263.02325">Po</tspan></text>
<text
xml:space="preserve"
style="font-size:188.40333557px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#25a34d;fill-opacity:1;stroke:none;font-family:Sans"
x="401.41913"
y="255.32637"
id="text3073"
sodipodi:linespacing="125%"
transform="scale(0.97718415,1.0233486)"><tspan
sodipodi:role="line"
id="tspan3075"
x="401.41913"
y="255.32637">L </tspan></text>
<text
xml:space="preserve"
style="font-size:188.40333557px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#a38c25;fill-opacity:1;stroke:none;font-family:Sans"
x="489.90826"
y="262.77887"
id="text3077"
sodipodi:linespacing="125%"
transform="scale(0.97718415,1.0233486)"><tspan
sodipodi:role="line"
id="tspan3079"
x="489.90826"
y="262.77887">y</tspan></text>
<text
xml:space="preserve"
style="font-size:188.40333557px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#a3257a;fill-opacity:1;stroke:none;font-family:Sans"
x="369.58545"
y="282.15436"
id="text3081"
sodipodi:linespacing="125%"
transform="scale(0.97718415,1.0233486)"><tspan
sodipodi:role="line"
id="tspan3083"
x="369.58545"
y="282.15436">L</tspan></text>
</g>
<text
transform="scale(0.97718415,1.0233486)"
sodipodi:linespacing="125%"
id="text3085"
y="343.51309"
x="214.77977"
style="font-size:188.40333557px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
style="font-size:37.68066788px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Liberation Mono;-inkscape-font-specification:Liberation Mono"
y="343.51309"
x="214.77977"
id="tspan3087"
sodipodi:role="line">Polyhedral LLVM</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -0,0 +1 @@
add_subdirectory(polly)

View File

@ -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()

View File

@ -0,0 +1,63 @@
//===- CLooG.h - CLooG interface --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// CLooG[1] interface.
//
// The CLooG interface takes a Scop and generates a CLooG AST (clast). This
// clast can either be returned directly or it can be pretty printed to stdout.
//
// A typical clast output looks like this:
//
// for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) {
// bb2(c2);
// }
//
// [1] http://www.cloog.org/ - The Chunky Loop Generator
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_CLOOG_H
#define POLLY_CLOOG_H
#include "polly/ScopPass.h"
#define CLOOG_INT_GMP 1
#include "cloog/cloog.h"
struct clast_name;
namespace llvm {
class raw_ostream;
}
namespace polly {
class Scop;
class Cloog;
class CloogInfo : public ScopPass {
Cloog *C;
Scop *scop;
public:
static char ID;
CloogInfo() : ScopPass(ID), C(0) {}
/// Write a .cloog input file
void dump(FILE *F);
/// Print a source code representation of the program.
void pprint(llvm::raw_ostream &OS);
/// Create the CLooG AST from this program.
const struct clast_stmt *getClast();
bool runOnScop(Scop &S);
void printScop(llvm::raw_ostream &OS) const;
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
#endif /* POLLY_CLOOG_H */

View File

@ -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 OPENSCOP_FOUND
#cmakedefine SCOPLIB_FOUND
#endif

View File

@ -0,0 +1,28 @@
/* include/polly/Config/config.h.in. Generated from autoconf/configure.ac by autoheader. */
/* Use gmp for isl */
#undef CLOOG_INT_GMP
/* Define if openscop found */
#undef OPENSCOP_FOUND
/* 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
/* Define if scoplib found */
#undef SCOPLIB_FOUND

View File

@ -0,0 +1,79 @@
//===------ polly/Dependences.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_DEPENDENCES_H
#define POLLY_DEPENDENCES_H
#include "polly/ScopPass.h"
#include <map>
struct isl_union_map;
struct isl_union_set;
struct isl_map;
struct isl_set;
using namespace llvm;
namespace polly {
class Scop;
class ScopStmt;
class Dependences : public ScopPass {
isl_union_map *must_dep, *may_dep;
isl_union_map *must_no_source, *may_no_source;
isl_union_map *war_dep;
isl_union_map *waw_dep;
isl_union_map *sink;
isl_union_map *must_source;
isl_union_map *may_source;
public:
static char ID;
typedef std::map<ScopStmt*, isl_map*> StatementToIslMapTy;
Dependences();
bool isValidScattering(StatementToIslMapTy *NewScatterings);
/// @brief Check if a dimension of the Scop can be executed in parallel.
///
/// @param loopDomain The subset of the scattering space that is executed in
/// parallel.
/// @param parallelDimension The scattering dimension that is being executed
/// in parallel.
///
/// @return bool Returns true, if executing parallelDimension in parallel is
/// valid for the scattering domain subset given.
bool isParallelDimension(isl_set *loopDomain, unsigned parallelDimension);
bool runOnScop(Scop &S);
void printScop(raw_ostream &OS) const;
virtual void releaseMemory();
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
};
} // End polly namespace.
#endif

View File

@ -0,0 +1,105 @@
//===- 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 RegionPass;
}
using namespace llvm;
namespace polly {
Pass *createAffSCEVItTesterPass();
Pass *createCloogExporterPass();
Pass *createCloogInfoPass();
Pass *createCodeGenerationPass();
Pass *createCodePreperationPass();
Pass *createDependencesPass();
Pass *createDOTOnlyPrinterPass();
Pass *createDOTOnlyViewerPass();
Pass *createDOTPrinterPass();
Pass *createDOTViewerPass();
Pass *createIndependentBlocksPass();
Pass *createInterchangePass();
Pass *createJSONExporterPass();
Pass *createJSONImporterPass();
Pass *createRegionSimplifyPass();
Pass *createScopInfoPass();
#ifdef OPENSCOP_FOUND
Pass *createScopExporterPass();
Pass *createScopImporterPass();
#endif
#ifdef SCOPLIB_FOUND
Pass *createPoccPass();
Pass *createScopLibExporterPass();
Pass *createScopLibImporterPass();
#endif
extern char &IndependentBlocksID;
extern char &CodePreperationID;
}
using namespace polly;
namespace {
struct PollyForcePassLinking {
PollyForcePassLinking() {
// We must reference the passes in such a way that compilers will not
// delete it all as dead code, even with whole program optimization,
// yet is effectively a NO-OP. As the compiler isn't smart enough
// to know that getenv() never returns -1, this will do the job.
if (std::getenv("bar") != (char*) -1)
return;
createAffSCEVItTesterPass();
createCloogExporterPass();
createCloogInfoPass();
createCodeGenerationPass();
createCodePreperationPass();
createDependencesPass();
createDOTOnlyPrinterPass();
createDOTOnlyViewerPass();
createDOTPrinterPass();
createDOTViewerPass();
createIndependentBlocksPass();
createInterchangePass();
createJSONExporterPass();
createJSONImporterPass();
createRegionSimplifyPass();
createScopInfoPass();
#ifdef OPENSCOP_FOUND
createScopExporterPass();
createScopImporterPass();
#endif
#ifdef SCOPLIB_FOUND
createPoccPass();
createScopLibExporterPass();
createScopLibImporterPass();
#endif
}
} PollyForcePassLinking; // Force link by creating a global definition.
}
#endif

157
polly/include/polly/MayAliasSet.h Executable file
View File

@ -0,0 +1,157 @@
//===- MayAliasSet.h - May-alias Set for Base Pointers ---------*- 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 two classes: MayAliasSet and MayAliasSetInfo.
// MayAliasSet contains the base pointers of access functions in SCoP that
// may/must alias each others. And MayAliasSetInfo will compute and hold these
// MayAliasSets in every SCoP in a function.
//
// The difference between MayAliasSet and the original LLVM AliasSet is that
// the LLVM AliasSets are disjoint, but MayAliasSets are not.
//
// Suppose we have the following LLVM IR:
// define void @f(i32* noalias nocapture %a, i32* noalias nocapture %b)nounwind{
// bb.nph:
// %0 = tail call i32 (...)* @rnd() nounwind
// %1 = icmp eq i32 %0, 0
// %ptr0 = select i1 %1, i32* %b, i32* %a
// %2 = load i32* %ptr0, align 4
// %3 = load i32* %a, align 4
// %4 = load i32* %b, align 4
// ret void
// }
//
// The LLVM AliasSetTracker constructs only one LLVM AliasSet that contains
// ptr0, a and b, but MayAliasSetInfo is supposed to build two MayAliasSets:
// {a, ptr0} and {b, ptr0}.
//
// Take the above LLVM IR for example, the MayAliasSetInfo builds two set:
// A: {a, ptr0} and B: {b, ptr0} and constructs base pointer to MayAliasSet
// mapping like:
// a -> A
// b -> B
// ptr0 -> A, B
//
// After that, SCoPInfo pass will build a access function for each MayAliasSet,
// so "%2 = load i32* %ptr0, align 4" will be translated to "read A" and
// "read B", while "%3 = load i32* %a, align 4" will be translated to "read A",
// and "%4 = load i32* %b, align 4" will be translated to "read B". This means
// we can treat the MayAliasSet as the identifier of the virtual array of memory
// access in SCoPs.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_MAY_ALIAS_SET_H
#define POLLY_MAY_ALIAS_SET_H
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Allocator.h"
#include <map>
namespace llvm {
class Value;
class AliasAnalysis;
class raw_ostream;
}
using namespace llvm;
namespace polly {
class MayAliasSetInfo;
class TempScop;
//===----------------------------------------------------------------------===//
/// @brief MayAliasSet of pointers in SCoPs.
///
/// Note: Pointers in MayAliasSet only must-alias with each other now.
class MayAliasSet {
// DO NOT IMPLEMENT
MayAliasSet(const MayAliasSet &);
// DO NOT IMPLEMENT
const MayAliasSet &operator=(const MayAliasSet &);
// TODO: Use CallbackVH to update the set when some base pointers are deleted
// by some pass.
SmallPtrSet<const Value*, 8> MustAliasPtrs;
MayAliasSet() {}
friend class MayAliasSetInfo;
public:
/// @name Must Alias Pointer Iterators
///
/// These iterators iterate over all must alias pointers in the set.
//@{
typedef SmallPtrSetIterator<const Value*> const_iterator;
const_iterator mustalias_begin() const { return MustAliasPtrs.begin(); }
const_iterator mustalias_end() const { return MustAliasPtrs.end(); }
//@}
/// @brief Add a must alias pointer to this set.
///
/// @param V The pointer to add.
void addMustAliasPtr(const Value* V) { MustAliasPtrs.insert(V); }
void print(raw_ostream &OS) const;
void dump() const;
};
//===----------------------------------------------------------------------===//
/// @brief Compute and manage the may-alias sets in a TempSCoP or SCoP.
class MayAliasSetInfo {
// DO NOT IMPLEMENT
MayAliasSetInfo(const MayAliasSetInfo &);
// DO NOT IMPLEMENT
const MayAliasSetInfo &operator=(const MayAliasSetInfo &);
SpecificBumpPtrAllocator<MayAliasSet> MayASAllocator;
// Mapping the pointers to their may-alias sets.
typedef std::multimap<const Value*, MayAliasSet*> MayAliasSetMapType;
MayAliasSetMapType BasePtrMap;
public:
MayAliasSetInfo() {}
/// @name MayAliasSet Iterators
///
/// These iterators iterate over all may-alias sets referring to a base
/// pointer.
//@{
typedef MayAliasSetMapType::iterator alias_iterator;
typedef MayAliasSetMapType::const_iterator const_alias_iterator;
alias_iterator alias_begin(const Value *BasePtr) {
return BasePtrMap.lower_bound(BasePtr);
}
alias_iterator alias_end(const Value *BasePtr) {
return BasePtrMap.upper_bound(BasePtr);
}
const_alias_iterator alias_begin(const Value *BasePtr) const {
return BasePtrMap.lower_bound(BasePtr);
}
const_alias_iterator alias_end(const Value *BasePtr) const {
return BasePtrMap.upper_bound(BasePtr);
}
//@}
/// @brief Build MayAliasSets in a SCoP.
///
/// @param Scop The SCoP to build MayAliasSets in.
/// @param AA The AliasAnalaysis provides the alias information.
void buildMayAliasSets(TempScop &Scop, AliasAnalysis &AA);
};
}
#endif

View File

@ -0,0 +1,272 @@
//===--- 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 "llvm/Pass.h"
#include "llvm/Analysis/AliasSetTracker.h"
#include <set>
using namespace llvm;
namespace llvm {
class RegionInfo;
class Region;
class LoopInfo;
class Loop;
class ScalarEvolution;
class SCEV;
class SCEVAddRecExpr;
class CallInst;
class Instruction;
class AliasAnalysis;
class Value;
}
namespace polly {
typedef std::set<const SCEV*> ParamSetType;
//===----------------------------------------------------------------------===//
/// @brief Pass to detect the maximal static control parts (Scops) of a
/// function.
class ScopDetection : public FunctionPass {
//===--------------------------------------------------------------------===//
// DO NOT IMPLEMENT
ScopDetection(const ScopDetection &);
// DO NOT IMPLEMENT
const ScopDetection &operator=(const ScopDetection &);
/// @brief Analysis passes used.
//@{
ScalarEvolution* SE;
LoopInfo *LI;
RegionInfo *RI;
AliasAnalysis *AA;
//@}
/// @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?
DetectionContext(Region &R, AliasAnalysis &AA, bool Verify)
: CurRegion(R), AST(AA), Verifying(Verify) {}
};
// Remember the valid regions
typedef std::set<const Region*> RegionSet;
RegionSet ValidRegions;
// 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.
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 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 &I, DetectionContext &Context) const;
/// @brief Check if the BB can be part of a Scop.
///
/// @param BB The basic block to check.
/// @param Context The context of scop detection.
///
/// @return True if the basic block is valid, false otherwise.
bool isValidBasicBlock(BasicBlock &BB, 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 Check if the SCEV expression is a valid affine function
///
/// @param S The SCEV expression to be checked
/// @param RefRegion The reference scope to check SCEV, it help to find out
/// induction variables and parameters
/// @param BasePtr If S represents a memory access, BasePtr should contain
/// a valid memory location to which the base address of the
/// memory access will be stored.
///
/// @return True if the SCEV expression is affine, false otherwise
///
bool isValidAffineFunction(const SCEV *S, Region &RefRegion,
Value **BasePtr = 0) 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 a function is an OpenMP subfunction.
///
/// An OpenMP subfunction is not valid for Scop detection.
///
/// @param F The function to check.
///
/// @return True if the function is not an OpenMP subfunction.
bool isValidFunction(llvm::Function &F);
public:
static char ID;
explicit ScopDetection() : FunctionPass(ID) {}
/// @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.
///
/// @return Return true if R is the maximum Region in a Scop, false otherwise.
bool isMaxRegionInScop(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(); }
//@}
/// @brief Remove a region and its children from valid region set.
///
/// @param R The region to remove.
void forgetScop(const Region &R) {
assert(isMaxRegionInScop(R) && "R is not a Scop!");
ValidRegions.erase(&R);
}
/// @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
#endif

578
polly/include/polly/ScopInfo.h Executable file
View File

@ -0,0 +1,578 @@
//===------ 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 represantation 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 "llvm/Analysis/RegionPass.h"
using namespace llvm;
namespace llvm {
class SCEV;
class ScalarEvolution;
class SCEVAddRecExpr;
class Loop;
class LoopInfo;
class Type;
class PHINode;
}
struct isl_map;
struct isl_basic_map;
struct isl_set;
struct isl_ctx;
struct isl_dim;
struct isl_constraint;
namespace polly {
class Scop;
class ScopStmt;
class ScopInfo;
class TempScop;
class SCEVAffFunc;
class Comparison;
//===----------------------------------------------------------------------===//
/// @brief Represent memory accesses in statements.
class MemoryAccess {
// DO NOT IMPLEMENT
MemoryAccess(const MemoryAccess &);
// DO NOT IMPLEMENT
const MemoryAccess &operator=(const 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 write access
///
/// A certain set of memory locactions 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 locactions 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,
Write,
MayWrite
};
private:
isl_map *AccessRelation;
enum AccessType Type;
const Value* BaseAddr;
std::string BaseName;
isl_basic_map *createBasicAccessMap(ScopStmt *Statement);
void setBaseName();
ScopStmt *statement;
public:
// @brief Create an affine memory access.
//
// @param AffFunc The access function.
// @param Statement The Statement that contains this access.
// @param SE The ScalarEvolution analysis.
MemoryAccess(const SCEVAffFunc &AffFunc, ScopStmt *Statement);
// @brief Create a read all access.
//
// @param BaseAddress The base address of the memory accessed.
// @param Statement The Statement that contains this access.
MemoryAccess(const Value *BaseAddress, ScopStmt *Statement);
~MemoryAccess();
/// @brief Is this a read memory access?
bool isRead() const { return Type == MemoryAccess::Read; }
isl_map *getAccessFunction() { return AccessRelation; }
isl_map *getAccessFunction() const { return AccessRelation; }
/// @brief Get an isl string representing this access function.
std::string getAccessFunctionStr() const;
const Value *getBaseAddr() const {
return BaseAddr;
}
const std::string &getBaseName() const {
return BaseName;
}
/// @brief Get the stride of this memory access in the specified domain
/// subset.
isl_set *getStride(const isl_set *domainSubset) const;
/// @brief Is consecutive memory accessed for a given
/// statement instance set?
bool isStrideOne(const isl_set *domainSubset) const;
/// @brief Is always the same memory accessed for a given
/// statement instance set?
bool isStrideZero(const isl_set *domainSubset) const;
/// @brief Get the statement that contains this memory access.
ScopStmt *getStatement() const { return statement; }
/// @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;
};
//===----------------------------------------------------------------------===//
/// @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 {
//===-------------------------------------------------------------------===//
// DO NOT IMPLEMENT
ScopStmt(const ScopStmt &);
// DO NOT IMPLEMENT
const ScopStmt &operator=(const ScopStmt &);
/// 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 statment and iteration vector (S, (5,3)) is called statment
/// instance.
isl_set *Domain;
/// The scattering map describes the execution order of the statement
/// instances.
///
/// A statement and its iteration domain do not give any information about the
/// order in time in which the different statement instances are executed.
/// This information is provided by the scattering.
///
/// The scattering maps every instance of each statement into a multi
/// dimensional scattering space. This space can be seen as a multi
/// dimensional clock.
///
/// Example:
///
/// <S,(5,4)> may be mapped to (5,4) by this scattering:
///
/// s0 = i (Year of execution)
/// s1 = j (Day of execution)
///
/// or to (9, 20) by this scattering:
///
/// s0 = i + j (Year of execution)
/// s1 = 20 (Day of execution)
///
/// The order statement instances are executed is defined by the
/// scattering vectors they are mapped to. A statement instance
/// <A, (i, j, ..)> is executed before a statement instance <B, (i', ..)>, if
/// the scattering vector of A is lexicographic smaller than the scattering
/// vector of B.
isl_map *Scattering;
/// The memory accesses of this statement.
///
/// The only side effects of a statement are its memory accesses.
typedef SmallVector<MemoryAccess*, 8> MemoryAccessVec;
MemoryAccessVec MemAccs;
std::map<const Instruction*, MemoryAccess*> InstructionToAccess;
//@}
/// The BasicBlock represented by this statement.
BasicBlock *BB;
/// @brief Whether this statement is a reduction.
bool IsReduction;
/// @brief The loop induction variables surrounding the statement.
///
/// This information is only needed for final code generation.
std::vector<PHINode*> IVS;
std::string BaseName;
/// Build the statment.
//@{
isl_set *toUpperLoopBound(const SCEVAffFunc &UpperBound, isl_dim *dim,
unsigned BoundedDimension) const;
isl_set *toConditionSet(const Comparison &Cmp, isl_dim *dim) const;
void addConditionsToDomain(TempScop &tempScop, const Region &CurRegion);
void buildIterationDomainFromLoops(TempScop &tempScop);
void buildIterationDomain(TempScop &tempScop, const Region &CurRegion);
void buildScattering(SmallVectorImpl<unsigned> &Scatter);
void buildAccesses(TempScop &tempScop, const Region &CurRegion);
//@}
/// Create the ScopStmt from a BasicBlock.
ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
BasicBlock &bb, SmallVectorImpl<Loop*> &NestLoops,
SmallVectorImpl<unsigned> &Scatter);
/// Create the finalization statement.
ScopStmt(Scop &parent, SmallVectorImpl<unsigned> &Scatter);
friend class Scop;
public:
~ScopStmt();
/// @brief Get an isl_ctx pointer.
isl_ctx *getIslContext();
/// @brief Get the iteration domain of this ScopStmt.
///
/// @return The iteration domain of this ScopStmt.
isl_set *getDomain() const { return Domain; }
/// @brief Get an isl string representing this domain.
std::string getDomainStr() const;
/// @brief Get the scattering function of this ScopStmt.
///
/// @return The scattering function of this ScopStmt.
isl_map *getScattering() const { return Scattering; }
void setScattering(isl_map *scattering) { Scattering = scattering; }
/// @brief Get an isl string representing this scattering.
std::string getScatteringStr() const;
/// @brief Get the BasicBlock represented by this ScopStmt.
///
/// @return The BasicBlock represented by this ScopStmt.
BasicBlock *getBasicBlock() const { return BB; }
MemoryAccess &getAccessFor(const Instruction *Inst) {
return *InstructionToAccess[Inst];
}
void setBasicBlock(BasicBlock *Block) { BB = Block; }
typedef MemoryAccessVec::iterator memacc_iterator;
memacc_iterator memacc_begin() { return MemAccs.begin(); }
memacc_iterator memacc_end() { return MemAccs.end(); }
unsigned getNumParams() const;
unsigned getNumIterators() const;
unsigned getNumScattering() const;
Scop *getParent() { return &Parent; }
const Scop *getParent() const { return &Parent; }
const char *getBaseName() const;
/// @brief Get the induction variable for a dimension.
///
/// @param Dimension The dimension of the induction variable
/// @return The induction variable at a certain dimension.
const PHINode *getInductionVariableForDimension(unsigned Dimension) const;
/// @brief Return the SCEV for a loop dimension.
const SCEVAddRecExpr *getSCEVForDimension(unsigned Dimension) const;
/// @brief Is this statement the final read statement?
///
/// A final read statement is scheduled after all statements to model
/// that all data used in the Scop is read after the Scop.
bool isFinalRead() { return getBasicBlock() == NULL; }
bool isReduction() { return IsReduction; }
/// @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 {
//===-------------------------------------------------------------------===//
// DO NOT IMPLEMENT
Scop(const Scop &);
// DO NOT IMPLEMENT
const Scop &operator=(const Scop &);
ScalarEvolution *SE;
/// The underlying Region.
Region &R;
/// Max loop depth.
unsigned MaxLoopDepth;
typedef std::vector<ScopStmt*> StmtSet;
/// The Statments in this Scop.
StmtSet Stmts;
/// Parameters of this Scop
typedef SmallVector<const SCEV*, 8> ParamVecType;
ParamVecType Parameters;
/// Constraints on parameters.
isl_set *Context;
/// 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);
/// @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);
/// Build the Scop and Statement with precalculate scop information.
void buildScop(TempScop &TempScop, const Region &CurRegion,
// Loops in Scop containing CurRegion
SmallVectorImpl<Loop*> &NestLoops,
// The scattering numbers
SmallVectorImpl<unsigned> &Scatter,
LoopInfo &LI);
/// Helper function for printing the Scop.
void printContext(raw_ostream &OS) const;
void printStatements(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; }
/// @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 Get the scattering dimension number of this Scop.
///
/// @return The scattering dimension number of this Scop.
inline unsigned getScatterDim() const {
unsigned maxScatterDim = 0;
for (const_iterator SI = begin(), SE = end(); SI != SE; ++SI)
maxScatterDim = std::max(maxScatterDim, (*SI)->getNumScattering());
return maxScatterDim;
}
/// @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.
inline isl_set *getContext() const { return Context; }
/// @brief Get an isl string representing the context.
std::string getContextStr() const;
/// @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 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 *getCtx() const;
};
/// @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 {
//===-------------------------------------------------------------------===//
// DO NOT IMPLEMENT
ScopInfo(const ScopInfo &);
// DO NOT IMPLEMENT
const ScopInfo &operator=(const ScopInfo &);
// The Scop
Scop *scop;
void clear() {
if (scop) {
delete scop;
scop = 0;
}
}
public:
static char ID;
explicit ScopInfo() : RegionPass(ID), scop(0) {}
~ScopInfo() { clear(); }
/// @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
#endif

View File

@ -0,0 +1,70 @@
//===- ScopLib.h - ScopLib interface ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Scoplib interface.
//
// The scoplib interface allows to import/export a scop using scoplib.
//===----------------------------------------------------------------------===//
#ifndef POLLY_SCOPLIB_H
#define POLLY_SCOPLIB_H
#define SCOPLIB_INT_T_IS_MP
#include "scoplib/scop.h"
#include <map>
namespace llvm {
class Value;
}
struct isl_constraint;
struct isl_basic_map;
struct isl_basic_set;
struct isl_map;
struct isl_set;
namespace polly {
class Dependences;
class ScopStmt;
class Scop;
class ScopLib {
Scop *PollyScop;
scoplib_scop_p scoplib;
Dependences *D;
std::map<const llvm::Value*, int> ArrayMap;
void initializeArrays();
void initializeParameters();
void initializeScattering();
void initializeStatements();
scoplib_statement_p initializeStatement(ScopStmt *stmt);
void freeStatement(scoplib_statement_p stmt);
static int accessToMatrix_constraint(isl_constraint *c, void *user);
static int accessToMatrix_basic_map(isl_basic_map *bmap, void *user);
scoplib_matrix_p createAccessMatrix(ScopStmt *S, bool isRead);
static int domainToMatrix_constraint(isl_constraint *c, void *user);
static int domainToMatrix_basic_set(isl_basic_set *bset, void *user);
scoplib_matrix_p domainToMatrix(isl_set *PS);
static int scatteringToMatrix_constraint(isl_constraint *c, void *user);
static int scatteringToMatrix_basic_map(isl_basic_map *bmap, void *user);
scoplib_matrix_p scatteringToMatrix(isl_map *pmap);
public:
ScopLib(Scop *S);
ScopLib(Scop *S, FILE *F, Dependences *D);
~ScopLib();
void print(FILE *F);
bool updateScattering();
};
}
#endif /* POLLY_SCOPLIB_H */

64
polly/include/polly/ScopPass.h Executable file
View File

@ -0,0 +1,64 @@
//===--------- 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;
/// getAnalysisUsage - Subclasses that override getAnalysisUsage
/// must call this.
///
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
public:
/// getIslContext - Get the isl_ctx of current SCoP.
isl_ctx *getIslContext();
Scop &getCurScop() const {
assert(S && "Not on a Scop!");
return *S;
}
private:
virtual bool runOnRegion(Region *R, RGPassManager &RGM);
void print(raw_ostream &OS, const Module *) const;
virtual void printScop(raw_ostream &OS) const {}
};
} // End llvm namespace
#endif

View File

@ -0,0 +1,292 @@
//===-- AffineSCEVIterator.h - Iterate the SCEV in an affine way -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// The iterator can be used to iterate over the affine component of the SCEV
// expression.
//
//===----------------------------------------------------------------------===//
#ifndef AFFINE_SCEV_ITERATOR_H
#define AFFINE_SCEV_ITERATOR_H
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include <map>
#include "llvm/ADT/SmallVector.h"
using namespace llvm;
namespace polly {
/// @brief The itertor transform the scalar expressions to the form of sum of
/// (constant * varialbe)s, and return the variable/constant pairs one by one
/// on the fly.
///
/// For example, we can write SCEV:
/// {{%x,+,sizeof(i32)}<%bb2.preheader>,+,(4 * sizeof(i32))}<%bb1>
/// in affine form:
/// (4 * sizeof(i32)) * %indvar + sizeof(i32) * %0 + 1 * %x + 0 * 1
/// so we can get the follow pair from the iterator:
/// {%indvar, (4 * sizeof(i32))}, {%0, sizeof(i32)}, {%x, 1} and {1, 0}
/// where %indvar is the induction variable of loop %bb1 and %0 is the induction
/// variable of loop %bb2.preheader.
///
/// In the returned pair,
/// The "first" field is the variable part, the "second" field constant part.
/// And the translation part of the expression will always return last.
///
class AffineSCEVIterator : public std::iterator<std::forward_iterator_tag,
std::pair<const SCEV*, const SCEV*>, ptrdiff_t>,
SCEVVisitor<AffineSCEVIterator,
std::pair<const SCEV*, const SCEV*> >
{
typedef std::iterator<std::forward_iterator_tag,
std::pair<const SCEV*, const SCEV*>, ptrdiff_t> super;
friend struct llvm::SCEVVisitor<AffineSCEVIterator,
std::pair<const SCEV*, const SCEV*> >;
ScalarEvolution *SE;
public:
typedef super::value_type value_type;
typedef super::pointer ptr_type;
typedef AffineSCEVIterator Self;
private:
typedef SCEVNAryExpr::op_iterator scev_op_it;
// The stack help us remember the SCEVs that not visit yet.
SmallVector<const SCEV*, 8> visitStack;
// The current value of this iterator.
value_type val;
const SCEVConstant* getSCEVOne(const SCEV* S) const {
return cast<SCEVConstant>(SE->getConstant(S->getType(), 1));
}
//===-------------------------------------------------------------------===//
/// Functions for SCEVVisitor.
///
/// These function compute the constant part and variable part of the SCEV,
/// and return them in a std::pair, where the first field is the variable,
/// and the second field is the constant.
///
value_type visitConstant(const SCEVConstant *S) {
return std::make_pair(getSCEVOne(S), S);
}
value_type visitUnknown(const SCEVUnknown* S) {
const Type *AllocTy;
Constant *FieldNo;
// We treat these as constant.
if (S->isSizeOf (AllocTy) ||
S->isAlignOf (AllocTy) ||
S->isOffsetOf(AllocTy, FieldNo))
return std::make_pair(getSCEVOne(S), S);
return std::make_pair(S, getSCEVOne(S));
}
value_type visitMulExpr(const SCEVMulExpr* S) {
SmallVector<const SCEV*, 4> Coeffs, Variables;
// Do not worry about the Constant * Variable * (Variable + Variable)
// MulExpr, we will never get a affine expression from it, so we just
// leave it there.
for (scev_op_it I = S->op_begin(), E = S->op_end(); I != E; ++I) {
// Get the constant part and the variable part of each operand.
value_type res = visit(*I);
Coeffs.push_back(res.second);
Variables.push_back(res.first);
}
// Get the constant part and variable part of this MulExpr by
// multiply them together.
const SCEV *Coeff = SE->getMulExpr(Coeffs);
// There maybe "sizeof" and others.
// TODO: Assert the allowed coeff type.
// assert(Coeff && "Expect Coeff to be a const!");
const SCEV *Var = SE->getMulExpr(Variables);
return std::make_pair(Var, Coeff);
}
value_type visitCastExpr(const SCEVCastExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
value_type visitTruncateExpr(const SCEVTruncateExpr *S) {
return visitCastExpr(S);
}
value_type visitZeroExtendExpr(const SCEVZeroExtendExpr *S) {
return visitCastExpr(S);
}
value_type visitSignExtendExpr(const SCEVSignExtendExpr *S) {
return visitCastExpr(S);
}
value_type visitAddExpr(const SCEVAddExpr *S) {
// AddExpr will handled out in visit Next;
return std::make_pair(S, getSCEVOne(S));
}
value_type visitAddRecExpr(const SCEVAddRecExpr *S) {
// AddRecExpr will handled out in visit Next;
return std::make_pair(S, getSCEVOne(S));
}
value_type visitUDivExpr(const SCEVUDivExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
value_type visitSMaxExpr(const SCEVSMaxExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
value_type visitUMaxExpr(const SCEVUMaxExpr *S) {
return std::make_pair(S, getSCEVOne(S));
}
/// Get the next {variable, constant} pair of the SCEV.
value_type visitNext() {
value_type ret(0, 0);
if (visitStack.empty())
return ret;
const SCEV* nextS = visitStack.back();
if (const SCEVAddRecExpr *ARec = dyn_cast<SCEVAddRecExpr>(nextS)){
// Visiting the AddRec, check if its Affine;
PHINode *IV = ARec->getLoop()->getCanonicalInductionVariable();
// Only decompose the AddRec, if the loop has a canonical induction
// variable.
if (ARec->isAffine() && IV != 0) {
ret = visit(ARec->getStepRecurrence(*SE));
if (isa<SCEVConstant>(ret.first)) { // If the step is constant.
const SCEV *Start = ARec->getStart();
visitStack.back() = Start;
// The AddRec is expect to be decomposed to
//
// | start + step * {1, +, 1}<loop>
//
// Now we get the {1, +, 1}<loop> part.
ret.first = SE->getSCEV(IV);
// Push CouldNotCompute to take the place.
visitStack.push_back(SE->getCouldNotCompute());
return ret;
}
// The step is not a constant. Then this AddRec is not Affine or
// no canonical induction variable found.
// Fall through.
}
}
// Get the constant part and variable part of the SCEV.
ret = visit(nextS);
// If the reach the last constant
if (isa<SCEVConstant>(ret.first) && (visitStack.size() != 1)) {
// Else, merge all constant component, we will output it at last.
visitStack.front() = SE->getAddExpr(visitStack.front(), ret.second);
//assert(isa<SCEVConstant>(visitStack.front().first));
// Pop the top constant, because it already merged into the bottom of the Stack
// and output it last.
visitStack.pop_back();
// Try again.
return visitNext();
}
// Not a constant or Stack not empty
// If ret is in (xxx) * AddExpr form, we will decompose the AddExpr
else if (const SCEVAddExpr *AddExpr = dyn_cast<SCEVAddExpr>(ret.first)) {
// Pop the current SCEV, we will decompose it.
visitStack.pop_back();
assert(AddExpr->getNumOperands() && "AddExpr without operand?");
for (scev_op_it I = AddExpr->op_begin(), E = AddExpr->op_end(); I != E; ++I){
visitStack.push_back(SE->getMulExpr(ret.second, *I));
}
// Try again with the new SCEV.
return visitNext();
}
return ret;
}
public:
/// @brief Create the iterator from a SCEV and the ScalarEvolution analysis.
AffineSCEVIterator(const SCEV* S, ScalarEvolution *se ) : SE(se) {
// Dont iterate CouldNotCompute.
if (isa<SCEVCouldNotCompute>(S))
return;
const Type *Ty = S->getType();
// Init the constant component.
visitStack.push_back(SE->getConstant(Ty, 0));
// Get the first affine component.
visitStack.push_back(S);
val = visitNext();
}
/// @brief Create an end iterator.
inline AffineSCEVIterator() {}
inline bool operator==(const Self& x) const {
return visitStack == x.visitStack;
}
inline bool operator!=(const Self& x) const { return !operator==(x); }
/// @brief Return the current (constant * variable) component of the SCEV.
///
/// @return The "first" field of the pair is the variable part,
/// the "second" field of the pair is the constant part.
inline value_type operator*() const {
assert(val.first && val.second && "Cant dereference iterator!");
return val;
}
inline const value_type* operator->() const {
assert(val.first && val.second && "Cant dereference iterator!");
return &val;
}
inline Self& operator++() { // Preincrement
assert(!visitStack.empty() && "Cant ++ iterator!");
// Pop the last SCEV.
visitStack.pop_back();
val = visitNext();
return *this;
}
inline Self operator++(int) { // Postincrement
Self tmp = *this; ++*this; return tmp;
}
};
inline static AffineSCEVIterator affine_begin(const SCEV* S, ScalarEvolution *SE) {
return AffineSCEVIterator(S, SE);
}
inline static AffineSCEVIterator affine_end() {
return AffineSCEVIterator();
}
} // end namespace polly
#endif

View File

@ -0,0 +1,47 @@
//===- Support/GICHelper.h -- Helper functions for GMP, ISL, and Cloog -----===/
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Helper functions for gmp, isl and Cloog objects.
//
//===----------------------------------------------------------------------===//
//
#ifndef POLLY_SUPPORT_GIC_HELPER_H
#define POLLY_SUPPORT_GIC_HELPER_H
#include "llvm/ADT/APInt.h"
#include <gmp.h>
struct isl_map;
struct isl_union_map;
struct isl_set;
struct isl_union_set;
namespace polly {
/// @brief Convert APInt to mpz.
///
/// @param v The mpz_t object your want to hold the result.
/// @param apint The APInt you want to convert.
void MPZ_from_APInt (mpz_t v, const llvm::APInt apint, bool is_signed = true);
/// @brief Convert mpz to APInt.
///
/// @param mpz The mpz_t you want to convert.
llvm::APInt APInt_from_MPZ (const mpz_t mpz);
/// @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);
//@}
} //end namespace polly
#endif

View File

@ -0,0 +1,86 @@
//===------ 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 Instruction;
class LoopInfo;
class Loop;
class ScalarEvolution;
class SCEV;
class Value;
class PHINode;
class Region;
class Pass;
class BasicBlock;
}
namespace polly {
// Helper function for 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);
//===----------------------------------------------------------------------===//
// Functions for checking affine functions.
bool isInvariant(const llvm::SCEV *S, llvm::Region &R);
bool isParameter(const llvm::SCEV *Var, llvm::Region &RefRegion,
llvm::LoopInfo &LI, llvm::ScalarEvolution &SE);
bool isIndVar(const llvm::SCEV *Var, llvm::Region &RefRegion,
llvm::LoopInfo &LI, llvm::ScalarEvolution &SE);
/// @brief Check if the instruction I is the induction variable of a loop.
///
/// @param I The instruction to check.
/// @param LI The LoopInfo analysis.
///
/// @return Return true if I is the induction variable of a loop, false
/// otherwise.
bool isIndVar(const llvm::Instruction *I, const 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);
// Helper function for LLVM-IR about Scop.
llvm::BasicBlock *createSingleEntryEdge(llvm::Region *R, llvm::Pass *P);
llvm::BasicBlock *createSingleExitEdge(llvm::Region *R, 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

View File

@ -0,0 +1,388 @@
//===-------- 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/MayAliasSet.h"
#include "polly/ScopDetection.h"
#include "llvm/Analysis/RegionPass.h"
#include "llvm/Instructions.h"
namespace llvm {
class TargetData;
}
using namespace llvm;
namespace polly {
class MayAliasSetInfo;
//===---------------------------------------------------------------------===//
/// @brief Affine function represent in llvm SCEV expressions.
///
/// A helper class for collect affine function information
class SCEVAffFunc {
// Temporary hack
friend class TempScopInfo;
// The translation component
const SCEV *TransComp;
// { Variable, Coefficient }
typedef std::map<const SCEV*, const SCEV*> LnrTransSet;
LnrTransSet LnrTrans;
public:
// The type of the scev affine function
enum SCEVAffFuncType {
None = 0,
ReadMem, // Or we could call it "Use"
WriteMem, // Or define
Eq, // == 0
Ne, // != 0
GE // >= 0
};
private:
// The base address of the address SCEV, if the Value is a pointer, this is
// an array access, otherwise, this is a value access.
// And the Write/Read modifier
Value *BaseAddr;
unsigned ElemBytes : 28;
SCEVAffFuncType FuncType : 3;
bool has_sign : 1;
public:
/// @brief Create a new SCEV affine function.
SCEVAffFunc() : TransComp(0), BaseAddr(0), ElemBytes(0), FuncType(None),
has_sign(true) {}
/// @brief Create a new SCEV affine function with memory access type or
/// condition type
explicit SCEVAffFunc(SCEVAffFuncType Type, unsigned elemBytes = 0,
Value* baseAddr = 0)
: TransComp(0), BaseAddr(baseAddr), ElemBytes(elemBytes),
FuncType(Type), has_sign(true) {}
/// @brief Construct a new SCEVAffFunc from a SCEV
///
/// @param S The SCEV that should be translated.
/// @param Type The type of this affine function.
/// @param R The region in which the affine function is evaluated.
/// @param Param A set of parameters, where new parameters found in this
/// affine function will be added.
/// @param LI A pointer to a current LoopInfo analysis.
/// @param SE A pointer to a current ScalarEvolution analysis.
SCEVAffFunc(const SCEV *S, SCEVAffFuncType Type, Region &R,
ParamSetType &Param, LoopInfo *LI, ScalarEvolution *SE);
void setUnsigned() {has_sign = false;}
// getCoeff - Get the Coefficient of a given variable.
const SCEV *getCoeff(const SCEV *Var) const {
LnrTransSet::const_iterator At = LnrTrans.find(Var);
return At == LnrTrans.end() ? 0 : At->second;
}
const SCEV *getTransComp() const {
return TransComp;
}
bool isSigned() const { return has_sign; }
enum SCEVAffFuncType getType() const { return FuncType; }
bool isDataRef() const {
return getType() == ReadMem || getType() == WriteMem;
}
unsigned getElemSizeInBytes() const {
assert(isDataRef() && "getElemSizeInBytes on the wrong type!");
return ElemBytes;
}
bool isRead() const { return FuncType == ReadMem; }
const Value *getBaseAddr() const { return BaseAddr; }
/// @brief Print the affine function.
///
/// @param OS The output stream the affine function is printed to.
void print(raw_ostream &OS, bool PrintInequality = true) const;
void dump() const;
};
static inline raw_ostream& operator<<(raw_ostream &OS, const SCEVAffFunc &SAF){
SAF.print(OS);
return OS;
}
class Comparison {
SCEVAffFunc *LHS;
SCEVAffFunc *RHS;
ICmpInst::Predicate Pred;
public:
Comparison(SCEVAffFunc *lhs, SCEVAffFunc *rhs, ICmpInst::Predicate pred)
: LHS(lhs), RHS(rhs), Pred(pred) {}
SCEVAffFunc *getLHS() const { return LHS; }
SCEVAffFunc *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*, SCEVAffFunc> LoopBoundMapType;
/// Mapping BBs to its condition constrains
typedef std::map<const BasicBlock*, BBCond> BBCondMapType;
typedef std::vector<std::pair<SCEVAffFunc, 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;
// Parameters used in this Scop.
ParamSetType Params;
// The max loop depth of this Scop
unsigned MaxLoopDepth;
// Remember the bounds of loops, to help us build iteration domain of BBs.
const LoopBoundMapType &LoopBounds;
const BBCondMapType &BBConds;
// Access function of bbs.
const AccFuncMapType &AccFuncMap;
// The alias information about this SCoP.
MayAliasSetInfo *MayASInfo;
// Basic blocks detected as reductions
std::set<BasicBlock*> Reductions;
friend class TempScopInfo;
explicit TempScop(Region &r, LoopBoundMapType &loopBounds,
BBCondMapType &BBCmps, AccFuncMapType &accFuncMap)
: R(r), MaxLoopDepth(0), LoopBounds(loopBounds), BBConds(BBCmps),
AccFuncMap(accFuncMap), MayASInfo(new MayAliasSetInfo()) {}
public:
~TempScop();
bool is_Reduction(BasicBlock &BB) { return Reductions.count(&BB) != 0; }
/// @name Information about this Temporary Scop.
///
//@{
/// @brief Get the parameters used in this Scop.
///
/// @return The parameters use in region.
ParamSetType &getParamSet() { return Params; }
/// @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 maximum loop depth of Region R.
///
/// @return The maximum loop depth of Region R.
unsigned getMaxLoopDepth() const { return MaxLoopDepth; }
/// @brief Get the loop bounds of the given loop.
///
/// @param L The loop to get the bounds.
///
/// @return The bounds of the loop L in { Lower bound, Upper bound } form.
///
const SCEVAffFunc &getLoopBound(const Loop *L) const {
LoopBoundMapType::const_iterator at = LoopBounds.find(L);
assert(at != LoopBounds.end() && "Only valid loop is allow!");
return at->second;
}
/// @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
///
const AccFuncSetType *getAccessFunctions(const BasicBlock* BB) const {
AccFuncMapType::const_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 {
//===-------------------------------------------------------------------===//
// DO NOT IMPLEMENT
TempScopInfo(const TempScopInfo &);
// DO NOT IMPLEMENT
const TempScopInfo &operator=(const TempScopInfo &);
// 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.
TargetData *TD;
// Remember the bounds of loops, to help us build iteration domain of BBs.
LoopBoundMapType LoopBounds;
// And also Remember the constrains for BBs
BBCondMapType BBConds;
// Access function of bbs.
AccFuncMapType AccFuncMap;
// Mapping regions to the corresponding Scop in current function.
TempScopMapType TempScops;
// Clear the context.
void clear();
/// @brief Build an affine function from a SCEV expression.
///
/// @param S The SCEV expression to be converted to affine
/// function.
/// @param Scop The Scope of this expression.
/// @param FuncToBuild The SCEVAffFunc to hold the result.
///
void buildAffineFunction(const SCEV *S, SCEVAffFunc &FuncToBuild,
Region &R, ParamSetType &Params) const;
/// @brief Build condition constrains to BBs in a valid Scop.
///
/// @param BB The BasicBlock to build condition constrains
/// @param RegionEntry The entry block of the Smallest Region that containing
/// BB
/// @param Cond The built condition
void buildCondition(BasicBlock *BB, BasicBlock *Region, TempScop &Scop);
// Build the affine function of the given condition
void buildAffineCondition(Value &V, bool inverted, Comparison **Comp,
TempScop &Scop) const;
// 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);
bool isReduction(BasicBlock &BB);
void buildAccessFunctions(Region &RefRegion, ParamSetType &Params,
BasicBlock &BB);
void buildLoopBounds(TempScop &Scop);
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
#endif

View File

@ -0,0 +1,8 @@
add_polly_library(PollyAnalysis
Dependences.cpp
ScopDetection.cpp
ScopInfo.cpp
ScopGraphPrinter.cpp
ScopPass.cpp
TempScopInfo.cpp
)

View File

@ -0,0 +1,414 @@
//===- Dependency.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/Dependences.h"
#include "polly/LinkAllPasses.h"
#include "polly/ScopInfo.h"
#include "polly/Support/GICHelper.h"
#define DEBUG_TYPE "polly-dependences"
#include "llvm/Support/Debug.h"
#include "llvm/Support/CommandLine.h"
#include <isl/flow.h>
#include <isl/map.h>
#include <isl/constraint.h>
using namespace polly;
using namespace llvm;
static cl::opt<bool>
LegalityCheckDisabled("disable-polly-legality",
cl::desc("Disable polly legality check"), cl::Hidden,
cl::init(false));
//===----------------------------------------------------------------------===//
Dependences::Dependences() : ScopPass(ID) {
must_dep = may_dep = NULL;
must_no_source = may_no_source = NULL;
sink = must_source = may_source = NULL;
war_dep = waw_dep = NULL;
}
bool Dependences::runOnScop(Scop &S) {
isl_dim *dim = isl_dim_alloc(S.getCtx(), S.getNumParams(), 0, 0);
if (sink)
isl_union_map_free(sink);
if (must_source)
isl_union_map_free(must_source);
if (may_source)
isl_union_map_free(may_source);
sink = isl_union_map_empty(isl_dim_copy(dim));
must_source = isl_union_map_empty(isl_dim_copy(dim));
may_source = isl_union_map_empty(isl_dim_copy(dim));
isl_union_map *schedule = isl_union_map_empty(dim);
if (must_dep)
isl_union_map_free(must_dep);
if (may_dep)
isl_union_map_free(may_dep);
if (must_no_source)
isl_union_map_free(must_no_source);
if (may_no_source)
isl_union_map_free(may_no_source);
if (war_dep)
isl_union_map_free(war_dep);
if (waw_dep)
isl_union_map_free(waw_dep);
must_dep = may_dep = NULL;
must_no_source = may_no_source = NULL;
war_dep = waw_dep = NULL;
for (Scop::iterator SI = S.begin(), SE = S.end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
for (ScopStmt::memacc_iterator MI = Stmt->memacc_begin(),
ME = Stmt->memacc_end(); MI != ME; ++MI) {
isl_set *domcp = isl_set_copy(Stmt->getDomain());
isl_map *accdom = isl_map_copy((*MI)->getAccessFunction());
accdom = isl_map_intersect_domain(accdom, domcp);
if ((*MI)->isRead())
isl_union_map_add_map(sink, accdom);
else
isl_union_map_add_map(must_source, accdom);
}
isl_map *scattering = isl_map_copy(Stmt->getScattering());
isl_union_map_add_map(schedule, scattering);
}
DEBUG(
dbgs().indent(4) << "Sink:\n";
dbgs().indent(8) << stringFromIslObj(sink) << "\n";
dbgs().indent(4) << "MustSource:\n";
dbgs().indent(8) << stringFromIslObj(must_source) << "\n";
dbgs().indent(4) << "MaySource:\n";
dbgs().indent(8) << stringFromIslObj(may_source) << "\n";
dbgs().indent(4) << "Schedule:\n";
dbgs().indent(8) << stringFromIslObj(schedule) << "\n";
);
isl_union_map_compute_flow(isl_union_map_copy(sink),
isl_union_map_copy(must_source),
isl_union_map_copy(may_source),
isl_union_map_copy(schedule),
&must_dep, &may_dep, &must_no_source,
&may_no_source);
isl_union_map_compute_flow(isl_union_map_copy(must_source),
isl_union_map_copy(must_source),
isl_union_map_copy(sink), schedule,
&waw_dep, &war_dep, NULL, NULL);
// Remove redundant statements.
must_dep = isl_union_map_coalesce(must_dep);
may_dep = isl_union_map_coalesce(may_dep);
must_no_source = isl_union_map_coalesce(must_no_source);
may_no_source = isl_union_map_coalesce(may_no_source);
waw_dep = isl_union_map_coalesce(waw_dep);
war_dep = isl_union_map_coalesce(war_dep);
return false;
}
bool Dependences::isValidScattering(StatementToIslMapTy *NewScattering) {
Scop &S = getCurScop();
if (LegalityCheckDisabled)
return true;
isl_dim *dim = isl_dim_alloc(S.getCtx(), S.getNumParams(), 0, 0);
isl_union_map *schedule = isl_union_map_empty(dim);
for (Scop::iterator SI = S.begin(), SE = S.end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
isl_map *scattering;
if (NewScattering->find(*SI) == NewScattering->end())
scattering = isl_map_copy(Stmt->getScattering());
else
scattering = isl_map_copy((*NewScattering)[Stmt]);
isl_union_map_add_map(schedule, scattering);
}
isl_union_map *temp_must_dep, *temp_may_dep;
isl_union_map *temp_must_no_source, *temp_may_no_source;
DEBUG(
dbgs().indent(4) << "Sink :=\n";
dbgs().indent(8) << stringFromIslObj(sink) << ";\n";
dbgs().indent(4) << "MustSource :=\n";
dbgs().indent(8) << stringFromIslObj(must_source) << ";\n";
dbgs().indent(4) << "MaySource :=\n";
dbgs().indent(8) << stringFromIslObj(may_source) << ";\n";
dbgs().indent(4) << "Schedule :=\n";
dbgs().indent(8) << stringFromIslObj(schedule) << ";\n";
);
isl_union_map_compute_flow(isl_union_map_copy(sink),
isl_union_map_copy(must_source),
isl_union_map_copy(may_source), schedule,
&temp_must_dep, &temp_may_dep,
&temp_must_no_source, &temp_may_no_source);
DEBUG(dbgs().indent(4) << "\nDependences calculated\n");
DEBUG(
dbgs().indent(4) << "TempMustDep:=\n";
dbgs().indent(8) << stringFromIslObj(temp_must_dep) << ";\n";
dbgs().indent(4) << "MustDep:=\n";
dbgs().indent(8) << stringFromIslObj(must_dep) << ";\n";
);
// Remove redundant statements.
temp_must_dep = isl_union_map_coalesce(temp_must_dep);
temp_may_dep = isl_union_map_coalesce(temp_may_dep);
temp_must_no_source = isl_union_map_coalesce(temp_must_no_source);
temp_may_no_source = isl_union_map_coalesce(temp_may_no_source);
if (!isl_union_map_is_equal(temp_must_dep, must_dep)) {
DEBUG(dbgs().indent(4) << "\nEqual 1 calculated\n");
return false;
}
DEBUG(dbgs().indent(4) << "\nEqual 1 calculated\n");
if (!isl_union_map_is_equal(temp_may_dep, may_dep))
return false;
DEBUG(dbgs().indent(4) << "\nEqual 2 calculated\n");
if (!isl_union_map_is_equal(temp_must_no_source, must_no_source))
return false;
if (!isl_union_map_is_equal(temp_may_no_source, may_no_source))
return false;
return true;
}
isl_union_map* getCombinedScheduleForDim(Scop *scop, unsigned dimLevel) {
isl_dim *dim = isl_dim_alloc(scop->getCtx(), scop->getNumParams(), 0, 0);
isl_union_map *schedule = isl_union_map_empty(dim);
for (Scop::iterator SI = scop->begin(), SE = scop->end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
isl_map *scattering = isl_map_copy(Stmt->getScattering());
unsigned remainingDimensions = isl_map_n_out(scattering) - dimLevel;
scattering = isl_map_project_out(scattering, isl_dim_out, dimLevel,
remainingDimensions);
isl_union_map_add_map(schedule, scattering);
}
return schedule;
}
bool Dependences::isParallelDimension(isl_set *loopDomain,
unsigned parallelDimension) {
Scop *S = &getCurScop();
isl_union_map *schedule = getCombinedScheduleForDim(S, parallelDimension);
// Calculate distance vector.
isl_union_set *scheduleSubset;
isl_union_map *scheduleDeps, *restrictedDeps;
isl_union_map *scheduleDeps_war, *restrictedDeps_war;
isl_union_map *scheduleDeps_waw, *restrictedDeps_waw;
scheduleSubset = isl_union_set_from_set(isl_set_copy(loopDomain));
scheduleDeps = isl_union_map_apply_range(isl_union_map_copy(must_dep),
isl_union_map_copy(schedule));
scheduleDeps = isl_union_map_apply_domain(scheduleDeps,
isl_union_map_copy(schedule));
scheduleDeps_war = isl_union_map_apply_range(isl_union_map_copy(war_dep),
isl_union_map_copy(schedule));
scheduleDeps_war = isl_union_map_apply_domain(scheduleDeps_war,
isl_union_map_copy(schedule));
scheduleDeps_waw = isl_union_map_apply_range(isl_union_map_copy(waw_dep),
isl_union_map_copy(schedule));
scheduleDeps_waw = isl_union_map_apply_domain(scheduleDeps_waw,
isl_union_map_copy(schedule));
// Dependences need to originate and to terminate in the scheduling space
// enumerated by this loop.
restrictedDeps = isl_union_map_intersect_domain(scheduleDeps,
isl_union_set_copy(scheduleSubset));
restrictedDeps = isl_union_map_intersect_range(restrictedDeps,
isl_union_set_copy(scheduleSubset));
isl_union_set *distance = isl_union_map_deltas(restrictedDeps);
restrictedDeps_war = isl_union_map_intersect_domain(scheduleDeps_war,
isl_union_set_copy(scheduleSubset));
restrictedDeps_war = isl_union_map_intersect_range(restrictedDeps_war,
isl_union_set_copy(scheduleSubset));
isl_union_set *distance_war = isl_union_map_deltas(restrictedDeps_war);
restrictedDeps_waw = isl_union_map_intersect_domain(scheduleDeps_waw,
isl_union_set_copy(scheduleSubset));
restrictedDeps_waw = isl_union_map_intersect_range(restrictedDeps_waw,
isl_union_set_copy(scheduleSubset));
isl_union_set *distance_waw = isl_union_map_deltas(restrictedDeps_waw);
isl_dim *dim = isl_dim_set_alloc(S->getCtx(), S->getNumParams(),
parallelDimension);
// [0, 0, 0, 0] - All zero
isl_basic_set *allZeroBS = isl_basic_set_universe(isl_dim_copy(dim));
unsigned dimensions = isl_dim_size(dim, isl_dim_set);
for (unsigned i = 0; i < dimensions; i++) {
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_int v;
isl_int_init(v);
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_set, i, v);
allZeroBS = isl_basic_set_add_constraint(allZeroBS, c);
isl_int_clear(v);
}
isl_set *allZero = isl_set_from_basic_set(allZeroBS);
// All zero, last unknown.
// [0, 0, 0, ?]
isl_basic_set *lastUnknownBS = isl_basic_set_universe(isl_dim_copy(dim));
dimensions = isl_dim_size(dim, isl_dim_set);
for (unsigned i = 0; i < dimensions - 1; i++) {
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_int v;
isl_int_init(v);
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_set, i, v);
lastUnknownBS = isl_basic_set_add_constraint(lastUnknownBS, c);
isl_int_clear(v);
}
isl_set *lastUnknown = isl_set_from_basic_set(lastUnknownBS);
// Valid distance vectors
isl_set *validDistances = isl_set_subtract(lastUnknown, allZero);
validDistances = isl_set_complement(validDistances);
isl_union_set *validDistancesUS = isl_union_set_from_set(validDistances);
isl_union_set *nonValid = isl_union_set_subtract(distance,
isl_union_set_copy(validDistancesUS));
isl_union_set *nonValid_war = isl_union_set_subtract(distance_war,
isl_union_set_copy(validDistancesUS));
isl_union_set *nonValid_waw = isl_union_set_subtract(distance_waw,
validDistancesUS);
return isl_union_set_is_empty(nonValid)
&& isl_union_set_is_empty(nonValid_war)
&& isl_union_set_is_empty(nonValid_waw);
}
void Dependences::printScop(raw_ostream &OS) const {
OS.indent(4) << "Must dependences:\n";
OS.indent(8) << stringFromIslObj(must_dep) << "\n";
OS.indent(4) << "May dependences:\n";
OS.indent(8) << stringFromIslObj(may_dep) << "\n";
OS.indent(4) << "Must no source:\n";
OS.indent(8) << stringFromIslObj(must_no_source) << "\n";
OS.indent(4) << "May no source:\n";
OS.indent(8) << stringFromIslObj(may_no_source) << "\n";
}
void Dependences::releaseMemory() {
if (must_dep)
isl_union_map_free(must_dep);
if (may_dep)
isl_union_map_free(may_dep);
if (must_no_source)
isl_union_map_free(must_no_source);
if (may_no_source)
isl_union_map_free(may_no_source);
if (war_dep)
isl_union_map_free(war_dep);
if (waw_dep)
isl_union_map_free(waw_dep);
must_dep = may_dep = NULL;
must_no_source = may_no_source = NULL;
war_dep = waw_dep = NULL;
if (sink)
isl_union_map_free(sink);
if (must_source)
isl_union_map_free(must_source);
if (may_source)
isl_union_map_free(may_source);
sink = must_source = may_source = NULL;
}
void Dependences::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
}
char Dependences::ID = 0;
static RegisterPass<Dependences>
X("polly-dependences", "Polly - Calculate dependences for Scop");
Pass* polly::createDependencesPass() {
return new Dependences();
}

16
polly/lib/Analysis/Makefile Executable file
View File

@ -0,0 +1,16 @@
##===- polly/lib/Exchange/Makefile ----------------*- Makefile -*-===##
#
# Indicate where we are relative to the top of the source tree.
#
LEVEL=../..
LIBRARYNAME=pollyanalysis
BUILD_ARCHIVE = 1
CPP.Flags += $(POLLY_INC)
#
# Include Makefile.common so we know what to do.
#
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,659 @@
//===----- 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/ScopDetection.h"
#include "polly/LinkAllPasses.h"
#include "polly/Support/ScopHelper.h"
#include "polly/Support/AffineSCEVIterator.h"
#include "llvm/LLVMContext.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Assembly/Writer.h"
#define DEBUG_TYPE "polly-detect"
#include "llvm/Support/Debug.h"
using namespace llvm;
using namespace polly;
//===----------------------------------------------------------------------===//
// Statistics.
STATISTIC(ValidRegion, "Number of regions that a valid part of Scop");
#define BADSCOP_STAT(NAME, DESC) STATISTIC(Bad##NAME##ForScop, \
"Number of bad regions for Scop: "\
DESC)
#define STATSCOP(NAME); assert(!Context.Verifying && #NAME); \
if (!Context.Verifying) ++Bad##NAME##ForScop;
BADSCOP_STAT(CFG, "CFG too complex");
BADSCOP_STAT(IndVar, "Non canonical induction variable in loop");
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(Scalar, "Found scalar dependency");
BADSCOP_STAT(Alias, "Found base address alias");
BADSCOP_STAT(SimpleRegion, "Region not simple");
BADSCOP_STAT(Other, "Others");
//===----------------------------------------------------------------------===//
// ScopDetection.
bool ScopDetection::isMaxRegionInScop(const Region &R) const {
// The Region is valid only if it could be found in the set.
return ValidRegions.count(&R);
}
bool ScopDetection::isValidAffineFunction(const SCEV *S, Region &RefRegion,
Value **BasePtr) const {
assert(S && "S must not be null!");
bool isMemoryAccess = (BasePtr != 0);
if (isMemoryAccess) *BasePtr = 0;
DEBUG(dbgs() << "Checking " << *S << " ... ");
if (isa<SCEVCouldNotCompute>(S)) {
DEBUG(dbgs() << "Non Affine: SCEV could not be computed\n");
return false;
}
for (AffineSCEVIterator I = affine_begin(S, SE), E = affine_end(); I != E;
++I) {
// The constant part must be a SCEVConstant.
// TODO: support sizeof in coefficient.
if (!isa<SCEVConstant>(I->second)) {
DEBUG(dbgs() << "Non Affine: Right hand side is not constant\n");
return false;
}
const SCEV *Var = I->first;
// A constant offset is affine.
if(isa<SCEVConstant>(Var))
continue;
// Memory accesses are allowed to have a base pointer.
if (Var->getType()->isPointerTy()) {
if (!isMemoryAccess) {
DEBUG(dbgs() << "Non Affine: Pointer in non memory access\n");
return false;
}
assert(I->second->isOne() && "Only one as pointer coefficient allowed.\n");
const SCEVUnknown *BaseAddr = dyn_cast<SCEVUnknown>(Var);
if (!BaseAddr || isa<UndefValue>(BaseAddr->getValue())){
DEBUG(dbgs() << "Cannot handle base: " << *Var << "\n");
return false;
}
// BaseAddr must be invariant in Scop.
if (!isParameter(BaseAddr, RefRegion, *LI, *SE)) {
DEBUG(dbgs() << "Non Affine: Base address not invariant in SCoP\n");
return false;
}
assert(*BasePtr == 0 && "Found second base pointer.\n");
*BasePtr = BaseAddr->getValue();
continue;
}
if (isParameter(Var, RefRegion, *LI, *SE)
|| isIndVar(Var, RefRegion, *LI, *SE))
continue;
DEBUG(dbgs() << "Non Affine: " ;
Var->print(dbgs());
dbgs() << " is neither parameter nor induction variable\n");
return false;
}
DEBUG(dbgs() << " is affine.\n");
return !isMemoryAccess || (*BasePtr != 0);
}
bool ScopDetection::isValidCFG(BasicBlock &BB, DetectionContext &Context) const
{
Region &RefRegion = Context.CurRegion;
TerminatorInst *TI = BB.getTerminator();
// Return instructions are only valid if the region is the top level region.
if (isa<ReturnInst>(TI) && !RefRegion.getExit() && TI->getNumOperands() == 0)
return true;
BranchInst *Br = dyn_cast<BranchInst>(TI);
if (!Br) {
DEBUG(dbgs() << "Non branch instruction as terminator of BB: ";
WriteAsOperand(dbgs(), &BB, false);
dbgs() << "\n");
STATSCOP(CFG);
return false;
}
if (Br->isUnconditional()) return true;
Value *Condition = Br->getCondition();
// UndefValue is not allowed as condition.
if (isa<UndefValue>(Condition)) {
DEBUG(dbgs() << "Undefined value in branch instruction of BB: ";
WriteAsOperand(dbgs(), &BB, false);
dbgs() << "\n");
STATSCOP(AffFunc);
return false;
}
// Only Constant and ICmpInst are allowed as condition.
if (!(isa<Constant>(Condition) || isa<ICmpInst>(Condition))) {
DEBUG(dbgs() << "Non Constant and non ICmpInst instruction in BB: ";
WriteAsOperand(dbgs(), &BB, false);
dbgs() << "\n");
STATSCOP(AffFunc);
return false;
}
// 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())
return false;
// Are both operands of the ICmp affine?
if (isa<UndefValue>(ICmp->getOperand(0))
|| isa<UndefValue>(ICmp->getOperand(1))) {
DEBUG(dbgs() << "Undefined operand in branch instruction of BB: ";
WriteAsOperand(dbgs(), &BB, false);
dbgs() << "\n");
STATSCOP(AffFunc);
return false;
}
const SCEV *ScevLHS = SE->getSCEV(ICmp->getOperand(0));
const SCEV *ScevRHS = SE->getSCEV(ICmp->getOperand(1));
bool affineLHS = isValidAffineFunction(ScevLHS, RefRegion);
bool affineRHS = isValidAffineFunction(ScevRHS, RefRegion);
if (!affineLHS || !affineRHS) {
DEBUG(dbgs() << "Non affine branch instruction in BB: ";
WriteAsOperand(dbgs(), &BB, false);
dbgs() << "\n");
STATSCOP(AffFunc);
return false;
}
}
// 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) {
DEBUG(dbgs() << "Non well structured condition starting at BB: ";
WriteAsOperand(dbgs(), &BB, false);
dbgs() << "\n");
STATSCOP(CFG);
return false;
}
return true;
}
bool ScopDetection::isValidCallInst(CallInst &CI) {
if (CI.mayHaveSideEffects() || CI.doesNotReturn())
return false;
if (CI.doesNotAccessMemory())
return true;
Function *CalledFunction = CI.getCalledFunction();
// Indirect calls are not supported.
if (CalledFunction == 0)
return false;
// TODO: Intrinsics.
return false;
}
bool ScopDetection::isValidMemoryAccess(Instruction &Inst,
DetectionContext &Context) const {
Value *Ptr = getPointerOperand(Inst), *BasePtr;
const SCEV *AccessFunction = SE->getSCEV(Ptr);
if (!isValidAffineFunction(AccessFunction, Context.CurRegion, &BasePtr)) {
DEBUG(dbgs() << "Bad memory addr " << *AccessFunction << "\n");
STATSCOP(AffFunc);
return false;
}
// FIXME: Alias Analysis thinks IntToPtrInst aliases with alloca instructions
// created by IndependentBlocks Pass.
if (isa<IntToPtrInst>(BasePtr)) {
DEBUG(dbgs() << "Find bad intoptr prt: " << *BasePtr << '\n');
STATSCOP(Other);
return false;
}
// Check if the base pointer of the memory access does alias with
// any other pointer. This cannot be handled at the moment.
AliasSet &AS =
Context.AST.getAliasSetForPointer(BasePtr, AliasAnalysis::UnknownSize,
Inst.getMetadata(LLVMContext::MD_tbaa));
if (!AS.isMustAlias()) {
DEBUG(dbgs() << "Bad pointer alias found:" << *BasePtr << "\nAS:\n" << AS);
// STATSCOP triggers an assertion if we are in verifying mode.
// This is generally good to check that we do not change the SCoP after we
// run the SCoP detection and consequently to ensure that we can still
// represent that SCoP. However, in case of aliasing this does not work.
// The independent blocks pass may create memory references which seem to
// alias, if -basicaa is not available. They actually do not. As we do not
// not know this and we would fail here if we verify it.
if (!Context.Verifying) {
STATSCOP(Alias);
}
return false;
}
return true;
}
bool ScopDetection::hasScalarDependency(Instruction &Inst,
Region &RefRegion) const {
for (Instruction::use_iterator UI = Inst.use_begin(), UE = Inst.use_end();
UI != UE; ++UI)
if (Instruction *Use = dyn_cast<Instruction>(*UI))
if (!RefRegion.contains(Use->getParent())) {
// DirtyHack 1: PHINode user outside the Scop is not allow, if this
// PHINode is induction variable, the scalar to array transform may
// break it and introduce a non-indvar PHINode, which is not allow in
// Scop.
// This can be fix by:
// Introduce a IndependentBlockPrepare pass, which translate all
// PHINodes not in Scop to array.
// The IndependentBlockPrepare pass can also split the entry block of
// the function to hold the alloca instruction created by scalar to
// array. and split the exit block of the Scop so the new create load
// instruction for escape users will not break other Scops.
if (isa<PHINode>(Use))
return true;
}
return false;
}
bool ScopDetection::isValidInstruction(Instruction &Inst,
DetectionContext &Context) const {
// Only canonical IVs are allowed.
if (PHINode *PN = dyn_cast<PHINode>(&Inst))
if (!isIndVar(PN, LI)) {
DEBUG(dbgs() << "Non canonical PHI node found: ";
WriteAsOperand(dbgs(), &Inst, false);
dbgs() << "\n");
return false;
}
// Scalar dependencies are not allowed.
if (hasScalarDependency(Inst, Context.CurRegion)) {
DEBUG(dbgs() << "Scalar dependency found: ";
WriteAsOperand(dbgs(), &Inst, false);
dbgs() << "\n");
STATSCOP(Scalar);
return false;
}
// We only check the call instruction but not invoke instruction.
if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
if (isValidCallInst(*CI))
return true;
DEBUG(dbgs() << "Bad call Inst: ";
WriteAsOperand(dbgs(), &Inst, false);
dbgs() << "\n");
STATSCOP(FuncCall);
return false;
}
if (!Inst.mayWriteToMemory() && !Inst.mayReadFromMemory()) {
// Handle cast instruction.
if (isa<IntToPtrInst>(Inst) || isa<BitCastInst>(Inst)) {
DEBUG(dbgs() << "Bad cast Inst!\n");
STATSCOP(Other);
return false;
}
if (isa<AllocaInst>(Inst)) {
DEBUG(dbgs() << "AllocaInst is not allowed!!\n");
STATSCOP(Other);
return false;
}
return true;
}
// Check the access function.
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
return isValidMemoryAccess(Inst, Context);
// We do not know this instruction, therefore we assume it is invalid.
DEBUG(dbgs() << "Bad instruction found: ";
WriteAsOperand(dbgs(), &Inst, false);
dbgs() << "\n");
STATSCOP(Other);
return false;
}
bool ScopDetection::isValidBasicBlock(BasicBlock &BB,
DetectionContext &Context) const {
if (!isValidCFG(BB, Context))
return false;
// Check all instructions, except the terminator instruction.
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
if (!isValidInstruction(*I, Context))
return false;
Loop *L = LI->getLoopFor(&BB);
if (L && L->getHeader() == &BB && !isValidLoop(L, Context))
return false;
return true;
}
bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
PHINode *IndVar = L->getCanonicalInductionVariable();
// No canonical induction variable.
if (!IndVar) {
DEBUG(dbgs() << "No canonical iv for loop: ";
WriteAsOperand(dbgs(), L->getHeader(), false);
dbgs() << "\n");
STATSCOP(IndVar);
return false;
}
// Is the loop count affine?
const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
if (!isValidAffineFunction(LoopCount, Context.CurRegion)) {
DEBUG(dbgs() << "Non affine loop bound for loop: ";
WriteAsOperand(dbgs(), L->getHeader(), false);
dbgs() << "\n");
STATSCOP(LoopBound);
return false;
}
return true;
}
Region *ScopDetection::expandRegion(Region &R) {
Region *CurrentRegion = &R;
Region *TmpRegion = R.getExpandedRegion();
DEBUG(dbgs() << "\tExpanding " << R.getNameStr() << "\n");
while (TmpRegion) {
DetectionContext Context(*TmpRegion, *AA, false /*verifying*/);
DEBUG(dbgs() << "\t\tTrying " << TmpRegion->getNameStr() << "\n");
if (!allBlocksValid(Context))
break;
if (isValidExit(Context)) {
if (CurrentRegion != &R)
delete CurrentRegion;
CurrentRegion = TmpRegion;
}
Region *TmpRegion2 = TmpRegion->getExpandedRegion();
if (TmpRegion != &R && TmpRegion != CurrentRegion)
delete TmpRegion;
TmpRegion = TmpRegion2;
}
if (&R == CurrentRegion)
return NULL;
DEBUG(dbgs() << "\tto " << CurrentRegion->getNameStr() << "\n");
return CurrentRegion;
}
void ScopDetection::findScops(Region &R) {
DetectionContext Context(R, *AA, false /*verifying*/);
if (isValidRegion(Context)) {
++ValidRegion;
ValidRegions.insert(&R);
return;
}
for (Region::iterator I = R.begin(), E = R.end(); I != E; ++I)
findScops(**I);
// 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 (Region::iterator I = R.begin(), E = R.end(); I != E; ++I)
ToExpand.push_back(*I);
for (std::vector<Region*>::iterator RI = ToExpand.begin(),
RE = ToExpand.end(); RI != RE; ++RI) {
Region *CurrentRegion = *RI;
// Skip invalid regions. Regions may become invalid, if they are element of
// an already expanded region.
if (ValidRegions.find(CurrentRegion) == ValidRegions.end())
continue;
Region *ExpandedR = expandRegion(*CurrentRegion);
if (!ExpandedR)
continue;
R.addSubRegion(ExpandedR, true);
ValidRegions.insert(ExpandedR);
ValidRegions.erase(CurrentRegion);
for (Region::iterator I = ExpandedR->begin(), E = ExpandedR->end(); I != E;
++I)
ValidRegions.erase(*I);
}
}
bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
Region &R = Context.CurRegion;
for (Region::block_iterator I = R.block_begin(), E = R.block_end(); I != E;
++I)
if (!isValidBasicBlock(*(I->getNodeAs<BasicBlock>()), Context))
return false;
return true;
}
bool ScopDetection::isValidExit(DetectionContext &Context) const {
Region &R = Context.CurRegion;
// PHI nodes are not allowed in the exit basic block.
if (BasicBlock *Exit = R.getExit()) {
BasicBlock::iterator I = Exit->begin();
if (I != Exit->end() && isa<PHINode> (*I)) {
DEBUG(dbgs() << "PHI node in exit";
dbgs() << "\n");
STATSCOP(Other);
return false;
}
}
return true;
}
bool ScopDetection::isValidRegion(DetectionContext &Context) const {
Region &R = Context.CurRegion;
DEBUG(dbgs() << "Checking region: " << R.getNameStr() << "\n\t");
// The toplevel region is no valid region.
if (!R.getParent()) {
DEBUG(dbgs() << "Top level region is invalid";
dbgs() << "\n");
return false;
}
// SCoP can not contains the entry block of the function, because we need
// to insert alloca instruction there when translate scalar to array.
if (R.getEntry() == &(R.getEntry()->getParent()->getEntryBlock())) {
DEBUG(dbgs() << "Region containing entry block of function is invalid!\n");
STATSCOP(Other);
return false;
}
// Only a simple region is allowed.
if (!R.isSimple()) {
DEBUG(dbgs() << "Region not simple: " << R.getNameStr() << '\n');
STATSCOP(SimpleRegion);
return false;
}
if (!allBlocksValid(Context))
return false;
if (!isValidExit(Context))
return false;
DEBUG(dbgs() << "OK\n");
return true;
}
bool ScopDetection::isValidFunction(llvm::Function &F) {
const std::string &Name = F.getNameStr();
size_t found = Name.find(".omp_subfn");
if (found != std::string::npos)
return false;
else
return true;
}
bool ScopDetection::runOnFunction(llvm::Function &F) {
AA = &getAnalysis<AliasAnalysis>();
SE = &getAnalysis<ScalarEvolution>();
LI = &getAnalysis<LoopInfo>();
RI = &getAnalysis<RegionInfo>();
Region *TopRegion = RI->getTopLevelRegion();
if(!isValidFunction(F))
return false;
findScops(*TopRegion);
return false;
}
void polly::ScopDetection::verifyRegion(const Region &R) const {
assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
DetectionContext Context(const_cast<Region&>(R), *AA, true /*verifying*/);
isValidRegion(Context);
}
void polly::ScopDetection::verifyAnalysis() const {
for (RegionSet::const_iterator I = ValidRegions.begin(),
E = ValidRegions.end(); I != E; ++I)
verifyRegion(**I);
}
void ScopDetection::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<DominatorTree>();
AU.addRequired<PostDominatorTree>();
AU.addRequired<LoopInfo>();
AU.addRequired<ScalarEvolution>();
// We also need AA and RegionInfo when we are verifying analysis.
AU.addRequiredTransitive<AliasAnalysis>();
AU.addRequiredTransitive<RegionInfo>();
AU.setPreservesAll();
}
void ScopDetection::print(raw_ostream &OS, const Module *) const {
for (RegionSet::const_iterator I = ValidRegions.begin(),
E = ValidRegions.end(); I != E; ++I)
OS << "Valid Region for Scop: " << (*I)->getNameStr() << '\n';
OS << "\n";
}
void ScopDetection::releaseMemory() {
ValidRegions.clear();
}
char ScopDetection::ID = 0;
static RegisterPass<ScopDetection>
X("polly-detect", "Polly - Detect Scops in functions");

View File

@ -0,0 +1,215 @@
//===- 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 "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->getEntry() == destBB && R->contains(srcBB))
return "constraint=false";
return "";
}
std::string getNodeLabel(RegionNode *Node, ScopDetection *SD) {
return DOTGraphTraits<RegionNode*>
::getNodeLabel(Node, SD->getRI()->getTopLevelRegion());
}
// 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";
O.indent(2 * (depth + 1)) << "label = \"\";\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 (Region::const_iterator RI = R->begin(), RE = R->end(); RI != RE; ++RI)
printRegionCluster(SD, *RI, O, depth + 1);
RegionInfo *RI = R->getRegionInfo();
for (Region::const_block_iterator BI = R->block_begin(),
BE = R->block_end(); BI != BE; ++BI) {
BasicBlock *BB = (*BI)->getNodeAs<BasicBlock>();
if (RI->getRegionFor(BB) == R)
O.indent(2 * (depth + 1)) << "Node"
<< static_cast<const 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();
}

View File

@ -0,0 +1,906 @@
//===--------- 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 represantation is shared among several tools in the polyhedral
// community, which are e.g. Cloog, Pluto, Loopo, Graphite.
//
//===----------------------------------------------------------------------===//
#include "polly/ScopInfo.h"
#include "polly/TempScopInfo.h"
#include "polly/LinkAllPasses.h"
#include "polly/Support/GICHelper.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/CommandLine.h"
#define DEBUG_TYPE "polly-scops"
#include "llvm/Support/Debug.h"
#include "isl/constraint.h"
#include "isl/set.h"
#include "isl/map.h"
#include <sstream>
#include <string>
#include <vector>
using namespace llvm;
using namespace polly;
STATISTIC(ScopFound, "Number of valid Scops");
STATISTIC(RichScopFound, "Number of Scops containing a loop");
//===----------------------------------------------------------------------===//
static void setCoefficient(const SCEV *Coeff, mpz_t v, bool negative,
bool isSigned = true) {
if (Coeff) {
const SCEVConstant *C = dyn_cast<SCEVConstant>(Coeff);
const APInt &CI = C->getValue()->getValue();
MPZ_from_APInt(v, negative ? (-CI) : CI, isSigned);
} else
isl_int_set_si(v, 0);
}
static isl_map *getValueOf(const SCEVAffFunc &AffFunc,
const ScopStmt *Statement, isl_dim *dim) {
const SmallVectorImpl<const SCEV*> &Params =
Statement->getParent()->getParams();
unsigned num_in = Statement->getNumIterators(), num_param = Params.size();
const char *dimname = isl_dim_get_tuple_name(dim, isl_dim_set);
dim = isl_dim_alloc(isl_dim_get_ctx(dim), num_param,
isl_dim_size(dim, isl_dim_set), 1);
dim = isl_dim_set_tuple_name(dim, isl_dim_in, dimname);
assert((AffFunc.getType() == SCEVAffFunc::Eq
|| AffFunc.getType() == SCEVAffFunc::ReadMem
|| AffFunc.getType() == SCEVAffFunc::WriteMem)
&& "AffFunc is not an equality");
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_int v;
isl_int_init(v);
// Set single output dimension.
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_out, 0, v);
// Set the coefficient for induction variables.
for (unsigned i = 0, e = num_in; i != e; ++i) {
setCoefficient(AffFunc.getCoeff(Statement->getSCEVForDimension(i)), v,
false, AffFunc.isSigned());
isl_constraint_set_coefficient(c, isl_dim_in, i, v);
}
// Set the coefficient of parameters
for (unsigned i = 0, e = num_param; i != e; ++i) {
setCoefficient(AffFunc.getCoeff(Params[i]), v, false, AffFunc.isSigned());
isl_constraint_set_coefficient(c, isl_dim_param, i, v);
}
// Set the constant.
setCoefficient(AffFunc.getTransComp(), v, false, AffFunc.isSigned());
isl_constraint_set_constant(c, v);
isl_int_clear(v);
isl_basic_map *BasicMap = isl_basic_map_universe(isl_dim_copy(dim));
BasicMap = isl_basic_map_add_constraint(BasicMap, c);
return isl_map_from_basic_map(BasicMap);
}
//===----------------------------------------------------------------------===//
MemoryAccess::~MemoryAccess() {
isl_map_free(getAccessFunction());
}
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, ".", "_");
}
void MemoryAccess::setBaseName() {
raw_string_ostream OS(BaseName);
WriteAsOperand(OS, getBaseAddr(), false);
BaseName = OS.str();
// Remove the % in the name. This is not supported by isl.
BaseName.erase(0,1);
makeIslCompatible(BaseName);
BaseName = "MemRef_" + BaseName;
}
std::string MemoryAccess::getAccessFunctionStr() const {
return stringFromIslObj(getAccessFunction());
}
isl_basic_map *MemoryAccess::createBasicAccessMap(ScopStmt *Statement) {
isl_dim *dim = isl_dim_alloc(Statement->getIslContext(),
Statement->getNumParams(),
Statement->getNumIterators(), 1);
setBaseName();
dim = isl_dim_set_tuple_name(dim, isl_dim_out, getBaseName().c_str());
dim = isl_dim_set_tuple_name(dim, isl_dim_in, Statement->getBaseName());
return isl_basic_map_universe(dim);
}
MemoryAccess::MemoryAccess(const SCEVAffFunc &AffFunc, ScopStmt *Statement) {
BaseAddr = AffFunc.getBaseAddr();
Type = AffFunc.isRead() ? Read : Write;
statement = Statement;
setBaseName();
isl_dim *dim = isl_dim_set_alloc(Statement->getIslContext(),
Statement->getNumParams(),
Statement->getNumIterators());
dim = isl_dim_set_tuple_name(dim, isl_dim_set, Statement->getBaseName());
AccessRelation = getValueOf(AffFunc, Statement, dim);
// Devide the access function by the size of the elements in the function.
isl_dim *dim2 = isl_dim_alloc(Statement->getIslContext(),
Statement->getNumParams(), 1, 1);
isl_basic_map *bmap = isl_basic_map_universe(isl_dim_copy(dim2));
isl_constraint *c = isl_equality_alloc(dim2);
isl_int v;
isl_int_init(v);
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_in, 0, v);
isl_int_set_si(v, AffFunc.getElemSizeInBytes());
isl_constraint_set_coefficient(c, isl_dim_out, 0, v);
bmap = isl_basic_map_add_constraint(bmap, c);
isl_map* dataSizeMap = isl_map_from_basic_map(bmap);
AccessRelation = isl_map_apply_range(AccessRelation, dataSizeMap);
AccessRelation = isl_map_set_tuple_name(AccessRelation, isl_dim_out,
getBaseName().c_str());
}
MemoryAccess::MemoryAccess(const Value *BaseAddress, ScopStmt *Statement) {
BaseAddr = BaseAddress;
Type = Read;
statement = Statement;
isl_basic_map *BasicAccessMap = createBasicAccessMap(Statement);
AccessRelation = isl_map_from_basic_map(BasicAccessMap);
}
void MemoryAccess::print(raw_ostream &OS) const {
OS.indent(12) << (isRead() ? "Read" : "Write") << "Access := \n";
OS.indent(16) << getAccessFunctionStr() << ";\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_dim *setDomain) {
isl_dim *mapDomain = isl_dim_map_from_set(setDomain);
isl_basic_map *bmap = isl_basic_map_universe(mapDomain);
// 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 < isl_basic_map_n_in(bmap) - 1; ++i) {
isl_int v;
isl_int_init(v);
isl_constraint *c = isl_equality_alloc(isl_basic_map_get_dim(bmap));
isl_int_set_si(v, 1);
isl_constraint_set_coefficient(c, isl_dim_in, i, v);
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_out, i, v);
bmap = isl_basic_map_add_constraint(bmap, c);
isl_int_clear(v);
}
// Set the last dimension of the input to be strict smaller than the
// last dimension of the output.
//
// input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX
//
unsigned lastDimension = isl_basic_map_n_in(bmap) - 1;
isl_int v;
isl_int_init(v);
isl_constraint *c = isl_inequality_alloc(isl_basic_map_get_dim(bmap));
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_in, lastDimension, v);
isl_int_set_si(v, 1);
isl_constraint_set_coefficient(c, isl_dim_out, lastDimension, v);
isl_int_set_si(v, -1);
isl_constraint_set_constant(c, v);
isl_int_clear(v);
bmap = isl_basic_map_add_constraint(bmap, c);
return isl_map_from_basic_map(bmap);
}
isl_set *MemoryAccess::getStride(const isl_set *domainSubset) const {
isl_map *accessRelation = isl_map_copy(getAccessFunction());
isl_set *scatteringDomain = isl_set_copy(const_cast<isl_set*>(domainSubset));
isl_map *scattering = isl_map_copy(getStatement()->getScattering());
scattering = isl_map_reverse(scattering);
int difference = isl_map_n_in(scattering) - isl_set_n_dim(scatteringDomain);
scattering = isl_map_project_out(scattering, isl_dim_in,
isl_set_n_dim(scatteringDomain),
difference);
// Remove all names of the scattering dimensions, as the names may be lost
// anyways during the project. This leads to consistent results.
scattering = isl_map_set_tuple_name(scattering, isl_dim_in, "");
scatteringDomain = isl_set_set_tuple_name(scatteringDomain, "");
isl_map *nextScatt = getEqualAndLarger(isl_set_get_dim(scatteringDomain));
nextScatt = isl_map_lexmin(nextScatt);
scattering = isl_map_intersect_domain(scattering, scatteringDomain);
nextScatt = isl_map_apply_range(nextScatt, isl_map_copy(scattering));
nextScatt = isl_map_apply_range(nextScatt, isl_map_copy(accessRelation));
nextScatt = isl_map_apply_domain(nextScatt, scattering);
nextScatt = isl_map_apply_domain(nextScatt, accessRelation);
return isl_map_deltas(nextScatt);
}
bool MemoryAccess::isStrideZero(const isl_set *domainSubset) const {
isl_set *stride = getStride(domainSubset);
isl_constraint *c = isl_equality_alloc(isl_set_get_dim(stride));
isl_int v;
isl_int_init(v);
isl_int_set_si(v, 1);
isl_constraint_set_coefficient(c, isl_dim_set, 0, v);
isl_int_set_si(v, 0);
isl_constraint_set_constant(c, v);
isl_int_clear(v);
isl_basic_set *bset = isl_basic_set_universe(isl_set_get_dim(stride));
bset = isl_basic_set_add_constraint(bset, c);
isl_set *strideZero = isl_set_from_basic_set(bset);
return isl_set_is_equal(stride, strideZero);
}
bool MemoryAccess::isStrideOne(const isl_set *domainSubset) const {
isl_set *stride = getStride(domainSubset);
isl_constraint *c = isl_equality_alloc(isl_set_get_dim(stride));
isl_int v;
isl_int_init(v);
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_constant(c, v);
isl_int_clear(v);
isl_basic_set *bset = isl_basic_set_universe(isl_set_get_dim(stride));
bset = isl_basic_set_add_constraint(bset, c);
isl_set *strideZero = isl_set_from_basic_set(bset);
return isl_set_is_equal(stride, strideZero);
}
//===----------------------------------------------------------------------===//
void ScopStmt::buildScattering(SmallVectorImpl<unsigned> &Scatter) {
unsigned NumberOfIterators = getNumIterators();
unsigned ScatDim = Parent.getMaxLoopDepth() * 2 + 1;
isl_dim *dim = isl_dim_alloc(Parent.getCtx(), Parent.getNumParams(),
NumberOfIterators, ScatDim);
dim = isl_dim_set_tuple_name(dim, isl_dim_out, "scattering");
dim = isl_dim_set_tuple_name(dim, isl_dim_in, getBaseName());
isl_basic_map *bmap = isl_basic_map_universe(isl_dim_copy(dim));
isl_int v;
isl_int_init(v);
// Loop dimensions.
for (unsigned i = 0; i < NumberOfIterators; ++i) {
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_int_set_si(v, 1);
isl_constraint_set_coefficient(c, isl_dim_out, 2 * i + 1, v);
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_in, i, v);
bmap = isl_basic_map_add_constraint(bmap, c);
}
// Constant dimensions
for (unsigned i = 0; i < NumberOfIterators + 1; ++i) {
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_out, 2 * i, v);
isl_int_set_si(v, Scatter[i]);
isl_constraint_set_constant(c, v);
bmap = isl_basic_map_add_constraint(bmap, c);
}
// Fill scattering dimensions.
for (unsigned i = 2 * NumberOfIterators + 1; i < ScatDim ; ++i) {
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_int_set_si(v, 1);
isl_constraint_set_coefficient(c, isl_dim_out, i, v);
isl_int_set_si(v, 0);
isl_constraint_set_constant(c, v);
bmap = isl_basic_map_add_constraint(bmap, c);
}
isl_int_clear(v);
isl_dim_free(dim);
Scattering = isl_map_from_basic_map(bmap);
}
void ScopStmt::buildAccesses(TempScop &tempScop, const Region &CurRegion) {
const AccFuncSetType *AccFuncs = tempScop.getAccessFunctions(BB);
for (AccFuncSetType::const_iterator I = AccFuncs->begin(),
E = AccFuncs->end(); I != E; ++I) {
MemAccs.push_back(new MemoryAccess(I->first, this));
InstructionToAccess[I->second] = MemAccs.back();
}
}
static isl_map *MapValueToLHS(isl_ctx *Context, unsigned ParameterNumber) {
std::string MapString;
isl_map *Map;
MapString = "{[i0] -> [i0, o1]}";
Map = isl_map_read_from_str(Context, MapString.c_str(), -1);
return isl_map_add_dims(Map, isl_dim_param, ParameterNumber);
}
static isl_map *MapValueToRHS(isl_ctx *Context, unsigned ParameterNumber) {
std::string MapString;
isl_map *Map;
MapString = "{[i0] -> [o0, i0]}";
Map = isl_map_read_from_str(Context, MapString.c_str(), -1);
return isl_map_add_dims(Map, isl_dim_param, ParameterNumber);
}
static isl_set *getComparison(isl_ctx *Context, const ICmpInst::Predicate Pred,
unsigned ParameterNumber) {
std::string SetString;
switch (Pred) {
case ICmpInst::ICMP_EQ:
SetString = "{[i0, i1] : i0 = i1}";
break;
case ICmpInst::ICMP_NE:
SetString = "{[i0, i1] : i0 + 1 <= i1; [i0, i1] : i0 - 1 >= i1}";
break;
case ICmpInst::ICMP_SLT:
SetString = "{[i0, i1] : i0 + 1 <= i1}";
break;
case ICmpInst::ICMP_ULT:
SetString = "{[i0, i1] : i0 + 1 <= i1}";
break;
case ICmpInst::ICMP_SGT:
SetString = "{[i0, i1] : i0 >= i1 + 1}";
break;
case ICmpInst::ICMP_UGT:
SetString = "{[i0, i1] : i0 >= i1 + 1}";
break;
case ICmpInst::ICMP_SLE:
SetString = "{[i0, i1] : i0 <= i1}";
break;
case ICmpInst::ICMP_ULE:
SetString = "{[i0, i1] : i0 <= i1}";
break;
case ICmpInst::ICMP_SGE:
SetString = "{[i0, i1] : i0 >= i1}";
break;
case ICmpInst::ICMP_UGE:
SetString = "{[i0, i1] : i0 >= i1}";
break;
default:
llvm_unreachable("Non integer predicate not supported");
}
isl_set *Set = isl_set_read_from_str(Context, SetString.c_str(), -1);
return isl_set_add_dims(Set, isl_dim_param, ParameterNumber);
}
static isl_set *compareValues(isl_map *LeftValue, isl_map *RightValue,
const ICmpInst::Predicate Predicate) {
isl_ctx *Context = isl_map_get_ctx(LeftValue);
unsigned NumberOfParameters = isl_map_n_param(LeftValue);
isl_map *MapToLHS = MapValueToLHS(Context, NumberOfParameters);
isl_map *MapToRHS = MapValueToRHS(Context, NumberOfParameters);
isl_map *LeftValueAtLHS = isl_map_apply_range(LeftValue, MapToLHS);
isl_map *RightValueAtRHS = isl_map_apply_range(RightValue, MapToRHS);
isl_map *BothValues = isl_map_intersect(LeftValueAtLHS, RightValueAtRHS);
isl_set *Comparison = getComparison(Context, Predicate, NumberOfParameters);
isl_map *ComparedValues = isl_map_intersect_range(BothValues, Comparison);
return isl_map_domain(ComparedValues);
}
isl_set *ScopStmt::toConditionSet(const Comparison &Comp, isl_dim *dim) const {
isl_map *LHSValue = getValueOf(*Comp.getLHS(), this, dim);
isl_map *RHSValue = getValueOf(*Comp.getRHS(), this, dim);
return compareValues(LHSValue, RHSValue, Comp.getPred());
}
isl_set *ScopStmt::toUpperLoopBound(const SCEVAffFunc &UpperBound, isl_dim *dim,
unsigned BoundedDimension) const {
// Set output dimension to bounded dimension.
isl_dim *RHSDim = isl_dim_alloc(Parent.getCtx(), getNumParams(),
getNumIterators(), 1);
RHSDim = isl_dim_set_tuple_name(RHSDim, isl_dim_in, getBaseName());
isl_constraint *c = isl_equality_alloc(isl_dim_copy(RHSDim));
isl_int v;
isl_int_init(v);
isl_int_set_si(v, 1);
isl_constraint_set_coefficient(c, isl_dim_in, BoundedDimension, v);
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_out, 0, v);
isl_int_clear(v);
isl_basic_map *bmap = isl_basic_map_universe(RHSDim);
bmap = isl_basic_map_add_constraint(bmap, c);
isl_map *LHSValue = isl_map_from_basic_map(bmap);
isl_map *RHSValue = getValueOf(UpperBound, this, dim);
return compareValues(LHSValue, RHSValue, ICmpInst::ICMP_SLE);
}
void ScopStmt::buildIterationDomainFromLoops(TempScop &tempScop) {
isl_dim *dim = isl_dim_set_alloc(Parent.getCtx(), getNumParams(),
getNumIterators());
dim = isl_dim_set_tuple_name(dim, isl_dim_set, getBaseName());
Domain = isl_set_universe(isl_dim_copy(dim));
isl_int v;
isl_int_init(v);
for (int i = 0, e = getNumIterators(); i != e; ++i) {
// Lower bound: IV >= 0.
isl_basic_set *bset = isl_basic_set_universe(isl_dim_copy(dim));
isl_constraint *c = isl_inequality_alloc(isl_dim_copy(dim));
isl_int_set_si(v, 1);
isl_constraint_set_coefficient(c, isl_dim_set, i, v);
bset = isl_basic_set_add_constraint(bset, c);
Domain = isl_set_intersect(Domain, isl_set_from_basic_set(bset));
// Upper bound: IV <= NumberOfIterations.
const Loop *L = getSCEVForDimension(i)->getLoop();
const SCEVAffFunc &UpperBound = tempScop.getLoopBound(L);
isl_set *UpperBoundSet = toUpperLoopBound(UpperBound, isl_dim_copy(dim), i);
Domain = isl_set_intersect(Domain, UpperBoundSet);
}
isl_int_clear(v);
}
void ScopStmt::addConditionsToDomain(TempScop &tempScop,
const Region &CurRegion) {
isl_dim *dim = isl_set_get_dim(Domain);
const Region *TopR = tempScop.getMaxRegion().getParent(),
*CurR = &CurRegion;
const BasicBlock *CurEntry = BB;
// Build BB condition constrains, by traveling up the region tree.
do {
assert(CurR && "We exceed the top region?");
// Skip when multiple regions share the same entry.
if (CurEntry != CurR->getEntry()) {
if (const BBCond *Cnd = tempScop.getBBCond(CurEntry))
for (BBCond::const_iterator I = Cnd->begin(), E = Cnd->end();
I != E; ++I) {
isl_set *c = toConditionSet(*I, dim);
Domain = isl_set_intersect(Domain, c);
}
}
CurEntry = CurR->getEntry();
CurR = CurR->getParent();
} while (TopR != CurR);
isl_dim_free(dim);
}
void ScopStmt::buildIterationDomain(TempScop &tempScop, const Region &CurRegion)
{
buildIterationDomainFromLoops(tempScop);
addConditionsToDomain(tempScop, CurRegion);
}
ScopStmt::ScopStmt(Scop &parent, TempScop &tempScop,
const Region &CurRegion, BasicBlock &bb,
SmallVectorImpl<Loop*> &NestLoops,
SmallVectorImpl<unsigned> &Scatter)
: Parent(parent), BB(&bb), IVS(NestLoops.size()) {
// Setup the induction variables.
for (unsigned i = 0, e = NestLoops.size(); i < e; ++i) {
PHINode *PN = NestLoops[i]->getCanonicalInductionVariable();
assert(PN && "Non canonical IV in Scop!");
IVS[i] = PN;
}
raw_string_ostream OS(BaseName);
WriteAsOperand(OS, &bb, false);
BaseName = OS.str();
// Remove the % in the name. This is not supported by isl.
BaseName.erase(0, 1);
makeIslCompatible(BaseName);
BaseName = "Stmt_" + BaseName;
buildIterationDomain(tempScop, CurRegion);
buildScattering(Scatter);
buildAccesses(tempScop, CurRegion);
IsReduction = tempScop.is_Reduction(*BB);
}
ScopStmt::ScopStmt(Scop &parent, SmallVectorImpl<unsigned> &Scatter)
: Parent(parent), BB(NULL), IVS(0) {
BaseName = "FinalRead";
// Build iteration domain.
std::string IterationDomainString = "{[i0] : i0 = 0}";
Domain = isl_set_read_from_str(Parent.getCtx(), IterationDomainString.c_str(),
-1);
Domain = isl_set_add_dims(Domain, isl_dim_param, Parent.getNumParams());
Domain = isl_set_set_tuple_name(Domain, getBaseName());
// Build scattering.
unsigned ScatDim = Parent.getMaxLoopDepth() * 2 + 1;
isl_dim *dim = isl_dim_alloc(Parent.getCtx(), Parent.getNumParams(), 1,
ScatDim);
dim = isl_dim_set_tuple_name(dim, isl_dim_out, "scattering");
dim = isl_dim_set_tuple_name(dim, isl_dim_in, getBaseName());
isl_basic_map *bmap = isl_basic_map_universe(isl_dim_copy(dim));
isl_int v;
isl_int_init(v);
isl_constraint *c = isl_equality_alloc(dim);
isl_int_set_si(v, -1);
isl_constraint_set_coefficient(c, isl_dim_out, 0, v);
// TODO: This is incorrect. We should not use a very large number to ensure
// that this statement is executed last.
isl_int_set_si(v, 200000000);
isl_constraint_set_constant(c, v);
bmap = isl_basic_map_add_constraint(bmap, c);
isl_int_clear(v);
Scattering = isl_map_from_basic_map(bmap);
// Build memory accesses, use SetVector to keep the order of memory accesses
// and prevent the same memory access inserted more than once.
SetVector<const Value*> BaseAddressSet;
for (Scop::const_iterator SI = Parent.begin(), SE = Parent.end(); SI != SE;
++SI) {
ScopStmt *Stmt = *SI;
for (MemoryAccessVec::const_iterator I = Stmt->memacc_begin(),
E = Stmt->memacc_end(); I != E; ++I)
BaseAddressSet.insert((*I)->getBaseAddr());
}
for (SetVector<const Value*>::iterator BI = BaseAddressSet.begin(),
BE = BaseAddressSet.end(); BI != BE; ++BI)
MemAccs.push_back(new MemoryAccess(*BI, this));
IsReduction = false;
}
std::string ScopStmt::getDomainStr() const {
return stringFromIslObj(getDomain());
}
std::string ScopStmt::getScatteringStr() const {
return stringFromIslObj(getScattering());
}
unsigned ScopStmt::getNumParams() const {
return Parent.getNumParams();
}
unsigned ScopStmt::getNumIterators() const {
// The final read has one dimension with one element.
if (!BB)
return 1;
return IVS.size();
}
unsigned ScopStmt::getNumScattering() const {
return isl_map_dim(Scattering, isl_dim_out);
}
const char *ScopStmt::getBaseName() const { return BaseName.c_str(); }
const PHINode *ScopStmt::getInductionVariableForDimension(unsigned Dimension)
const {
return IVS[Dimension];
}
const SCEVAddRecExpr *ScopStmt::getSCEVForDimension(unsigned Dimension)
const {
PHINode *PN = IVS[Dimension];
return cast<SCEVAddRecExpr>(getParent()->getSE()->getSCEV(PN));
}
isl_ctx *ScopStmt::getIslContext() {
return Parent.getCtx();
}
ScopStmt::~ScopStmt() {
while (!MemAccs.empty()) {
delete MemAccs.back();
MemAccs.pop_back();
}
isl_set_free(Domain);
isl_map_free(Scattering);
}
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) << "Scattering :=\n";
if (Domain) {
OS.indent(16) << getScatteringStr() << ";\n";
} else
OS.indent(16) << "n/a\n";
for (MemoryAccessVec::const_iterator I = MemAccs.begin(), E = MemAccs.end();
I != E; ++I)
(*I)->print(OS);
}
void ScopStmt::dump() const { print(dbgs()); }
//===----------------------------------------------------------------------===//
/// Scop class implement
Scop::Scop(TempScop &tempScop, LoopInfo &LI, ScalarEvolution &ScalarEvolution)
: SE(&ScalarEvolution), R(tempScop.getMaxRegion()),
MaxLoopDepth(tempScop.getMaxLoopDepth()) {
isl_ctx *ctx = isl_ctx_alloc();
ParamSetType &Params = tempScop.getParamSet();
Parameters.insert(Parameters.begin(), Params.begin(), Params.end());
isl_dim *dim = isl_dim_set_alloc(ctx, getNumParams(), 0);
// TODO: Insert relations between parameters.
// TODO: Insert constraints on parameters.
Context = isl_set_universe (dim);
SmallVector<Loop*, 8> NestLoops;
SmallVector<unsigned, 8> Scatter;
Scatter.assign(MaxLoopDepth + 1, 0);
// Build the iteration domain, access functions and scattering functions
// traversing the region tree.
buildScop(tempScop, getRegion(), NestLoops, Scatter, LI);
Stmts.push_back(new ScopStmt(*this, Scatter));
assert(NestLoops.empty() && "NestLoops not empty at top level!");
}
Scop::~Scop() {
isl_set_free(Context);
// Free the statements;
for (iterator I = begin(), E = end(); I != E; ++I)
delete *I;
// Do we need a singleton to manage this?
//isl_ctx_free(ctx);
}
std::string Scop::getContextStr() const {
return stringFromIslObj(getContext());
}
std::string Scop::getNameStr() const {
std::string ExitName, EntryName;
raw_string_ostream ExitStr(ExitName);
raw_string_ostream EntryStr(EntryName);
WriteAsOperand(EntryStr, R.getEntry(), false);
EntryStr.str();
if (R.getExit()) {
WriteAsOperand(ExitStr, R.getExit(), false);
ExitStr.str();
} else
ExitName = "FunctionExit";
return EntryName + "---" + ExitName;
}
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";
}
void Scop::printStatements(raw_ostream &OS) const {
OS << "Statements {\n";
for (const_iterator SI = begin(), SE = end();SI != SE; ++SI)
OS.indent(4) << (**SI);
OS.indent(4) << "}\n";
}
void Scop::print(raw_ostream &OS) const {
printContext(OS.indent(4));
printStatements(OS.indent(4));
}
void Scop::dump() const { print(dbgs()); }
isl_ctx *Scop::getCtx() const { return isl_set_get_ctx(Context); }
ScalarEvolution *Scop::getSE() const { return SE; }
bool Scop::isTrivialBB(BasicBlock *BB, TempScop &tempScop) {
if (tempScop.getAccessFunctions(BB))
return false;
return true;
}
void Scop::buildScop(TempScop &tempScop,
const Region &CurRegion,
SmallVectorImpl<Loop*> &NestLoops,
SmallVectorImpl<unsigned> &Scatter,
LoopInfo &LI) {
Loop *L = castToLoop(CurRegion, LI);
if (L)
NestLoops.push_back(L);
unsigned loopDepth = NestLoops.size();
assert(Scatter.size() > loopDepth && "Scatter not big enough!");
for (Region::const_element_iterator I = CurRegion.element_begin(),
E = CurRegion.element_end(); I != E; ++I)
if (I->isSubRegion())
buildScop(tempScop, *(I->getNodeAs<Region>()), NestLoops, Scatter, LI);
else {
BasicBlock *BB = I->getNodeAs<BasicBlock>();
if (isTrivialBB(BB, tempScop))
continue;
Stmts.push_back(new ScopStmt(*this, tempScop, CurRegion, *BB, NestLoops,
Scatter));
// Increasing the Scattering function is OK for the moment, because
// we are using a depth first iterator and the program is well structured.
++Scatter[loopDepth];
}
if (!L)
return;
// Exiting a loop region.
Scatter[loopDepth] = 0;
NestLoops.pop_back();
++Scatter[loopDepth-1];
}
//===----------------------------------------------------------------------===//
void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LoopInfo>();
AU.addRequired<RegionInfo>();
AU.addRequired<ScalarEvolution>();
AU.addRequired<TempScopInfo>();
AU.setPreservesAll();
}
bool ScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
LoopInfo &LI = getAnalysis<LoopInfo>();
ScalarEvolution &SE = getAnalysis<ScalarEvolution>();
TempScop *tempScop = getAnalysis<TempScopInfo>().getTempScop(R);
// This region is no Scop.
if (!tempScop) {
scop = 0;
return false;
}
// Statistics.
++ScopFound;
if (tempScop->getMaxLoopDepth() > 0) ++RichScopFound;
scop = new Scop(*tempScop, LI, SE);
return false;
}
char ScopInfo::ID = 0;
static RegisterPass<ScopInfo>
X("polly-scops", "Polly - Create polyhedral description of Scops");
Pass *polly::createScopInfoPass() {
return new ScopInfo();
}

42
polly/lib/Analysis/ScopPass.cpp Executable file
View File

@ -0,0 +1,42 @@
//===- 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 = 0;
if ((S = getAnalysis<ScopInfo>().getScop()))
return runOnScop(*S);
return false;
}
isl_ctx *ScopPass::getIslContext() {
assert(S && "Not in on a Scop!");
return S->getCtx();
}
void ScopPass::print(raw_ostream &OS, const Module *M) const {
if (S)
printScop(OS);
}
void ScopPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<ScopInfo>();
AU.setPreservesAll();
}

View File

@ -0,0 +1,523 @@
//===---------- 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/LinkAllPasses.h"
#include "polly/Support/AffineSCEVIterator.h"
#include "polly/Support/GICHelper.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/ADT/STLExtras.h"
#define DEBUG_TYPE "polly-analyze-ir"
#include "llvm/Support/Debug.h"
using namespace llvm;
using namespace polly;
//===----------------------------------------------------------------------===//
/// Helper Class
SCEVAffFunc::SCEVAffFunc(const SCEV *S, SCEVAffFuncType Type, Region &R,
ParamSetType &Params, LoopInfo *LI,
ScalarEvolution *SE)
: ElemBytes(0), FuncType(Type), has_sign(true) {
assert(S && "S can not be null!");
assert(!isa<SCEVCouldNotCompute>(S) && "Non affine function in Scop");
for (AffineSCEVIterator I = affine_begin(S, SE), E = affine_end();
I != E; ++I) {
// The constant part must be a SCEVConstant.
// TODO: support sizeof in coefficient.
assert(isa<SCEVConstant>(I->second)
&& "Expected SCEVConst in coefficient!");
const SCEV *Var = I->first;
if (isa<SCEVConstant>(Var)) // Extract the constant part.
// Add the translation component.
TransComp = I->second;
else if (Var->getType()->isPointerTy()) { // Extract the base address.
const SCEVUnknown *Addr = dyn_cast<SCEVUnknown>(Var);
assert(Addr && "Broken SCEV detected!");
BaseAddr = Addr->getValue();
} else { // Extract other affine components.
LnrTrans.insert(*I);
if (isIndVar(Var, R, *LI, *SE))
continue;
assert(isParameter(Var, R, *LI, *SE)
&& "Found non affine function in Scop!");
Params.insert(Var);
}
}
}
void SCEVAffFunc::print(raw_ostream &OS, bool PrintInequality) const {
// Print BaseAddr.
if (isDataRef()) {
OS << (isRead() ? "Reads" : "Writes") << " ";
WriteAsOperand(OS, getBaseAddr(), false);
OS << "[";
}
for (LnrTransSet::const_iterator I = LnrTrans.begin(), E = LnrTrans.end();
I != E; ++I)
OS << *I->second << " * " << *I->first << " + ";
if (TransComp)
OS << *TransComp;
if (isDataRef())
OS << "]";
if (!PrintInequality)
return;
if (getType() == GE)
OS << " >= 0";
else if (getType() == Eq)
OS << " == 0";
else if (getType() == Ne)
OS << " != 0";
}
void SCEVAffFunc::dump() const {
print(errs());
}
inline raw_ostream &operator<<(raw_ostream &OS, const SCEVAffFunc &AffFunc) {
AffFunc.print(OS);
return OS;
}
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() {
if (MayASInfo) delete MayASInfo;
}
void TempScop::print(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI) const {
OS << "Scop: " << R.getNameStr() << "\tParameters: (";
// Print Parameters.
for (ParamSetType::const_iterator PI = Params.begin(), PE = Params.end();
PI != PE; ++PI)
OS << **PI << ", ";
OS << "), Max Loop Depth: "<< MaxLoopDepth <<"\n";
printDetail(OS, SE, LI, &R, 0);
}
void TempScop::printDetail(llvm::raw_ostream &OS, ScalarEvolution *SE,
LoopInfo *LI, const Region *CurR,
unsigned ind) const {
// Print the loop bounds, if the current region is a loop.
LoopBoundMapType::const_iterator at = LoopBounds.find(castToLoop(*CurR, *LI));
if (at != LoopBounds.end()) {
OS.indent(ind) << "Bounds of Loop: " << at->first->getHeader()->getName()
<< ":\t{ ";
at->second.print(OS, false);
OS << " }\n";
ind += 2;
}
// Iterate over the region nodes of this Scop to print the access functions
// and loop bounds.
for (Region::const_element_iterator I = CurR->element_begin(),
E = CurR->element_end(); I != E; ++I) {
if (I->isSubRegion()) {
Region *subR = I->getNodeAs<Region>();
printDetail(OS, SE, LI, subR, ind + 2);
} else {
BasicBlock *BB = I->getNodeAs<BasicBlock>();
if (const AccFuncSetType *AccFunc = getAccessFunctions(BB)) {
OS.indent(ind) << "BB: " << BB->getName() << "{\n";
for (AccFuncSetType::const_iterator FI = AccFunc->begin(),
FE = AccFunc->end(); FI != FE; ++FI) {
const SCEVAffFunc &AF = FI->first;
const Value *Ptr = AF.getBaseAddr();
OS.indent(ind + 2) << AF << " Refs: ";
for (MayAliasSetInfo::const_alias_iterator
MI = MayASInfo->alias_begin(Ptr), ME = MayASInfo->alias_end(Ptr);
MI != ME; ++MI) {
MI->second->print(OS);
OS << ", ";
}
OS << '\n';
}
if (Reductions.count(BB))
OS.indent(ind + 2) << "Reduction\n";
OS.indent(ind) << "}\n";
}
}
}
}
void TempScopInfo::buildAffineFunction(const SCEV *S, SCEVAffFunc &FuncToBuild,
Region &R, ParamSetType &Params) const {
assert(S && "S can not be null!");
assert(!isa<SCEVCouldNotCompute>(S)
&& "Un Expect broken affine function in Scop!");
for (AffineSCEVIterator I = affine_begin(S, SE), E = affine_end();
I != E; ++I) {
// The constant part must be a SCEVConstant.
// TODO: support sizeof in coefficient.
assert(isa<SCEVConstant>(I->second) && "Expect SCEVConst in coefficient!");
const SCEV *Var = I->first;
// Extract the constant part
if (isa<SCEVConstant>(Var))
// Add the translation component
FuncToBuild.TransComp = I->second;
else if (Var->getType()->isPointerTy()) { // Extract the base address
const SCEVUnknown *BaseAddr = dyn_cast<SCEVUnknown>(Var);
assert(BaseAddr && "Why we got a broken scev?");
FuncToBuild.BaseAddr = BaseAddr->getValue();
} else { // Extract other affine components.
FuncToBuild.LnrTrans.insert(*I);
// Do not add the indvar to the parameter list.
if (!isIndVar(Var, R, *LI, *SE)) {
DEBUG(dbgs() << "Non indvar: "<< *Var << '\n');
assert(isParameter(Var, R, *LI, *SE)
&& "Find non affine function in scop!");
Params.insert(Var);
}
}
}
}
bool TempScopInfo::isReduction(BasicBlock &BB) {
int loadAccess = 0, storeAccess = 0;
const StoreInst *storeInst;
const Value *storePointer;
const LoadInst *loadInst[2];
const Value *loadPointer[2];
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) {
Instruction &Inst = *I;
if (isa<LoadInst>(&Inst)) {
if (loadAccess >= 2)
return false;
loadInst[loadAccess] = dyn_cast<LoadInst>(&Inst);
loadPointer[loadAccess] = loadInst[loadAccess]->getPointerOperand();
loadAccess++;
} else if (isa<StoreInst>(&Inst)) {
if (storeAccess >= 1)
return false;
storeInst = dyn_cast<StoreInst>(&Inst);
storePointer = storeInst->getPointerOperand();
storeAccess++;
}
}
if (loadAccess < 2)
return false;
if (loadPointer[0] == loadPointer[1])
return false;
const Value *reductionLoadInst;
if (storePointer == loadPointer[0])
reductionLoadInst = loadInst[0];
else if (storePointer == loadPointer[1])
reductionLoadInst = loadInst[1];
else
return false;
const Instruction *reductionInst =
dyn_cast<Instruction>(storeInst->getValueOperand());
// Check if the value stored is an instruction
if (!reductionInst)
return false;
// Reduction operations must be associative and commutative
if (!reductionInst->isAssociative() || !reductionInst->isCommutative())
return false;
// Check if this instruction is using the loaded value
for (User::const_op_iterator I = reductionInst->op_begin(),
E = reductionInst->op_end(); I != E; I++) {
const Value *operand = I->get();
if (operand == reductionLoadInst) {
// The loaded value's one and only use must be this one.
return operand->hasOneUse();
}
}
return false;
}
void TempScopInfo::buildAccessFunctions(Region &R, ParamSetType &Params,
BasicBlock &BB) {
AccFuncSetType Functions;
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) {
Instruction &Inst = *I;
if (isa<LoadInst>(&Inst) || isa<StoreInst>(&Inst)) {
// Create the SCEVAffFunc.
if (LoadInst *ld = dyn_cast<LoadInst>(&Inst)) {
unsigned size = TD->getTypeStoreSize(ld->getType());
Functions.push_back(
std::make_pair(SCEVAffFunc(SCEVAffFunc::ReadMem, size), &Inst));
} else {//Else it must be a StoreInst.
StoreInst *st = cast<StoreInst>(&Inst);
unsigned size = TD->getTypeStoreSize(st->getValueOperand()->getType());
Functions.push_back(
std::make_pair(SCEVAffFunc(SCEVAffFunc::WriteMem, size), &Inst));
}
Value *Ptr = getPointerOperand(Inst);
buildAffineFunction(SE->getSCEV(Ptr), Functions.back().first, R, Params);
}
}
if (Functions.empty())
return;
AccFuncSetType &Accs = AccFuncMap[&BB];
Accs.insert(Accs.end(), Functions.begin(), Functions.end());
}
void TempScopInfo::buildLoopBounds(TempScop &Scop) {
Region &R = Scop.getMaxRegion();
unsigned MaxLoopDepth = 0;
for (Region::block_iterator I = R.block_begin(), E = R.block_end();
I != E; ++I) {
Loop *L = LI->getLoopFor(I->getNodeAs<BasicBlock>());
if (!L || !R.contains(L))
continue;
if (LoopBounds.find(L) != LoopBounds.end())
continue;
LoopBounds[L] = SCEVAffFunc(SCEVAffFunc::Eq);
const SCEV *LoopCount = SE->getBackedgeTakenCount(L);
buildAffineFunction(LoopCount, LoopBounds[L], Scop.getMaxRegion(),
Scop.getParamSet());
Loop *OL = R.outermostLoopInRegion(L);
unsigned LoopDepth = L->getLoopDepth() - OL->getLoopDepth() + 1;
if (LoopDepth > MaxLoopDepth)
MaxLoopDepth = LoopDepth;
}
Scop.MaxLoopDepth = MaxLoopDepth;
}
void TempScopInfo::buildAffineCondition(Value &V, bool inverted,
Comparison **Comp,
TempScop &Scop) const {
Region &R = Scop.getMaxRegion();
ParamSetType &Params = Scop.getParamSet();
if (ConstantInt *C = dyn_cast<ConstantInt>(&V)) {
// If this is always true condition, we will create 1 >= 0,
// otherwise we will create 1 == 0.
SCEVAffFunc *AffLHS = new SCEVAffFunc(SE->getConstant(C->getType(), 0),
SCEVAffFunc::Eq, R, Params, LI, SE);
SCEVAffFunc *AffRHS = new SCEVAffFunc(SE->getConstant(C->getType(), 1),
SCEVAffFunc::Eq, R, Params, LI, SE);
if (C->isOne() == inverted)
*Comp = new Comparison(AffRHS, AffLHS, ICmpInst::ICMP_NE);
else
*Comp = new Comparison(AffLHS, AffLHS, ICmpInst::ICMP_EQ);
return;
}
ICmpInst *ICmp = dyn_cast<ICmpInst>(&V);
assert(ICmp && "Only ICmpInst of constant as condition supported!");
const SCEV *LHS = SE->getSCEV(ICmp->getOperand(0)),
*RHS = SE->getSCEV(ICmp->getOperand(1));
ICmpInst::Predicate Pred = ICmp->getPredicate();
// Invert the predicate if needed.
if (inverted)
Pred = ICmpInst::getInversePredicate(Pred);
SCEVAffFunc *AffLHS = new SCEVAffFunc(LHS, SCEVAffFunc::Eq, R, Params, LI,
SE);
SCEVAffFunc *AffRHS = new SCEVAffFunc(RHS, SCEVAffFunc::Eq, R, Params, LI,
SE);
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;
}
*Comp = new Comparison(AffLHS, AffRHS, Pred);
}
void TempScopInfo::buildCondition(BasicBlock *BB, BasicBlock *RegionEntry,
TempScop &Scop) {
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. Add all
// conditions on the path to BB except if BB postdominates the block
// containing the condition.
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;
// Is BB on the ELSE side of the branch?
bool inverted = DT->dominates(Br->getSuccessor(1), BB);
Comparison *Cmp;
buildAffineCondition(*(Br->getCondition()), inverted, &Cmp, Scop);
Cond.push_back(*Cmp);
}
if (!Cond.empty())
BBConds[BB] = Cond;
}
TempScop *TempScopInfo::buildTempScop(Region &R) {
TempScop *TScop = new TempScop(R, LoopBounds, BBConds, AccFuncMap);
for (Region::block_iterator I = R.block_begin(), E = R.block_end();
I != E; ++I) {
BasicBlock *BB = I->getNodeAs<BasicBlock>();
buildAccessFunctions(R, TScop->getParamSet(), *BB);
buildCondition(BB, R.getEntry(), *TScop);
if (isReduction(*BB))
TScop->Reductions.insert(BB);
}
buildLoopBounds(*TScop);
// Build the MayAliasSets.
TScop->MayASInfo->buildMayAliasSets(*TScop, *AA);
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<DominatorTree>();
PDT = &getAnalysis<PostDominatorTree>();
SE = &getAnalysis<ScalarEvolution>();
LI = &getAnalysis<LoopInfo>();
SD = &getAnalysis<ScopDetection>();
AA = &getAnalysis<AliasAnalysis>();
TD = &getAnalysis<TargetData>();
for (ScopDetection::iterator I = SD->begin(), E = SD->end(); I != E; ++I) {
Region *R = const_cast<Region*>(*I);
TempScops.insert(std::make_pair(R, buildTempScop(*R)));
}
return false;
}
void TempScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<TargetData>();
AU.addRequiredTransitive<DominatorTree>();
AU.addRequiredTransitive<PostDominatorTree>();
AU.addRequiredTransitive<LoopInfo>();
AU.addRequiredTransitive<ScalarEvolution>();
AU.addRequiredTransitive<ScopDetection>();
AU.addRequiredID(IndependentBlocksID);
AU.addRequired<AliasAnalysis>();
AU.setPreservesAll();
}
TempScopInfo::~TempScopInfo() {
clear();
}
void TempScopInfo::clear() {
BBConds.clear();
LoopBounds.clear();
AccFuncMap.clear();
DeleteContainerSeconds(TempScops);
TempScops.clear();
}
//===----------------------------------------------------------------------===//
// TempScop information extraction pass implement
char TempScopInfo::ID = 0;
static RegisterPass<TempScopInfo>
X("polly-analyze-ir", "Polly - Analyse the LLVM-IR in the detected regions");

49
polly/lib/CMakeLists.txt Executable file
View File

@ -0,0 +1,49 @@
add_subdirectory(Analysis)
add_subdirectory(Support)
add_subdirectory(JSON)
set(MODULE TRUE)
set(LLVM_NO_RTTI 1)
if (OPENSCOP_FOUND)
set(POLLY_EXCHANGE_FILES
Exchange/OpenScopImporter.cpp Exchange/OpenScopExporter.cpp)
endif (OPENSCOP_FOUND)
if (SCOPLIB_FOUND)
set(POLLY_SCOPLIB_FILES
Pocc.cpp
Exchange/ScopLib.cpp
Exchange/ScopLibExporter.cpp
Exchange/ScopLibImporter.cpp)
endif (SCOPLIB_FOUND)
set(LLVM_USED_LIBS
PollyAnalysis
PollySupport
PollyJSON
)
add_polly_library(LLVMPolly
Cloog.cpp
CodePreparation.cpp
CodeGeneration.cpp
IndependentBlocks.cpp
Interchange.cpp
MayAliasSet.cpp
Pocc.cpp
RegionSimplify.cpp
Exchange/JSONExporter.cpp
${POLLY_EXCHANGE_FILES}
${POLLY_SCOPLIB_FILES}
)
add_dependencies(LLVMPolly
PollyAnalysis
PollySupport
PollyJSON
)
set_target_properties(LLVMPolly
PROPERTIES
LINKER_LANGUAGE CXX
PREFIX "")

299
polly/lib/Cloog.cpp Normal file
View File

@ -0,0 +1,299 @@
//===- Cloog.cpp - Cloog interface ----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Cloog[1] interface.
//
// The Cloog interface takes a Scop and generates a Cloog AST (clast). This
// clast can either be returned directly or it can be pretty printed to stdout.
//
// A typical clast output looks like this:
//
// for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) {
// bb2(c2);
// }
//
// [1] http://www.cloog.org/ - The Chunky Loop Generator
//
//===----------------------------------------------------------------------===//
#include "polly/Cloog.h"
#include "polly/LinkAllPasses.h"
#include "polly/ScopInfo.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Module.h"
#include "cloog/isl/domain.h"
using namespace llvm;
using namespace polly;
namespace polly {
class Cloog {
Scop *S;
CloogOptions *Options;
CloogState *State;
clast_stmt *ClastRoot;
void buildCloogOptions();
CloogUnionDomain *buildCloogUnionDomain();
CloogInput *buildCloogInput();
public:
Cloog(Scop *Scop);
~Cloog();
/// Write a .cloog input file
void dump(FILE *F);
/// Print a source code representation of the program.
void pprint(llvm::raw_ostream &OS);
/// Create the Cloog AST from this program.
struct clast_stmt *getClast();
};
Cloog::Cloog(Scop *Scop) : S(Scop) {
State = cloog_state_malloc();
buildCloogOptions();
ClastRoot = cloog_clast_create_from_input(buildCloogInput(), Options);
}
Cloog::~Cloog() {
cloog_options_free(Options);
cloog_clast_free(ClastRoot);
cloog_state_free(State);
}
// Create a FILE* write stream and get the output to it written
// to a std::string.
class FileToString {
int FD[2];
FILE *input;
static const int BUFFERSIZE = 20;
char buf[BUFFERSIZE + 1];
public:
FileToString() {
pipe(FD);
input = fdopen(FD[1], "w");
}
~FileToString() {
close(FD[0]);
//close(FD[1]);
}
FILE *getInputFile() {
return input;
}
void closeInput() {
fclose(input);
close(FD[1]);
}
std::string getOutput() {
std::string output;
int readSize;
while (true) {
readSize = read(FD[0], &buf, BUFFERSIZE);
if (readSize <= 0)
break;
output += std::string(buf, readSize);
}
return output;
}
};
/// Write .cloog input file.
void Cloog::dump(FILE *F) {
CloogInput *Input = buildCloogInput();
cloog_input_dump_cloog(F, Input, Options);
cloog_input_free(Input);
}
/// Print a source code representation of the program.
void Cloog::pprint(raw_ostream &OS) {
FileToString *Output = new FileToString();
clast_pprint(Output->getInputFile(), ClastRoot, 0, Options);
Output->closeInput();
OS << Output->getOutput();
delete (Output);
}
/// Create the Cloog AST from this program.
struct clast_stmt *Cloog::getClast() {
return ClastRoot;
}
void Cloog::buildCloogOptions() {
Options = cloog_options_malloc(State);
Options->quiet = 1;
Options->strides = 1;
Options->save_domains = 1;
Options->noscalars = 1;
}
CloogUnionDomain *Cloog::buildCloogUnionDomain() {
CloogUnionDomain *DU = cloog_union_domain_alloc(S->getNumParams());
for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
if (Stmt->isFinalRead())
continue;
CloogScattering *Scattering=
cloog_scattering_from_isl_map(isl_map_copy(Stmt->getScattering()));
CloogDomain *Domain =
cloog_domain_from_isl_set(isl_set_copy(Stmt->getDomain()));
std::string entryName = Stmt->getBaseName();
char *Name = (char*)malloc(sizeof(char) * (entryName.size() + 1));
strcpy(Name, entryName.c_str());
DU = cloog_union_domain_add_domain(DU, Name, Domain, Scattering, Stmt);
}
return DU;
}
CloogInput *Cloog::buildCloogInput() {
CloogDomain *Context =
cloog_domain_from_isl_set(isl_set_copy(S->getContext()));
CloogUnionDomain *Statements = buildCloogUnionDomain();
CloogInput *Input = cloog_input_alloc (Context, Statements);
return Input;
}
} // End namespace polly.
namespace {
struct CloogExporter : public ScopPass {
static char ID;
Scop *S;
explicit CloogExporter() : ScopPass(ID) {}
std::string getFileName(Region *R) const;
virtual bool runOnScop(Scop &S);
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
std::string CloogExporter::getFileName(Region *R) const {
std::string FunctionName = R->getEntry()->getParent()->getNameStr();
std::string ExitName, EntryName;
raw_string_ostream ExitStr(ExitName);
raw_string_ostream EntryStr(EntryName);
WriteAsOperand(EntryStr, R->getEntry(), false);
EntryStr.str();
if (R->getExit()) {
WriteAsOperand(ExitStr, R->getExit(), false);
ExitStr.str();
} else
ExitName = "FunctionExit";
std::string RegionName = EntryName + "---" + ExitName;
std::string FileName = FunctionName + "___" + RegionName + ".cloog";
return FileName;
}
char CloogExporter::ID = 0;
bool CloogExporter::runOnScop(Scop &S) {
Region &R = S.getRegion();
CloogInfo &C = getAnalysis<CloogInfo>();
std::string FunctionName = R.getEntry()->getParent()->getNameStr();
std::string Filename = getFileName(&R);
errs() << "Writing Scop '" << R.getNameStr() << "' in function '"
<< FunctionName << "' to '" << Filename << "'...\n";
FILE *F = fopen(Filename.c_str(), "w");
C.dump(F);
fclose(F);
return false;
}
void CloogExporter::getAnalysisUsage(AnalysisUsage &AU) const {
// Get the Common analysis usage of ScopPasses.
ScopPass::getAnalysisUsage(AU);
AU.addRequired<CloogInfo>();
}
static RegisterPass<CloogExporter> A("polly-export-cloog",
"Polly - Export the Cloog input file"
" (Writes a .cloog file for each Scop)"
);
llvm::Pass* polly::createCloogExporterPass() {
return new CloogExporter();
}
/// Write a .cloog input file
void CloogInfo::dump(FILE *F) {
C->dump(F);
}
/// Print a source code representation of the program.
void CloogInfo::pprint(llvm::raw_ostream &OS) {
C->pprint(OS);
}
/// Create the Cloog AST from this program.
const struct clast_stmt *CloogInfo::getClast() {
return C->getClast();
}
bool CloogInfo::runOnScop(Scop &S) {
if (C)
delete C;
scop = &S;
C = new Cloog(&S);
return false;
}
void CloogInfo::printScop(raw_ostream &OS) const {
Function *function = scop->getRegion().getEntry()->getParent();
OS << function->getNameStr() << "():\n";
C->pprint(OS);
}
void CloogInfo::getAnalysisUsage(AnalysisUsage &AU) const {
// Get the Common analysis usage of ScopPasses.
ScopPass::getAnalysisUsage(AU);
}
char CloogInfo::ID = 0;
static RegisterPass<CloogInfo> B("polly-cloog",
"Execute Cloog code generation");
Pass* polly::createCloogInfoPass() {
return new CloogInfo();
}

1497
polly/lib/CodeGeneration.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
//===---- 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.
//
//===----------------------------------------------------------------------===//
//
// This file implement the code preparation for Scop detect, which will:
// 1. Translate all PHINodes that not induction variable to memory access,
// this will easier parameter and scalar dependencies checking.
//
//===----------------------------------------------------------------------===//
#include "polly/LinkAllPasses.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/Instruction.h"
#include "llvm/Pass.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Transforms/Utils/Local.h"
#define DEBUG_TYPE "polly-code-prep"
#include "llvm/Support/Debug.h"
using namespace llvm;
using namespace polly;
namespace {
//===----------------------------------------------------------------------===//
/// @brief Scop Code Preparation - Perform some transforms to make scop detect
/// easier.
///
class CodePreperation : public FunctionPass {
// DO NOT IMPLEMENT.
CodePreperation(const CodePreperation &);
// DO NOT IMPLEMENT.
const CodePreperation &operator=(const CodePreperation &);
// LoopInfo to compute canonical induction variable.
LoopInfo *LI;
// Clear the context.
void clear();
bool eliminatePHINodes(Function &F);
public:
static char ID;
explicit CodePreperation() : FunctionPass(ID) {}
~CodePreperation();
/// @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;
//@}
};
}
//===----------------------------------------------------------------------===//
/// CodePreperation implement.
void CodePreperation::clear() {
}
CodePreperation::~CodePreperation() {
clear();
}
bool CodePreperation::eliminatePHINodes(Function &F) {
// The PHINodes that will be deleted.
std::vector<PHINode*> PNtoDel;
// The PHINodes that will be preserved.
std::vector<PHINode*> PreservedPNs;
// Scan the PHINodes in this function.
for (Function::iterator ibb = F.begin(), ibe = F.end();
ibb != ibe; ++ibb)
for (BasicBlock::iterator iib = ibb->begin(), iie = ibb->getFirstNonPHI();
iib != iie; ++iib)
if (PHINode *PN = cast<PHINode>(iib)) {
if (Loop *L = LI->getLoopFor(ibb)) {
// Induction variable will be preserved.
if (L->getCanonicalInductionVariable() == PN) {
PreservedPNs.push_back(PN);
continue;
}
}
// As DemotePHIToStack does not support invoke edges, we preserve
// PHINodes that have invoke edges.
if (hasInvokeEdge(PN))
PreservedPNs.push_back(PN);
else
PNtoDel.push_back(PN);
}
if (PNtoDel.empty())
return false;
// Eliminate the PHINodes that not an Induction variable.
while (!PNtoDel.empty()) {
PHINode *PN = PNtoDel.back();
PNtoDel.pop_back();
DemotePHIToStack(PN);
}
// Move all preserved PHINodes to the beginning of the BasicBlock.
while (!PreservedPNs.empty()) {
PHINode *PN = PreservedPNs.back();
PreservedPNs.pop_back();
BasicBlock *BB = PN->getParent();
if (PN == BB->begin())
continue;
PN->moveBefore(BB->begin());
}
return true;
}
void CodePreperation::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LoopInfo>();
AU.addPreserved<LoopInfo>();
AU.addPreserved<RegionInfo>();
AU.addPreserved<DominatorTree>();
AU.addPreserved<DominanceFrontier>();
}
bool CodePreperation::runOnFunction(Function &F) {
LI = &getAnalysis<LoopInfo>();
splitEntryBlockForAlloca(&F.getEntryBlock(), this);
eliminatePHINodes(F);
return false;
}
void CodePreperation::releaseMemory() {
clear();
}
void CodePreperation::print(raw_ostream &OS, const Module *) const {
}
char CodePreperation::ID = 0;
RegisterPass<CodePreperation> X("polly-prepare",
"Polly - Prepare code for polly.",
false, true);
char &polly::CodePreperationID = CodePreperation::ID;
Pass *polly::createCodePreperationPass() {
return new CodePreperation();
}

View File

@ -0,0 +1,261 @@
//===-- 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/Dependences.h"
#include "polly/ScopInfo.h"
#include "polly/ScopPass.h"
#include "json/reader.h"
#include "json/writer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/system_error.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/Writer.h"
#include "stdio.h"
#include "isl/set.h"
#include "isl/map.h"
#include "isl/constraint.h"
#include "isl/printer.h"
#include <string>
using namespace llvm;
using namespace polly;
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("."));
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(""));
struct JSONExporter : public ScopPass {
static char ID;
Scop *S;
explicit JSONExporter() : ScopPass(ID) {}
std::string getFileName(Scop *S) const;
Json::Value getJSON(Scop &scop) const;
virtual bool runOnScop(Scop &S);
void printScop(raw_ostream &OS) const;
void getAnalysisUsage(AnalysisUsage &AU) const;
};
struct JSONImporter : public ScopPass {
static char ID;
Scop *S;
explicit JSONImporter() : ScopPass(ID) {}
std::string getFileName(Scop *S) const;
virtual bool runOnScop(Scop &S);
void printScop(raw_ostream &OS) const;
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char JSONExporter::ID = 0;
std::string JSONExporter::getFileName(Scop *S) const {
std::string FunctionName =
S->getRegion().getEntry()->getParent()->getNameStr();
std::string FileName = FunctionName + "___" + S->getNameStr() + ".jscop";
return FileName;
}
void JSONExporter::printScop(raw_ostream &OS) const {
S->print(OS);
}
Json::Value JSONExporter::getJSON(Scop &scop) const {
Json::Value root;
root["name"] = S->getRegion().getNameStr();
root["context"] = S->getContextStr();
root["statements"];
for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
if (Stmt->isFinalRead())
continue;
Json::Value statement;
statement["name"] = Stmt->getBaseName();
statement["domain"] = Stmt->getDomainStr();
statement["schedule"] = Stmt->getScatteringStr();
statement["accesses"];
for (ScopStmt::memacc_iterator MI = Stmt->memacc_begin(),
ME = Stmt->memacc_end(); MI != ME; ++MI) {
Json::Value access;
access["kind"] = (*MI)->isRead() ? "read" : "write";
access["relation"] = (*MI)->getAccessFunctionStr();
statement["accesses"].append(access);
}
root["statements"].append(statement);
}
return root;
}
bool JSONExporter::runOnScop(Scop &scop) {
S = &scop;
Region &R = S->getRegion();
std::string FileName = ImportDir + "/" + getFileName(S);
char *text;
Json::Value jscop = getJSON(scop);
Json::StyledWriter writer;
std::string fileContent = writer.write(jscop);
// Write to file.
std::string ErrInfo;
tool_output_file F(FileName.c_str(), ErrInfo);
std::string FunctionName = R.getEntry()->getParent()->getNameStr();
errs() << "Writing JScop '" << R.getNameStr() << "' in function '"
<< FunctionName << "' to '" << FileName << "'.\n";
if (ErrInfo.empty()) {
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>();
}
static RegisterPass<JSONExporter> A("polly-export-jscop",
"Polly - Export Scops as JSON"
" (Writes a .jscop file for each Scop)"
);
Pass *polly::createJSONExporterPass() {
return new JSONExporter();
}
char JSONImporter::ID = 0;
std::string JSONImporter::getFileName(Scop *S) const {
std::string FunctionName =
S->getRegion().getEntry()->getParent()->getNameStr();
std::string FileName = FunctionName + "___" + S->getNameStr() + ".jscop";
if (ImportPostfix != "")
FileName += "." + ImportPostfix;
return FileName;
}
void JSONImporter::printScop(raw_ostream &OS) const {
S->print(OS);
}
typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
bool JSONImporter::runOnScop(Scop &scop) {
S = &scop;
Region &R = S->getRegion();
Dependences *D = &getAnalysis<Dependences>();
std::string FileName = ImportDir + "/" + getFileName(S);
std::string FunctionName = R.getEntry()->getParent()->getNameStr();
errs() << "Reading JScop '" << R.getNameStr() << "' in function '"
<< FunctionName << "' from '" << FileName << "'.\n";
OwningPtr<MemoryBuffer> result;
error_code ec = MemoryBuffer::getFile(FileName, result);
if (ec) {
errs() << "File could not be read: " << ec.message() << "\n";
return false;
}
Json::Reader reader;
Json::Value jscop;
bool parsingSuccessful = reader.parse(result->getBufferStart(), jscop);
if (!parsingSuccessful) {
errs() << "JSCoP file could not be parsed\n";
return false;
}
StatementToIslMapTy &NewScattering = *(new StatementToIslMapTy());
int index = 0;
for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
if (Stmt->isFinalRead())
continue;
Json::Value schedule = jscop["statements"][index]["schedule"];
isl_map *m = isl_map_read_from_str(S->getCtx(), schedule.asCString(), -1);
NewScattering[*SI] = m;
index++;
}
if (!D->isValidScattering(&NewScattering)) {
errs() << "JScop file contains a scattering that changes the "
<< "dependences. Use -disable-polly-legality to continue anyways\n";
return false;
}
for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
if (NewScattering.find(Stmt) != NewScattering.end())
Stmt->setScattering((NewScattering)[Stmt]);
}
return false;
}
void JSONImporter::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
AU.addRequired<Dependences>();
}
static RegisterPass<JSONImporter> B("polly-import-jscop",
"Polly - Import Scops from JSON"
" (Reads a .jscop file for each Scop)"
);
Pass *polly::createJSONImporterPass() {
return new JSONImporter();
}

16
polly/lib/Exchange/Makefile Executable file
View File

@ -0,0 +1,16 @@
##===- polly/lib/Exchange/Makefile ----------------*- Makefile -*-===##
#
# Indicate where we are relative to the top of the source tree.
#
LEVEL=../..
LIBRARYNAME=pollyexchange
BUILD_ARCHIVE = 1
CPP.Flags += $(POLLY_INC)
#
# Include Makefile.common so we know what to do.
#
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,583 @@
//===-- OpenScopExporter.cpp - Export Scops with openscop library --------===//
//
// 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 to text file.
//
//===----------------------------------------------------------------------===//
#include "polly/LinkAllPasses.h"
#ifdef OPENSCOP_FOUND
#include "polly/ScopInfo.h"
#include "polly/ScopPass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Assembly/Writer.h"
#define OPENSCOP_INT_T_IS_MP
#include "openscop/openscop.h"
#include "stdio.h"
#include "isl/set.h"
#include "isl/constraint.h"
using namespace llvm;
using namespace polly;
namespace {
static cl::opt<std::string>
ExportDir("polly-export-dir",
cl::desc("The directory to export the .scop files to."), cl::Hidden,
cl::value_desc("Directory path"), cl::ValueRequired, cl::init("."));
struct ScopExporter : public ScopPass {
static char ID;
Scop *S;
explicit ScopExporter() : ScopPass(ID) {}
std::string getFileName(Scop *S) const;
virtual bool runOnScop(Scop &S);
void printScop(raw_ostream &OS) const;
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char ScopExporter::ID = 0;
class OpenScop {
Scop *PollyScop;
openscop_scop_p openscop;
std::map<const Value*, int> ArrayMap;
void initializeArrays();
void initializeParameters();
void initializeScattering();
void initializeStatements();
openscop_statement_p initializeStatement(ScopStmt *stmt);
void freeStatement(openscop_statement_p stmt);
static int accessToMatrix_constraint(isl_constraint *c, void *user);
static int accessToMatrix_basic_map(isl_basic_map *bmap, void *user);
openscop_matrix_p createAccessMatrix(ScopStmt *S, bool isRead);
static int domainToMatrix_constraint(isl_constraint *c, void *user);
static int domainToMatrix_basic_set(isl_basic_set *bset, void *user);
openscop_matrix_p domainToMatrix(isl_set *PS);
static int scatteringToMatrix_constraint(isl_constraint *c, void *user);
static int scatteringToMatrix_basic_map(isl_basic_map *bmap, void *user);
openscop_matrix_p scatteringToMatrix(isl_map *pmap);
public:
OpenScop(Scop *S);
~OpenScop();
void print(FILE *F);
};
OpenScop::OpenScop(Scop *S) : PollyScop(S) {
openscop = openscop_scop_malloc();
initializeArrays();
initializeParameters();
initializeScattering();
initializeStatements();
}
void OpenScop::initializeParameters() {
openscop->nb_parameters = PollyScop->getNumParams();
openscop->parameters = new char*[openscop->nb_parameters];
for (int i = 0; i < openscop->nb_parameters; ++i) {
openscop->parameters[i] = new char[20];
sprintf(openscop->parameters[i], "p_%d", i);
}
}
void OpenScop::initializeArrays() {
int nb_arrays = 0;
for (Scop::iterator SI = PollyScop->begin(), SE = PollyScop->end(); SI != SE;
++SI)
for (ScopStmt::memacc_iterator MI = (*SI)->memacc_begin(),
ME = (*SI)->memacc_end(); MI != ME; ++MI) {
const Value *BaseAddr = (*MI)->getBaseAddr();
if (ArrayMap.find(BaseAddr) == ArrayMap.end()) {
ArrayMap.insert(std::make_pair(BaseAddr, nb_arrays));
++nb_arrays;
}
}
openscop->nb_arrays = nb_arrays;
openscop->arrays = new char*[nb_arrays];
for (int i = 0; i < nb_arrays; ++i)
for (std::map<const Value*, int>::iterator VI = ArrayMap.begin(),
VE = ArrayMap.end(); VI != VE; ++VI)
if ((*VI).second == i) {
const Value *V = (*VI).first;
std::string name = V->getNameStr();
openscop->arrays[i] = new char[name.size() + 1];
strcpy(openscop->arrays[i], name.c_str());
}
}
void OpenScop::initializeScattering() {
openscop->nb_scattdims = PollyScop->getScatterDim();
openscop->scattdims = new char*[openscop->nb_scattdims];
for (int i = 0; i < openscop->nb_scattdims; ++i) {
openscop->scattdims[i] = new char[20];
sprintf(openscop->scattdims[i], "s_%d", i);
}
}
openscop_statement_p OpenScop::initializeStatement(ScopStmt *stmt) {
openscop_statement_p Stmt = openscop_statement_malloc();
// Domain & Schedule
Stmt->domain = domainToMatrix(stmt->getDomain());
Stmt->schedule = scatteringToMatrix(stmt->getScattering());
// Statement name
const char* entryName = stmt->getBaseName();
Stmt->body = (char*)malloc(sizeof(char) * (strlen(entryName) + 1));
strcpy(Stmt->body, entryName);
// Iterator names
Stmt->nb_iterators = isl_set_n_dim(stmt->getDomain());
Stmt->iterators = new char*[Stmt->nb_iterators];
for (int i = 0; i < Stmt->nb_iterators; ++i) {
Stmt->iterators[i] = new char[20];
sprintf(Stmt->iterators[i], "i_%d", i);
}
// Memory Accesses
Stmt->read = createAccessMatrix(stmt, true);
Stmt->write = createAccessMatrix(stmt, false);
return Stmt;
}
void OpenScop::initializeStatements() {
for (Scop::reverse_iterator SI = PollyScop->rbegin(), SE = PollyScop->rend();
SI != SE; ++SI) {
if ((*SI)->isFinalRead())
continue;
openscop_statement_p stmt = initializeStatement(*SI);
stmt->next = openscop->statement;
openscop->statement = stmt;
}
}
void OpenScop::freeStatement(openscop_statement_p stmt) {
if (stmt->read)
openscop_matrix_free(stmt->read);
stmt->read = NULL;
if (stmt->write)
openscop_matrix_free(stmt->write);
stmt->write = NULL;
if (stmt->domain)
openscop_matrix_free(stmt->domain);
stmt->domain = NULL;
if (stmt->schedule)
openscop_matrix_free(stmt->schedule);
stmt->schedule = NULL;
for (int i = 0; i < stmt->nb_iterators; ++i)
delete[](stmt->iterators[i]);
delete[](stmt->iterators);
stmt->iterators = NULL;
stmt->nb_iterators = 0;
delete[](stmt->body);
stmt->body = NULL;
openscop_statement_free(stmt);
}
void OpenScop::print(FILE *F) {
openscop_scop_print_dot_scop(F, openscop);
}
/// Add an isl constraint to an OpenScop matrix.
///
/// @param user The matrix
/// @param c The constraint
int OpenScop::domainToMatrix_constraint(isl_constraint *c, void *user) {
openscop_matrix_p m = (openscop_matrix_p) user;
int nb_params = isl_constraint_dim(c, isl_dim_param);
int nb_vars = isl_constraint_dim(c, isl_dim_set);
int nb_div = isl_constraint_dim(c, isl_dim_div);
assert(!nb_div && "Existentially quantified variables not yet supported");
openscop_vector_p vec = openscop_vector_malloc(nb_params + nb_vars + 2);
// Assign type
if (isl_constraint_is_equality(c))
openscop_vector_tag_equality(vec);
else
openscop_vector_tag_inequality(vec);
isl_int v;
isl_int_init(v);
// Assign variables
for (int i = 0; i < nb_vars; ++i) {
isl_constraint_get_coefficient(c, isl_dim_set, i, &v);
isl_int_set(vec->p[i + 1], v);
}
// Assign parameters
for (int i = 0; i < nb_params; ++i) {
isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
isl_int_set(vec->p[nb_vars + i + 1], v);
}
// Assign constant
isl_constraint_get_constant(c, &v);
isl_int_set(vec->p[nb_params + nb_vars + 1], v);
openscop_matrix_insert_vector(m, vec, m->NbRows);
return 0;
}
/// Add an isl basic set to a OpenScop matrix_list
///
/// @param bset The basic set to add
/// @param user The matrix list we should add the basic set to
///
/// XXX: At the moment this function expects just a matrix, as support
/// for matrix lists is currently not available in OpenScop. So union of
/// polyhedron are not yet supported
int OpenScop::domainToMatrix_basic_set(isl_basic_set *bset, void *user) {
openscop_matrix_p m = (openscop_matrix_p) user;
assert(!m->NbRows && "Union of polyhedron not yet supported");
isl_basic_set_foreach_constraint(bset, &domainToMatrix_constraint, user);
return 0;
}
/// Translate a isl_set to a OpenScop matrix.
///
/// @param PS The set to be translated
/// @return A OpenScop Matrix
openscop_matrix_p OpenScop::domainToMatrix(isl_set *PS) {
// Create a canonical copy of this set.
isl_set *set = isl_set_copy(PS);
set = isl_set_compute_divs (set);
set = isl_set_align_divs (set);
// Initialize the matrix.
unsigned NbRows, NbColumns;
NbRows = 0;
NbColumns = isl_set_n_dim(PS) + isl_set_n_param(PS) + 2;
openscop_matrix_p matrix = openscop_matrix_malloc(NbRows, NbColumns);
// Copy the content into the matrix.
isl_set_foreach_basic_set(set, &domainToMatrix_basic_set, matrix);
isl_set_free(set);
return matrix;
}
/// Add an isl constraint to an OpenScop matrix.
///
/// @param user The matrix
/// @param c The constraint
int OpenScop::scatteringToMatrix_constraint(isl_constraint *c, void *user) {
openscop_matrix_p m = (openscop_matrix_p) user;
int nb_params = isl_constraint_dim(c, isl_dim_param);
int nb_in = isl_constraint_dim(c, isl_dim_in);
int nb_out = isl_constraint_dim(c, isl_dim_out);
int nb_div = isl_constraint_dim(c, isl_dim_div);
assert(!nb_div && "Existentially quantified variables not yet supported");
openscop_vector_p vec =
openscop_vector_malloc(nb_params + nb_in + nb_out + 2);
// Assign type
if (isl_constraint_is_equality(c))
openscop_vector_tag_equality(vec);
else
openscop_vector_tag_inequality(vec);
isl_int v;
isl_int_init(v);
// Assign scattering
for (int i = 0; i < nb_out; ++i) {
isl_constraint_get_coefficient(c, isl_dim_out, i, &v);
isl_int_set(vec->p[i + 1], v);
}
// Assign variables
for (int i = 0; i < nb_in; ++i) {
isl_constraint_get_coefficient(c, isl_dim_in, i, &v);
isl_int_set(vec->p[nb_out + i + 1], v);
}
// Assign parameters
for (int i = 0; i < nb_params; ++i) {
isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
isl_int_set(vec->p[nb_out + nb_in + i + 1], v);
}
// Assign constant
isl_constraint_get_constant(c, &v);
isl_int_set(vec->p[nb_out + nb_in + nb_params + 1], v);
openscop_matrix_insert_vector(m, vec, m->NbRows);
return 0;
}
/// Add an isl basic map to a OpenScop matrix_list
///
/// @param bmap The basic map to add
/// @param user The matrix list we should add the basic map to
///
/// XXX: At the moment this function expects just a matrix, as support
/// for matrix lists is currently not available in OpenScop. So union of
/// polyhedron are not yet supported
int OpenScop::scatteringToMatrix_basic_map(isl_basic_map *bmap, void *user) {
openscop_matrix_p m = (openscop_matrix_p) user;
assert(!m->NbRows && "Union of polyhedron not yet supported");
isl_basic_map_foreach_constraint(bmap, &scatteringToMatrix_constraint, user);
return 0;
}
/// Translate a isl_map to a OpenScop matrix.
///
/// @param map The map to be translated
/// @return A OpenScop Matrix
openscop_matrix_p OpenScop::scatteringToMatrix(isl_map *pmap) {
// Create a canonical copy of this set.
isl_map *map = isl_map_copy(pmap);
map = isl_map_compute_divs (map);
map = isl_map_align_divs (map);
// Initialize the matrix.
unsigned NbRows, NbColumns;
NbRows = 0;
NbColumns = isl_map_n_in(pmap) + isl_map_n_out(pmap) + isl_map_n_param(pmap)
+ 2;
openscop_matrix_p matrix = openscop_matrix_malloc(NbRows, NbColumns);
// Copy the content into the matrix.
isl_map_foreach_basic_map(map, &scatteringToMatrix_basic_map, matrix);
isl_map_free(map);
return matrix;
}
/// Add an isl constraint to an OpenScop matrix.
///
/// @param user The matrix
/// @param c The constraint
int OpenScop::accessToMatrix_constraint(isl_constraint *c, void *user) {
openscop_matrix_p m = (openscop_matrix_p) user;
int nb_params = isl_constraint_dim(c, isl_dim_param);
int nb_in = isl_constraint_dim(c, isl_dim_in);
int nb_div = isl_constraint_dim(c, isl_dim_div);
assert(!nb_div && "Existentially quantified variables not yet supported");
openscop_vector_p vec =
openscop_vector_malloc(nb_params + nb_in + 2);
isl_int v;
isl_int_init(v);
// The access dimension has to be one.
isl_constraint_get_coefficient(c, isl_dim_out, 0, &v);
assert(isl_int_is_one(v));
bool inverse = true ;
// Assign variables
for (int i = 0; i < nb_in; ++i) {
isl_constraint_get_coefficient(c, isl_dim_in, i, &v);
if (inverse) isl_int_neg(v,v);
isl_int_set(vec->p[i + 1], v);
}
// Assign parameters
for (int i = 0; i < nb_params; ++i) {
isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
if (inverse) isl_int_neg(v,v);
isl_int_set(vec->p[nb_in + i + 1], v);
}
// Assign constant
isl_constraint_get_constant(c, &v);
if (inverse) isl_int_neg(v,v);
isl_int_set(vec->p[nb_in + nb_params + 1], v);
openscop_matrix_insert_vector(m, vec, m->NbRows);
return 0;
}
/// Add an isl basic map to a OpenScop matrix_list
///
/// @param bmap The basic map to add
/// @param user The matrix list we should add the basic map to
///
/// XXX: At the moment this function expects just a matrix, as support
/// for matrix lists is currently not available in OpenScop. So union of
/// polyhedron are not yet supported
int OpenScop::accessToMatrix_basic_map(isl_basic_map *bmap, void *user) {
isl_basic_map_foreach_constraint(bmap, &accessToMatrix_constraint, user);
return 0;
}
/// Create the memory access matrix for openscop
///
/// @param S The polly statement the access matrix is created for.
/// @param isRead Are we looking for read or write accesses?
/// @param ArrayMap A map translating from the memory references to the openscop
/// indeces
///
/// @return The memory access matrix, as it is required by openscop.
openscop_matrix_p OpenScop::createAccessMatrix(ScopStmt *S, bool isRead) {
unsigned NbColumns = S->getNumIterators() + S->getNumParams() + 2;
openscop_matrix_p m = openscop_matrix_malloc(0, NbColumns);
for (ScopStmt::memacc_iterator MI = S->memacc_begin(), ME = S->memacc_end();
MI != ME; ++MI)
if ((*MI)->isRead() == isRead) {
// Extract the access function.
isl_map_foreach_basic_map((*MI)->getAccessFunction(),
&accessToMatrix_basic_map, m);
// Set the index of the memory access base element.
std::map<const Value*, int>::iterator BA =
ArrayMap.find((*MI)->getBaseAddr());
isl_int_set_si(m->p[m->NbRows - 1][0], (*BA).second + 1);
}
return m;
}
OpenScop::~OpenScop() {
// Free array names.
for (int i = 0; i < openscop->nb_arrays; ++i)
delete[](openscop->arrays[i]);
delete[](openscop->arrays);
openscop->arrays = NULL;
openscop->nb_arrays = 0;
// Free scattering names.
for (int i = 0; i < openscop->nb_scattdims; ++i)
delete[](openscop->scattdims[i]);
delete[](openscop->scattdims);
openscop->scattdims = NULL;
openscop->nb_scattdims = 0;
// Free parameters
for (int i = 0; i < openscop->nb_parameters; ++i)
delete[](openscop->parameters[i]);
delete[](openscop->parameters);
openscop->parameters = NULL;
openscop->nb_parameters = 0;
openscop_statement_p stmt = openscop->statement;
// Free Statements
while (stmt) {
openscop_statement_p TempStmt = stmt->next;
stmt->next = NULL;
freeStatement(stmt);
stmt = TempStmt;
}
openscop->statement = NULL;
openscop_scop_free(openscop);
}
std::string ScopExporter::getFileName(Scop *S) const {
std::string FunctionName =
S->getRegion().getEntry()->getParent()->getNameStr();
std::string FileName = FunctionName + "___" + S->getNameStr() + ".scop";
return FileName;
}
void ScopExporter::printScop(raw_ostream &OS) const {
S->print(OS);
}
bool ScopExporter::runOnScop(Scop &scop) {
S = &scop;
Region &R = S->getRegion();
std::string FileName = ExportDir + "/" + getFileName(S);
FILE *F = fopen(FileName.c_str(), "w");
if (!F) {
errs() << "Cannot open file: " << FileName << "\n";
errs() << "Skipping export.\n";
return false;
}
OpenScop openscop(S);
openscop.print(F);
fclose(F);
std::string FunctionName = R.getEntry()->getParent()->getNameStr();
errs() << "Writing Scop '" << R.getNameStr() << "' in function '"
<< FunctionName << "' to '" << FileName << "'.\n";
return false;
}
void ScopExporter::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
}
static RegisterPass<ScopExporter> A("polly-export",
"Polly - Export Scops with OpenScop library"
" (Writes a .scop file for each Scop)"
);
Pass *polly::createScopExporterPass() {
return new ScopExporter();
}
#endif

View File

@ -0,0 +1,255 @@
//===-- OpenScopImporter.cpp - Import Scops with openscop library --------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Import modified .scop files into Polly. This allows to change the schedule of
// statements.
//
//===----------------------------------------------------------------------===//
#include "polly/LinkAllPasses.h"
#include "polly/Dependences.h"
#include "polly/ScopInfo.h"
#include "polly/ScopPass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Assembly/Writer.h"
#ifdef OPENSCOP_FOUND
#define OPENSCOP_INT_T_IS_MP
#include "openscop/openscop.h"
#include "isl/set.h"
#include "isl/constraint.h"
using namespace llvm;
using namespace polly;
namespace {
static cl::opt<std::string>
ImportDir("polly-import-dir",
cl::desc("The directory to import the .scop files from."),
cl::Hidden, cl::value_desc("Directory path"), cl::ValueRequired,
cl::init("."));
static cl::opt<std::string>
ImportPostfix("polly-import-postfix",
cl::desc("Postfix to append to the import .scop files."),
cl::Hidden, cl::value_desc("File postfix"), cl::ValueRequired,
cl::init(""));
struct ScopImporter : public ScopPass {
static char ID;
Scop *S;
Dependences *D;
explicit ScopImporter() : ScopPass(ID) {}
bool updateScattering(Scop *S, openscop_scop_p OScop);
std::string getFileName(Scop *S) const;
virtual bool runOnScop(Scop &S);
virtual void printScop(raw_ostream &OS) const;
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char ScopImporter::ID = 0;
/// @brief Create an isl constraint from a row of OpenScop integers.
///
/// @param row An array of isl/OpenScop integers.
/// @param dim An isl dim object, describing how to spilt the dimensions.
///
/// @return An isl constraint representing this integer array.
isl_constraint *constraintFromMatrixRow(isl_int *row, isl_dim *dim) {
isl_constraint *c;
unsigned NbOut = isl_dim_size(dim, isl_dim_out);
unsigned NbIn = isl_dim_size(dim, isl_dim_in);
unsigned NbParam = isl_dim_size(dim, isl_dim_param);
if (isl_int_is_zero(row[0]))
c = isl_equality_alloc(isl_dim_copy(dim));
else
c = isl_inequality_alloc(isl_dim_copy(dim));
unsigned current_column = 1;
for (unsigned j = 0; j < NbOut; ++j)
isl_constraint_set_coefficient(c, isl_dim_out, j, row[current_column++]);
for (unsigned j = 0; j < NbIn; ++j)
isl_constraint_set_coefficient(c, isl_dim_in, j, row[current_column++]);
for (unsigned j = 0; j < NbParam; ++j)
isl_constraint_set_coefficient(c, isl_dim_param, j, row[current_column++]);
isl_constraint_set_constant(c, row[current_column]);
return c;
}
/// @brief Create an isl map from a OpenScop matrix.
///
/// @param m The OpenScop matrix to translate.
/// @param dim The dimensions that are contained in the OpenScop matrix.
///
/// @return An isl map representing m.
isl_map *mapFromMatrix(openscop_matrix_p m, isl_dim *dim) {
isl_basic_map *bmap = isl_basic_map_universe(isl_dim_copy(dim));
for (unsigned i = 0; i < m->NbRows; ++i) {
isl_constraint *c;
c = constraintFromMatrixRow(m->p[i], dim);
bmap = isl_basic_map_add_constraint(bmap, c);
}
return isl_map_from_basic_map(bmap);
}
/// @brief Create a new scattering for PollyStmt.
///
/// @param m The matrix describing the new scattering.
/// @param PollyStmt The statement to create the scattering for.
///
/// @return An isl_map describing the scattering.
isl_map *scatteringForStmt(openscop_matrix_p m, ScopStmt *PollyStmt) {
unsigned NbParam = PollyStmt->getNumParams();
unsigned NbIterators = PollyStmt->getNumIterators();
unsigned NbScattering = m->NbColumns - 2 - NbParam - NbIterators;
isl_ctx *ctx = PollyStmt->getParent()->getCtx();
isl_dim *dim = isl_dim_alloc(ctx, NbParam, NbIterators, NbScattering);
dim = isl_dim_set_tuple_name(dim, isl_dim_out, "scattering");
dim = isl_dim_set_tuple_name(dim, isl_dim_in, PollyStmt->getBaseName());
isl_map *map = mapFromMatrix(m, dim);
isl_dim_free(dim);
return map;
}
typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
/// @brief Read the new scattering from the OpenScop description.
///
/// @S The Scop to update
/// @OScop The OpenScop data structure describing the new scattering.
/// @return A map that contains for each Statement the new scattering.
StatementToIslMapTy *readScattering(Scop *S, openscop_scop_p OScop) {
StatementToIslMapTy &NewScattering = *(new StatementToIslMapTy());
openscop_statement_p stmt = OScop->statement;
for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
if ((*SI)->isFinalRead())
continue;
if (!stmt) {
errs() << "Not enough statements available in OpenScop file\n";
delete &NewScattering;
return NULL;
}
NewScattering[*SI] = scatteringForStmt(stmt->schedule, *SI);
stmt = stmt->next;
}
if (stmt) {
errs() << "Too many statements in OpenScop file\n";
delete &NewScattering;
return NULL;
}
return &NewScattering;
}
/// @brief Update the scattering in a Scop using the OpenScop description of
/// the scattering.
///
/// @S The Scop to update
/// @OScop The OpenScop data structure describing the new scattering.
/// @return Returns false, if the update failed.
bool ScopImporter::updateScattering(Scop *S, openscop_scop_p OScop) {
StatementToIslMapTy *NewScattering = readScattering(S, OScop);
if (!NewScattering)
return false;
if (!D->isValidScattering(NewScattering)) {
errs() << "OpenScop file contains a scattering that changes the "
<< "dependences. Use -disable-polly-legality to continue anyways\n";
return false;
}
for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
if (NewScattering->find(Stmt) != NewScattering->end())
Stmt->setScattering((*NewScattering)[Stmt]);
}
return true;
}
std::string ScopImporter::getFileName(Scop *S) const {
std::string FunctionName =
S->getRegion().getEntry()->getParent()->getNameStr();
std::string FileName = FunctionName + "___" + S->getNameStr() + ".scop";
return FileName;
}
void ScopImporter::printScop(raw_ostream &OS) const {
S->print(OS);
}
bool ScopImporter::runOnScop(Scop &scop) {
S = &scop;
Region &R = scop.getRegion();
D = &getAnalysis<Dependences>();
std::string FileName = ImportDir + "/" + getFileName(S) + ImportPostfix;
FILE *F = fopen(FileName.c_str(), "r");
if (!F) {
errs() << "Cannot open file: " << FileName << "\n";
errs() << "Skipping import.\n";
return false;
}
openscop_scop_p openscop = openscop_scop_read(F);
fclose(F);
std::string FunctionName = R.getEntry()->getParent()->getNameStr();
errs() << "Reading Scop '" << R.getNameStr() << "' in function '"
<< FunctionName << "' from '" << FileName << "'.\n";
bool UpdateSuccessfull = updateScattering(S, openscop);
if (!UpdateSuccessfull) {
errs() << "Update failed" << "\n";
}
return false;
}
void ScopImporter::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
AU.addRequired<Dependences>();
}
static RegisterPass<ScopImporter> A("polly-import",
"Polly - Import Scops with OpenScop library"
" (Reads a .scop file for each Scop)"
);
Pass *polly::createScopImporterPass() {
return new ScopImporter();
}
#endif

View File

@ -0,0 +1,722 @@
//===- ScopLib.cpp - ScopLib interface ------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// ScopLib Interface
//
//===----------------------------------------------------------------------===//
#include "polly/LinkAllPasses.h"
#ifdef SCOPLIB_FOUND
#include "polly/Dependences.h"
#include "polly/ScopLib.h"
#include "polly/ScopInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Assembly/Writer.h"
#include "stdio.h"
#include "isl/set.h"
#include "isl/constraint.h"
using namespace llvm;
namespace polly {
ScopLib::ScopLib(Scop *S) : PollyScop(S) {
scoplib = scoplib_scop_malloc();
initializeArrays();
initializeParameters();
initializeScattering();
initializeStatements();
}
ScopLib::ScopLib(Scop *S, FILE *F, Dependences *dep) : PollyScop(S), D(dep) {
scoplib = scoplib_scop_read(F);
}
void ScopLib::initializeParameters() {
scoplib->nb_parameters = PollyScop->getNumParams();
scoplib->parameters = (char**) malloc(sizeof(char*) * scoplib->nb_parameters);
for (int i = 0; i < scoplib->nb_parameters; ++i) {
scoplib->parameters[i] = (char *) malloc(sizeof(char*) * 20);
sprintf(scoplib->parameters[i], "p_%d", i);
}
}
void ScopLib::initializeArrays() {
int nb_arrays = 0;
for (Scop::iterator SI = PollyScop->begin(), SE = PollyScop->end(); SI != SE;
++SI)
for (ScopStmt::memacc_iterator MI = (*SI)->memacc_begin(),
ME = (*SI)->memacc_end(); MI != ME; ++MI) {
const Value *BaseAddr = (*MI)->getBaseAddr();
if (ArrayMap.find(BaseAddr) == ArrayMap.end()) {
ArrayMap.insert(std::make_pair(BaseAddr, nb_arrays));
++nb_arrays;
}
}
scoplib->nb_arrays = nb_arrays;
scoplib->arrays = (char**)malloc(sizeof(char*) * nb_arrays);
for (int i = 0; i < nb_arrays; ++i)
for (std::map<const Value*, int>::iterator VI = ArrayMap.begin(),
VE = ArrayMap.end(); VI != VE; ++VI)
if ((*VI).second == i) {
const Value *V = (*VI).first;
std::string name = V->getNameStr();
scoplib->arrays[i] = (char*) malloc(sizeof(char*) * (name.size() + 1));
strcpy(scoplib->arrays[i], name.c_str());
}
}
void ScopLib::initializeScattering() {
}
scoplib_statement_p ScopLib::initializeStatement(ScopStmt *stmt) {
scoplib_statement_p Stmt = scoplib_statement_malloc();
// Domain & Schedule
Stmt->domain = scoplib_matrix_list_malloc();
Stmt->domain->elt = domainToMatrix(stmt->getDomain());
Stmt->domain->next = NULL;
Stmt->schedule = scatteringToMatrix(stmt->getScattering());
// Statement name
std::string entryName;
raw_string_ostream OS(entryName);
WriteAsOperand(OS, stmt->getBasicBlock(), false);
entryName = OS.str();
Stmt->body = (char*)malloc(sizeof(char) * (entryName.size() + 1));
strcpy(Stmt->body, entryName.c_str());
// Iterator names
Stmt->nb_iterators = isl_set_n_dim(stmt->getDomain());
Stmt->iterators = (char**) malloc(sizeof(char*) * Stmt->nb_iterators);
for (int i = 0; i < Stmt->nb_iterators; ++i) {
Stmt->iterators[i] = (char*) malloc(sizeof(char*) * 20);
sprintf(Stmt->iterators[i], "i_%d", i);
}
// Memory Accesses
Stmt->read = createAccessMatrix(stmt, true);
Stmt->write = createAccessMatrix(stmt, false);
return Stmt;
}
void ScopLib::initializeStatements() {
for (Scop::reverse_iterator SI = PollyScop->rbegin(), SE = PollyScop->rend();
SI != SE; ++SI) {
if ((*SI)->isFinalRead())
continue;
scoplib_statement_p stmt = initializeStatement(*SI);
stmt->next = scoplib->statement;
scoplib->statement = stmt;
}
}
void ScopLib::freeStatement(scoplib_statement_p stmt) {
if (stmt->read)
scoplib_matrix_free(stmt->read);
stmt->read = NULL;
if (stmt->write)
scoplib_matrix_free(stmt->write);
stmt->write = NULL;
while (stmt->domain) {
scoplib_matrix_free(stmt->domain->elt);
stmt->domain = stmt->domain->next;
}
if (stmt->schedule)
scoplib_matrix_free(stmt->schedule);
stmt->schedule = NULL;
for (int i = 0; i < stmt->nb_iterators; ++i)
free(stmt->iterators[i]);
free(stmt->iterators);
stmt->iterators = NULL;
stmt->nb_iterators = 0;
scoplib_statement_free(stmt);
}
void ScopLib::print(FILE *F) {
scoplib_scop_print_dot_scop(F, scoplib);
}
/// Add an isl constraint to an ScopLib matrix.
///
/// @param user The matrix
/// @param c The constraint
int ScopLib::domainToMatrix_constraint(isl_constraint *c, void *user) {
scoplib_matrix_p m = (scoplib_matrix_p) user;
int nb_params = isl_constraint_dim(c, isl_dim_param);
int nb_vars = isl_constraint_dim(c, isl_dim_set);
int nb_div = isl_constraint_dim(c, isl_dim_div);
assert(!nb_div && "Existentially quantified variables not yet supported");
scoplib_vector_p vec = scoplib_vector_malloc(nb_params + nb_vars + 2);
// Assign type
if (isl_constraint_is_equality(c))
scoplib_vector_tag_equality(vec);
else
scoplib_vector_tag_inequality(vec);
isl_int v;
isl_int_init(v);
// Assign variables
for (int i = 0; i < nb_vars; ++i) {
isl_constraint_get_coefficient(c, isl_dim_set, i, &v);
isl_int_set(vec->p[i + 1], v);
}
// Assign parameters
for (int i = 0; i < nb_params; ++i) {
isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
isl_int_set(vec->p[nb_vars + i + 1], v);
}
// Assign constant
isl_constraint_get_constant(c, &v);
isl_int_set(vec->p[nb_params + nb_vars + 1], v);
scoplib_matrix_insert_vector(m, vec, m->NbRows);
return 0;
}
/// Add an isl basic set to a ScopLib matrix_list
///
/// @param bset The basic set to add
/// @param user The matrix list we should add the basic set to
///
/// XXX: At the moment this function expects just a matrix, as support
/// for matrix lists is currently not available in ScopLib. So union of
/// polyhedron are not yet supported
int ScopLib::domainToMatrix_basic_set(isl_basic_set *bset, void *user) {
scoplib_matrix_p m = (scoplib_matrix_p) user;
assert(!m->NbRows && "Union of polyhedron not yet supported");
isl_basic_set_foreach_constraint(bset, &domainToMatrix_constraint, user);
return 0;
}
/// Translate a isl_set to a ScopLib matrix.
///
/// @param PS The set to be translated
/// @return A ScopLib Matrix
scoplib_matrix_p ScopLib::domainToMatrix(isl_set *PS) {
// Create a canonical copy of this set.
isl_set *set = isl_set_copy(PS);
set = isl_set_compute_divs (set);
set = isl_set_align_divs (set);
// Initialize the matrix.
unsigned NbRows, NbColumns;
NbRows = 0;
NbColumns = isl_set_n_dim(PS) + isl_set_n_param(PS) + 2;
scoplib_matrix_p matrix = scoplib_matrix_malloc(NbRows, NbColumns);
// Copy the content into the matrix.
isl_set_foreach_basic_set(set, &domainToMatrix_basic_set, matrix);
isl_set_free(set);
return matrix;
}
/// Add an isl constraint to an ScopLib matrix.
///
/// @param user The matrix
/// @param c The constraint
int ScopLib::scatteringToMatrix_constraint(isl_constraint *c, void *user) {
scoplib_matrix_p m = (scoplib_matrix_p) user;
int nb_params = isl_constraint_dim(c, isl_dim_param);
int nb_in = isl_constraint_dim(c, isl_dim_in);
int nb_div = isl_constraint_dim(c, isl_dim_div);
assert(!nb_div && "Existentially quantified variables not yet supported");
scoplib_vector_p vec =
scoplib_vector_malloc(nb_params + nb_in + 2);
// Assign type
if (isl_constraint_is_equality(c))
scoplib_vector_tag_equality(vec);
else
scoplib_vector_tag_inequality(vec);
isl_int v;
isl_int_init(v);
// Assign variables
for (int i = 0; i < nb_in; ++i) {
isl_constraint_get_coefficient(c, isl_dim_in, i, &v);
isl_int_set(vec->p[i + 1], v);
}
// Assign parameters
for (int i = 0; i < nb_params; ++i) {
isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
isl_int_set(vec->p[nb_in + i + 1], v);
}
// Assign constant
isl_constraint_get_constant(c, &v);
isl_int_set(vec->p[nb_in + nb_params + 1], v);
scoplib_vector_p null =
scoplib_vector_malloc(nb_params + nb_in + 2);
vec = scoplib_vector_sub(null, vec);
scoplib_matrix_insert_vector(m, vec, 0);
return 0;
}
/// Add an isl basic map to a ScopLib matrix_list
///
/// @param bmap The basic map to add
/// @param user The matrix list we should add the basic map to
///
/// XXX: At the moment this function expects just a matrix, as support
/// for matrix lists is currently not available in ScopLib. So union of
/// polyhedron are not yet supported
int ScopLib::scatteringToMatrix_basic_map(isl_basic_map *bmap, void *user) {
scoplib_matrix_p m = (scoplib_matrix_p) user;
assert(!m->NbRows && "Union of polyhedron not yet supported");
isl_basic_map_foreach_constraint(bmap, &scatteringToMatrix_constraint, user);
return 0;
}
/// Translate a isl_map to a ScopLib matrix.
///
/// @param map The map to be translated
/// @return A ScopLib Matrix
scoplib_matrix_p ScopLib::scatteringToMatrix(isl_map *pmap) {
// Create a canonical copy of this set.
isl_map *map = isl_map_copy(pmap);
map = isl_map_compute_divs (map);
map = isl_map_align_divs (map);
// Initialize the matrix.
unsigned NbRows, NbColumns;
NbRows = 0;
NbColumns = isl_map_n_in(pmap) + isl_map_n_param(pmap) + 2;
scoplib_matrix_p matrix = scoplib_matrix_malloc(NbRows, NbColumns);
// Copy the content into the matrix.
isl_map_foreach_basic_map(map, &scatteringToMatrix_basic_map, matrix);
// Only keep the relevant rows.
scoplib_matrix_p reduced = scoplib_matrix_ncopy(matrix,
isl_map_n_in(pmap) * 2 + 1);
scoplib_matrix_free (matrix);
isl_map_free(map);
return reduced;
}
/// Add an isl constraint to an ScopLib matrix.
///
/// @param user The matrix
/// @param c The constraint
int ScopLib::accessToMatrix_constraint(isl_constraint *c, void *user) {
scoplib_matrix_p m = (scoplib_matrix_p) user;
int nb_params = isl_constraint_dim(c, isl_dim_param);
int nb_in = isl_constraint_dim(c, isl_dim_in);
int nb_div = isl_constraint_dim(c, isl_dim_div);
assert(!nb_div && "Existentially quantified variables not yet supported");
scoplib_vector_p vec =
scoplib_vector_malloc(nb_params + nb_in + 2);
isl_int v;
isl_int_init(v);
// The access dimension has to be one.
isl_constraint_get_coefficient(c, isl_dim_out, 0, &v);
assert(isl_int_is_one(v));
bool inverse = true ;
// Assign variables
for (int i = 0; i < nb_in; ++i) {
isl_constraint_get_coefficient(c, isl_dim_in, i, &v);
if (inverse) isl_int_neg(v,v);
isl_int_set(vec->p[i + 1], v);
}
// Assign parameters
for (int i = 0; i < nb_params; ++i) {
isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
if (inverse) isl_int_neg(v,v);
isl_int_set(vec->p[nb_in + i + 1], v);
}
// Assign constant
isl_constraint_get_constant(c, &v);
if (inverse) isl_int_neg(v,v);
isl_int_set(vec->p[nb_in + nb_params + 1], v);
scoplib_matrix_insert_vector(m, vec, m->NbRows);
return 0;
}
/// Add an isl basic map to a ScopLib matrix_list
///
/// @param bmap The basic map to add
/// @param user The matrix list we should add the basic map to
///
/// XXX: At the moment this function expects just a matrix, as support
/// for matrix lists is currently not available in ScopLib. So union of
/// polyhedron are not yet supported
int ScopLib::accessToMatrix_basic_map(isl_basic_map *bmap, void *user) {
isl_basic_map_foreach_constraint(bmap, &accessToMatrix_constraint, user);
return 0;
}
/// Create the memory access matrix for scoplib
///
/// @param S The polly statement the access matrix is created for.
/// @param isRead Are we looking for read or write accesses?
/// @param ArrayMap A map translating from the memory references to the scoplib
/// indeces
///
/// @return The memory access matrix, as it is required by scoplib.
scoplib_matrix_p ScopLib::createAccessMatrix(ScopStmt *S, bool isRead) {
unsigned NbColumns = S->getNumIterators() + S->getNumParams() + 2;
scoplib_matrix_p m = scoplib_matrix_malloc(0, NbColumns);
for (ScopStmt::memacc_iterator MI = S->memacc_begin(), ME = S->memacc_end();
MI != ME; ++MI)
if ((*MI)->isRead() == isRead) {
// Extract the access function.
isl_map_foreach_basic_map((*MI)->getAccessFunction(),
&accessToMatrix_basic_map, m);
// Set the index of the memory access base element.
std::map<const Value*, int>::iterator BA =
ArrayMap.find((*MI)->getBaseAddr());
isl_int_set_si(m->p[m->NbRows - 1][0], (*BA).second + 1);
}
return m;
}
ScopLib::~ScopLib() {
if (!scoplib)
return;
// Free array names.
for (int i = 0; i < scoplib->nb_arrays; ++i)
free(scoplib->arrays[i]);
free(scoplib->arrays);
scoplib->arrays = NULL;
scoplib->nb_arrays = 0;
// Free parameters
for (int i = 0; i < scoplib->nb_parameters; ++i)
free(scoplib->parameters[i]);
free(scoplib->parameters);
scoplib->parameters = NULL;
scoplib->nb_parameters = 0;
scoplib_statement_p stmt = scoplib->statement;
// Free Statements
while (stmt) {
scoplib_statement_p TempStmt = stmt->next;
stmt->next = NULL;
freeStatement(stmt);
stmt = TempStmt;
}
scoplib->statement = NULL;
scoplib_scop_free(scoplib);
}
/// @brief Create an isl constraint from a row of OpenScop integers.
///
/// @param row An array of isl/OpenScop integers.
/// @param dim An isl dim object, describing how to spilt the dimensions.
///
/// @return An isl constraint representing this integer array.
isl_constraint *constraintFromMatrixRow(isl_int *row, isl_dim *dim) {
isl_constraint *c;
unsigned NbIn = isl_dim_size(dim, isl_dim_in);
unsigned NbParam = isl_dim_size(dim, isl_dim_param);
if (isl_int_is_zero(row[0]))
c = isl_equality_alloc(isl_dim_copy(dim));
else
c = isl_inequality_alloc(isl_dim_copy(dim));
unsigned current_column = 1;
for (unsigned j = 0; j < NbIn; ++j)
isl_constraint_set_coefficient(c, isl_dim_in, j, row[current_column++]);
for (unsigned j = 0; j < NbParam; ++j)
isl_constraint_set_coefficient(c, isl_dim_param, j, row[current_column++]);
isl_constraint_set_constant(c, row[current_column]);
return c;
}
/// @brief Create an isl map from a OpenScop matrix.
///
/// @param m The OpenScop matrix to translate.
/// @param dim The dimensions that are contained in the OpenScop matrix.
///
/// @return An isl map representing m.
isl_map *mapFromMatrix(scoplib_matrix_p m, isl_dim *dim,
unsigned scatteringDims) {
isl_basic_map *bmap = isl_basic_map_universe(isl_dim_copy(dim));
for (unsigned i = 0; i < m->NbRows; ++i) {
isl_constraint *c;
c = constraintFromMatrixRow(m->p[i], dim);
mpz_t minusOne;
mpz_init(minusOne);
mpz_set_si(minusOne, -1);
isl_constraint_set_coefficient(c, isl_dim_out, i, minusOne);
bmap = isl_basic_map_add_constraint(bmap, c);
}
for (unsigned i = m->NbRows; i < scatteringDims; i++) {
isl_constraint *c;
c = isl_equality_alloc(isl_dim_copy(dim));
mpz_t One;
mpz_init(One);
mpz_set_si(One, 1);
isl_constraint_set_coefficient(c, isl_dim_out, i, One);
bmap = isl_basic_map_add_constraint(bmap, c);
}
return isl_map_from_basic_map(bmap);
}
/// @brief Create an isl constraint from a row of OpenScop integers.
///
/// @param row An array of isl/OpenScop integers.
/// @param dim An isl dim object, describing how to spilt the dimensions.
///
/// @return An isl constraint representing this integer array.
isl_constraint *constraintFromMatrixRowFull(isl_int *row, isl_dim *dim) {
isl_constraint *c;
unsigned NbOut = isl_dim_size(dim, isl_dim_out);
unsigned NbIn = isl_dim_size(dim, isl_dim_in);
unsigned NbParam = isl_dim_size(dim, isl_dim_param);
if (isl_int_is_zero(row[0]))
c = isl_equality_alloc(isl_dim_copy(dim));
else
c = isl_inequality_alloc(isl_dim_copy(dim));
unsigned current_column = 1;
for (unsigned j = 0; j < NbOut; ++j)
isl_constraint_set_coefficient(c, isl_dim_out, j, row[current_column++]);
for (unsigned j = 0; j < NbIn; ++j)
isl_constraint_set_coefficient(c, isl_dim_in, j, row[current_column++]);
for (unsigned j = 0; j < NbParam; ++j)
isl_constraint_set_coefficient(c, isl_dim_param, j, row[current_column++]);
isl_constraint_set_constant(c, row[current_column]);
return c;
}
/// @brief Create an isl map from a OpenScop matrix.
///
/// @param m The OpenScop matrix to translate.
/// @param dim The dimensions that are contained in the OpenScop matrix.
///
/// @return An isl map representing m.
isl_map *mapFromMatrix(scoplib_matrix_p m, isl_dim *dim) {
isl_basic_map *bmap = isl_basic_map_universe(isl_dim_copy(dim));
for (unsigned i = 0; i < m->NbRows; ++i) {
isl_constraint *c;
c = constraintFromMatrixRowFull(m->p[i], dim);
bmap = isl_basic_map_add_constraint(bmap, c);
}
return isl_map_from_basic_map(bmap);
}
/// @brief Create a new scattering for PollyStmt.
///
/// @param m The matrix describing the new scattering.
/// @param PollyStmt The statement to create the scattering for.
///
/// @return An isl_map describing the scattering.
isl_map *scatteringForStmt(scoplib_matrix_p m, ScopStmt *PollyStmt,
int scatteringDims) {
unsigned NbParam = PollyStmt->getNumParams();
unsigned NbIterators = PollyStmt->getNumIterators();
unsigned NbScattering;
if (scatteringDims == -1)
NbScattering = m->NbColumns - 2 - NbParam - NbIterators;
else
NbScattering = scatteringDims;
isl_ctx *ctx = PollyStmt->getParent()->getCtx();
isl_dim *dim = isl_dim_alloc(ctx, NbParam, NbIterators, NbScattering);
dim = isl_dim_set_tuple_name(dim, isl_dim_out, "scattering");
dim = isl_dim_set_tuple_name(dim, isl_dim_in, PollyStmt->getBaseName());
isl_map *map;
if (scatteringDims == -1)
map = mapFromMatrix(m, dim);
else
map = mapFromMatrix(m, dim, scatteringDims);
isl_dim_free(dim);
return map;
}
unsigned maxScattering(scoplib_statement_p stmt) {
unsigned max = 0;
while (stmt) {
max = std::max(max, stmt->schedule->NbRows);
stmt = stmt->next;
}
return max;
}
typedef Dependences::StatementToIslMapTy StatementToIslMapTy;
/// @brief Read the new scattering from the scoplib description.
///
/// @S The Scop to update
/// @OScop The ScopLib data structure describing the new scattering.
/// @return A map that contains for each Statement the new scattering.
StatementToIslMapTy *readScattering(Scop *S, scoplib_scop_p OScop) {
StatementToIslMapTy &NewScattering = *(new StatementToIslMapTy());
scoplib_statement_p stmt = OScop->statement;
// Check if we have dimensions for each scattering or if each row
// represents a scattering dimension.
int numScatteringDims = -1;
ScopStmt *pollyStmt = *S->begin();
if (stmt->schedule->NbColumns
== 2 + pollyStmt->getNumParams() + pollyStmt->getNumIterators()) {
numScatteringDims = maxScattering(stmt);
}
for (Scop::iterator SI = S->begin(), SE = S->end(); SI != SE; ++SI) {
if ((*SI)->isFinalRead())
continue;
if (!stmt) {
errs() << "Not enough statements available in OpenScop file\n";
delete &NewScattering;
return NULL;
}
NewScattering[*SI] = scatteringForStmt(stmt->schedule, *SI,
numScatteringDims);
stmt = stmt->next;
}
if (stmt) {
errs() << "Too many statements in OpenScop file\n";
delete &NewScattering;
return NULL;
}
return &NewScattering;
}
/// @brief Update the scattering in a Scop using the scoplib description of
/// the scattering.
bool ScopLib::updateScattering() {
if (!scoplib)
return false;
StatementToIslMapTy *NewScattering = readScattering(PollyScop, scoplib);
if (!NewScattering)
return false;
if (!D->isValidScattering(NewScattering)) {
errs() << "OpenScop file contains a scattering that changes the "
<< "dependences. Use -disable-polly-legality to continue anyways\n";
return false;
}
for (Scop::iterator SI = PollyScop->begin(), SE = PollyScop->end(); SI != SE;
++SI) {
ScopStmt *Stmt = *SI;
if (NewScattering->find(Stmt) != NewScattering->end())
Stmt->setScattering((*NewScattering)[Stmt]);
}
return true;
}
}
#endif

View File

@ -0,0 +1,99 @@
//===-- ScopLibExporter.cpp - Export Scops with scoplib ----------------===//
//
// 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 to text file.
//
//===----------------------------------------------------------------------===//
#include "polly/LinkAllPasses.h"
#ifdef SCOPLIB_FOUND
#include "polly/ScopInfo.h"
#include "polly/ScopPass.h"
#include "polly/ScopLib.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Assembly/Writer.h"
#include "stdio.h"
#include "isl/set.h"
#include "isl/constraint.h"
using namespace llvm;
using namespace polly;
namespace {
static cl::opt<std::string>
ExportDir("polly-export-scoplib-dir",
cl::desc("The directory to export the .scoplib files to."),
cl::Hidden, cl::value_desc("Directory path"), cl::ValueRequired,
cl::init("."));
class ScopLibExporter : public ScopPass {
Scop *S;
std::string getFileName(Scop *S) const;
public:
static char ID;
explicit ScopLibExporter() : ScopPass(ID) {}
virtual bool runOnScop(Scop &scop);
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char ScopLibExporter::ID = 0;
std::string ScopLibExporter::getFileName(Scop *S) const {
std::string FunctionName =
S->getRegion().getEntry()->getParent()->getNameStr();
std::string FileName = FunctionName + "___" + S->getNameStr() + ".scoplib";
return FileName;
}
bool ScopLibExporter::runOnScop(Scop &scop) {
S = &scop;
Region *R = &S->getRegion();
std::string FileName = ExportDir + "/" + getFileName(S);
FILE *F = fopen(FileName.c_str(), "w");
if (!F) {
errs() << "Cannot open file: " << FileName << "\n";
errs() << "Skipping export.\n";
return false;
}
ScopLib scoplib(S);
scoplib.print(F);
fclose(F);
std::string FunctionName = R->getEntry()->getParent()->getNameStr();
errs() << "Writing Scop '" << R->getNameStr() << "' in function '"
<< FunctionName << "' to '" << FileName << "'.\n";
return false;
}
void ScopLibExporter::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
}
static RegisterPass<ScopLibExporter> A("polly-export-scoplib",
"Polly - Export Scops with ScopLib library"
" (Writes a .scoplib file for each Scop)"
);
Pass *polly::createScopLibExporterPass() {
return new ScopLibExporter();
}
#endif

View File

@ -0,0 +1,120 @@
//===-- ScopLibImporter.cpp - Import Scops with scoplib. -----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Import modified .scop files into Polly. This allows to change the schedule of
// statements.
//
//===----------------------------------------------------------------------===//
#include "polly/LinkAllPasses.h"
#ifdef SCOPLIB_FOUND
#include "polly/ScopInfo.h"
#include "polly/ScopLib.h"
#include "polly/Dependences.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Assembly/Writer.h"
#define SCOPLIB_INT_T_IS_MP
#include "scoplib/scop.h"
#include "isl/set.h"
#include "isl/constraint.h"
using namespace llvm;
using namespace polly;
namespace {
static cl::opt<std::string>
ImportDir("polly-import-scoplib-dir",
cl::desc("The directory to import the .scoplib files from."),
cl::Hidden, cl::value_desc("Directory path"), cl::ValueRequired,
cl::init("."));
static cl::opt<std::string>
ImportPostfix("polly-import-scoplib-postfix",
cl::desc("Postfix to append to the import .scoplib files."),
cl::Hidden, cl::value_desc("File postfix"), cl::ValueRequired,
cl::init(""));
struct ScopLibImporter : public RegionPass {
static char ID;
Scop *S;
Dependences *D;
explicit ScopLibImporter() : RegionPass(ID) {}
bool updateScattering(Scop *S, scoplib_scop_p OScop);
std::string getFileName(Scop *S) const;
virtual bool runOnRegion(Region *R, RGPassManager &RGM);
virtual void print(raw_ostream &OS, const Module *) const;
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char ScopLibImporter::ID = 0;
namespace {
std::string ScopLibImporter::getFileName(Scop *S) const {
std::string FunctionName =
S->getRegion().getEntry()->getParent()->getNameStr();
std::string FileName = FunctionName + "___" + S->getNameStr() + ".scoplib";
return FileName;
}
void ScopLibImporter::print(raw_ostream &OS, const Module *) const {}
bool ScopLibImporter::runOnRegion(Region *R, RGPassManager &RGM) {
S = getAnalysis<ScopInfo>().getScop();
D = &getAnalysis<Dependences>();
if (!S)
return false;
std::string FileName = ImportDir + "/" + getFileName(S) + ImportPostfix;
FILE *F = fopen(FileName.c_str(), "r");
if (!F) {
errs() << "Cannot open file: " << FileName << "\n";
errs() << "Skipping import.\n";
return false;
}
std::string FunctionName = R->getEntry()->getParent()->getNameStr();
errs() << "Reading Scop '" << R->getNameStr() << "' in function '"
<< FunctionName << "' from '" << FileName << "'.\n";
ScopLib scoplib(S, F, D);
bool UpdateSuccessfull = scoplib.updateScattering();
fclose(F);
if (!UpdateSuccessfull) {
errs() << "Update failed" << "\n";
}
return false;
}
void ScopLibImporter::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<ScopInfo>();
AU.addRequired<Dependences>();
}
}
static RegisterPass<ScopLibImporter> A("polly-import-scoplib",
"Polly - Import Scops with ScopLib library"
" (Reads a .scoplib file for each Scop)"
);
Pass *polly::createScopLibImporterPass() {
return new ScopLibImporter();
}
#endif

View File

@ -0,0 +1,550 @@
//===------ 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/ScopDetection.h"
#include "polly/Support/ScopHelper.h"
#include "polly/Cloog.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/RegionPass.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/Writer.h"
#define DEBUG_TYPE "polly-independent"
#include "llvm/Support/Debug.h"
#include <vector>
using namespace polly;
using namespace llvm;
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 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 Inst->isSafeToSpeculativelyExecute();
}
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()));
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);
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 operand 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;
}
// No need to move induction variable.
if (isIndVar(Operand, LI)) {
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 contained in the same BB with
// the root instruction.
// FIXME: Remember this in visited Map.
if (Operand->getParent() == CurBB) {
DEBUG(dbgs() << "No need to move.\n");
// Try to move its operand.
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);
// Skip all its children as we already processed them.
continue;
} 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));
// Process its operands.
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 (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II)
if (!isSafeToMove(II) && !isIndVar(II, LI))
WorkList.push_back(II);
ReplacedMapType ReplacedMap;
Instruction *InsertPos = BB->getFirstNonPHIOrDbg();
for (std::vector<Instruction*>::iterator I = WorkList.begin(),
E = WorkList.end(); I != E; ++I)
moveOperandTree(*I, 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 (Region::const_block_iterator SI = R->block_begin(), SE = R->block_end();
SI != SE; ++SI)
Changed |= createIndependentBlocks((*SI)->getNodeAs<BasicBlock>(), R);
return Changed;
}
bool IndependentBlocks::eliminateDeadCode(const Region *R) {
std::vector<Instruction*> WorkList;
// Find all trivially dead instructions.
for (Region::const_block_iterator SI = R->block_begin(), SE = R->block_end();
SI != SE; ++SI) {
BasicBlock *BB = (*SI)->getNodeAs<BasicBlock>();
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
if (isInstructionTriviallyDead(I))
WorkList.push_back(I);
}
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 (isIndVar(OpInst, LI)) 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 *Reg = toUpdate.back();
toUpdate.pop_back();
for (Region::iterator I = Reg->begin(), E = Reg->end(); I != E; ++I) {
Region *SubR = *I;
if (SubR->getExit() == ExitBB)
toUpdate.push_back(SubR);
}
Reg->replaceExit(NewExit);
}
RI->setRegionFor(NewExit, R->getParent());
return true;
}
bool IndependentBlocks::translateScalarToArray(const Region *R) {
bool Changed = false;
for (Region::const_block_iterator SI = R->block_begin(), SE = R->block_end();
SI != SE; ++SI)
Changed |= translateScalarToArray((*SI)->getNodeAs<BasicBlock>(), R);
return Changed;
}
bool IndependentBlocks::translateScalarToArray(Instruction *Inst,
const Region *R) {
if (isIndVar(Inst, LI))
return false;
SmallVector<Instruction*, 4> LoadInside, LoadOutside;
for (Instruction::use_iterator UI = Inst->use_begin(),
UE = Inst->use_end(); UI != UE; ++UI)
// Inst is referenced outside or referenced as an escaped operand.
if (Instruction *U = dyn_cast<Instruction>(*UI)) {
BasicBlock *UParent = U->getParent();
if (isEscapeUse(U, R))
LoadOutside.push_back(U);
if (isIndVar(U, LI))
continue;
if (R->contains(UParent) && isEscapeOperand(Inst, UParent, R))
LoadInside.push_back(U);
}
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.
BasicBlock::iterator StorePos = Inst;
(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();
assert(!isa<PHINode>(U) && "Can not handle PHI node outside!");
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 outside!");
SE->forgetValue(U);
LoadInst *L = new LoadInst(Slot, Inst->getName()+".loadarray",
false, U);
U->replaceUsesOfWith(Inst, L);
}
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 (BasicBlock::iterator II = BB->begin(), IE = --BB->end();
II != IE; ++II) {
Instruction *Inst = &*II;
if (isIndVar(Inst, LI))
continue;
// A value inside the Scop is referenced outside.
for (Instruction::use_iterator UI = Inst->use_begin(),
UE = Inst->use_end(); UI != UE; ++UI) {
if (isEscapeUse(*UI, R)) {
DEBUG(dbgs() << "Instruction not independent:\n");
DEBUG(dbgs() << "Instruction used outside the Scop!\n");
DEBUG(Inst->print(dbgs()));
DEBUG(dbgs() << "\n");
return false;
}
}
for (Instruction::op_iterator OI = Inst->op_begin(),
OE = Inst->op_end(); OI != OE; ++OI) {
if (isEscapeOperand(*OI, BB, R)) {
DEBUG(dbgs() << "Instruction in function '";
WriteAsOperand(dbgs(), BB->getParent(), false);
dbgs() << "' not independent:\n");
DEBUG(dbgs() << "Uses invalid operator\n");
DEBUG(Inst->print(dbgs()));
DEBUG(dbgs() << "\n");
DEBUG(dbgs() << "Invalid operator is: ";
WriteAsOperand(dbgs(), *OI, false);
dbgs() << "\n");
return false;
}
}
}
return true;
}
bool IndependentBlocks::areAllBlocksIndependent(const Region *R) const {
for (Region::const_block_iterator SI = R->block_begin(), SE = R->block_end();
SI != SE; ++SI)
if (!isIndependentBlock(R, (*SI)->getNodeAs<BasicBlock>()))
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<DominatorTree>();
AU.addPreserved<DominanceFrontier>();
AU.addPreserved<PostDominatorTree>();
AU.addRequired<RegionInfo>();
AU.addPreserved<RegionInfo>();
AU.addRequired<LoopInfo>();
AU.addPreserved<LoopInfo>();
AU.addRequired<ScalarEvolution>();
AU.addPreserved<ScalarEvolution>();
AU.addRequired<ScopDetection>();
AU.addPreserved<ScopDetection>();
AU.addPreserved<CloogInfo>();
}
bool IndependentBlocks::runOnFunction(llvm::Function &F) {
bool Changed = false;
RI = &getAnalysis<RegionInfo>();
LI = &getAnalysis<LoopInfo>();
SD = &getAnalysis<ScopDetection>();
SE = &getAnalysis<ScalarEvolution>();
AllocaBlock = &F.getEntryBlock();
DEBUG(dbgs() << "Run IndepBlock on " << F.getName() << '\n');
for (ScopDetection::iterator I = SD->begin(), E = SD->end(); I != E; ++I) {
const Region *R = *I;
Changed |= createIndependentBlocks(R);
Changed |= eliminateDeadCode(R);
// This may change the RegionTree.
Changed |= splitExitBlock(const_cast<Region*>(R));
}
DEBUG(dbgs() << "Before Scalar to Array------->\n");
DEBUG(F.dump());
for (ScopDetection::iterator I = SD->begin(), E = SD->end(); I != E; ++I)
Changed |= translateScalarToArray(*I);
DEBUG(dbgs() << "After Independent Blocks------------->\n");
DEBUG(F.dump());
verifyAnalysis();
return Changed;
}
void IndependentBlocks::verifyAnalysis() const {
for (ScopDetection::const_iterator I = SD->begin(), E = SD->end();I != E;++I)
verifyScop(*I);
}
void IndependentBlocks::verifyScop(const Region *R) const {
assert (areAllBlocksIndependent(R) && "Cannot generate independent blocks");
}
char IndependentBlocks::ID = 0;
static RegisterPass<IndependentBlocks>
Z("polly-independent", "Polly - Create independent blocks");
char &polly::IndependentBlocksID = IndependentBlocks::ID;
Pass* polly::createIndependentBlocksPass() {
return new IndependentBlocks();
}

83
polly/lib/Interchange.cpp Normal file
View File

@ -0,0 +1,83 @@
//===- Interchange.cpp - Interchange interface ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "polly/Cloog.h"
#include "polly/LinkAllPasses.h"
#include "polly/ScopInfo.h"
#include "polly/Dependences.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/CommandLine.h"
#include <isl/map.h>
#define DEBUG_TYPE "polly-interchange"
#include "llvm/Support/Debug.h"
using namespace llvm;
using namespace polly;
namespace {
class Interchange : public ScopPass {
public:
static char ID;
explicit Interchange() : ScopPass(ID) {}
virtual bool runOnScop(Scop &S);
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char Interchange::ID = 0;
bool Interchange::runOnScop(Scop &S) {
if (std::distance(S.begin(), S.end()) != 2) // One statement besides the final statement
return false;
for (Scop::iterator SI = S.begin(), SE = S.end(); SI != SE; ++SI) {
ScopStmt *Stmt = *SI;
if (!Stmt->isReduction())
continue;
isl_map *Scattering = isl_map_copy(Stmt->getScattering());
const std::string MapString = "{scattering[i0, i1, i2, i3, i4] -> scattering[i0, i3, i2, i1, i4]}";
isl_map *Map = isl_map_read_from_str(Stmt->getIslContext(), MapString.c_str(), -1);
isl_map_add_dims(Map, isl_dim_param, Stmt->getNumParams());
Scattering = isl_map_apply_range(Scattering, Map);
Stmt->setScattering(Scattering);
DEBUG(
isl_printer *p = isl_printer_to_str(S.getCtx());
isl_printer_print_map(p, Scattering);
dbgs() << isl_printer_get_str(p) << '\n';
isl_printer_flush(p);
isl_printer_free(p);
);
}
return false;
}
void Interchange::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
AU.addRequired<Dependences>();
}
static RegisterPass<Interchange> A("polly-interchange",
"Polly - Perform loop interchange");
Pass* polly::createInterchangePass() {
return new Interchange();
}

6
polly/lib/JSON/CMakeLists.txt Executable file
View File

@ -0,0 +1,6 @@
add_polly_library(PollyJSON
json_reader.cpp
json_value.cpp
json_writer.cpp
)

View File

@ -0,0 +1 @@
The json-cpp library and this documentation are in Public Domain.

16
polly/lib/JSON/Makefile Executable file
View File

@ -0,0 +1,16 @@
##===- polly/lib/Support/Makefile ----------------*- Makefile -*-===##
#
# Indicate where we are relative to the top of the source tree.
#
LEVEL=../..
LIBRARYNAME=pollyjson
BUILD_ARCHIVE = 1
CPP.Flags += $(POLLY_INC)
#
# Include Makefile.common so we know what to do.
#
include $(LEVEL)/Makefile.common

View File

@ -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

View File

@ -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 1
# 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,196 @@
#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 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 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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,174 @@
#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 usefull to support feature such as RPC where bandwith 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.
*
* \param indentation Each level will be indented by this amount extra.
* \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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,885 @@
#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 (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
return sin;
}
} // namespace Json

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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") == NULL && !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+NULL
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_(NULL)
, 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_ = NULL; // 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

View File

@ -0,0 +1,8 @@
Import( 'env buildLibrary' )
buildLibrary( env, Split( """
json_reader.cpp
json_value.cpp
json_writer.cpp
""" ),
'json' )

78
polly/lib/Makefile Executable file
View File

@ -0,0 +1,78 @@
##===- polly/lib/Makefile -----------------------*- Makefile -*-===##
#
# Indicate where we are relative to the top of the source tree.
#
LEVEL :=..
DIRS = Support
USEDLIBS = pollysupport.a
LIBRARYNAME=LLVMPolly
LOADABLE_MODULE = 1
include $(LEVEL)/Makefile.config
CPP.Flags += $(POLLY_INC)
DIRS += Exchange
USEDLIBS += pollyexchange.a
DIRS += Analysis
USEDLIBS += pollyanalysis.a
DIRS += JSON
USEDLIBS += pollyjson.a
# TODO: Export symbols for RTTI or EH?
#
# Include Makefile.common so we know what to do.
#
include $(LEVEL)/Makefile.common
LIBS += $(POLLY_LD) $(POLLY_LIB)
$(LibDir)/libpollyanalysis.a : $(LibDir)/.dir $(PROJ_OBJ_DIR)/Analysis/$(BuildMode)/.dir \
$(PROJ_SRC_DIR)/Analysis/*
$(Verb) if [ -d $(PROJ_SRC_DIR)/Analysis ]; then\
if ([ ! -f Analysis/Makefile ] || \
command test Analysis/Makefile -ot $(PROJ_SRC_DIR)/Analysis/Makefile ); then \
$(MKDIR) Analysis; \
$(CP) $(PROJ_SRC_DIR)/Analysis/Makefile Analysis/Makefile; \
fi; \
($(MAKE) -C Analysis $@ ) || exit 1; \
fi
$(LibDir)/libpollyexchange.a : $(LibDir)/.dir $(PROJ_OBJ_DIR)/Exchange/$(BuildMode)/.dir \
$(PROJ_SRC_DIR)/Exchange/*
$(Verb) if [ -d $(PROJ_SRC_DIR)/Exchange ]; then\
if ([ ! -f Exchange/Makefile ] || \
command test Exchange/Makefile -ot $(PROJ_SRC_DIR)/Exchange/Makefile ); then \
$(MKDIR) Exchange; \
$(CP) $(PROJ_SRC_DIR)/Exchange/Makefile Exchange/Makefile; \
fi; \
($(MAKE) -C Exchange $@ ) || exit 1; \
fi
$(LibDir)/libpollysupport.a : $(LibDir)/.dir $(PROJ_OBJ_DIR)/Support/$(BuildMode)/.dir \
$(PROJ_SRC_DIR)/Support/*
$(Verb) if [ -d $(PROJ_SRC_DIR)/Support ]; then\
if ([ ! -f Support/Makefile ] || \
command test Support/Makefile -ot $(PROJ_SRC_DIR)/Support/Makefile ); then \
$(MKDIR) Support; \
$(CP) $(PROJ_SRC_DIR)/Support/Makefile Support/Makefile; \
fi; \
($(MAKE) -C Support $@ ) || exit 1; \
fi
$(LibDir)/libpollyjson.a : $(LibDir)/.dir $(PROJ_OBJ_DIR)/JSON/$(BuildMode)/.dir \
$(PROJ_SRC_DIR)/JSON/*
$(Verb) if [ -d $(PROJ_SRC_DIR)/JSON ]; then\
if ([ ! -f JSON/Makefile ] || \
command test JSON/Makefile -ot $(PROJ_SRC_DIR)/JSON/Makefile ); then \
$(MKDIR) JSON; \
$(CP) $(PROJ_SRC_DIR)/JSON/Makefile JSON/Makefile; \
fi; \
($(MAKE) -C JSON $@ ) || exit 1; \
fi

92
polly/lib/MayAliasSet.cpp Executable file
View File

@ -0,0 +1,92 @@
//===---------- MayAliasSet.cpp - May-Alais Set for base pointers --------===//
//
// 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 MayAliasSet class
//
//===----------------------------------------------------------------------===//
#include "polly/TempScopInfo.h"
#include "polly/MayAliasSet.h"
#include "llvm/LLVMContext.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AliasSetTracker.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
using namespace polly;
void MayAliasSet::print(raw_ostream &OS) const {
OS << "Must alias {";
for (const_iterator I = mustalias_begin(), E = mustalias_end(); I != E; ++I) {
WriteAsOperand(OS, *I, false);
OS << ", ";
}
OS << "} May alias {";
OS << '}';
}
void MayAliasSet::dump() const {
print(dbgs());
}
void MayAliasSetInfo::buildMayAliasSets(TempScop &Scop, AliasAnalysis &AA) {
AliasSetTracker AST(AA);
Region &MaxR = Scop.getMaxRegion();
// Find out all base pointers that appeared in Scop and build the Alias set.
// Note: We may build the alias sets while we are building access functions
// to obtain better performance.
for (Region::block_iterator I = MaxR.block_begin(), E = MaxR.block_end();
I != E; ++I) {
BasicBlock *BB = I->getNodeAs<BasicBlock>();
if (const AccFuncSetType *AFS = Scop.getAccessFunctions(BB)) {
for (AccFuncSetType::const_iterator AI = AFS->begin(), AE = AFS->end();
AI != AE; ++AI) {
const SCEVAffFunc &AccFunc = AI->first;
Instruction *Inst = AI->second;
Value *BaseAddr = const_cast<Value*>(AccFunc.getBaseAddr());
AST.add(BaseAddr, AliasAnalysis::UnknownSize,
Inst->getMetadata(LLVMContext::MD_tbaa));
}
}
}
// Build the may-alias set with the AliasSetTracker.
for (AliasSetTracker::iterator I = AST.begin(), E = AST.end(); I != E; ++I) {
AliasSet &AS = *I;
// Ignore the dummy alias set.
if (AS.isForwardingAliasSet()) continue;
// The most simple case: All pointers in the set must-alias each others.
if (AS.isMustAlias()) {
MayAliasSet *MayAS = new (MayASAllocator.Allocate()) MayAliasSet();
for (AliasSet::iterator PI = AS.begin(), PE = AS.end(); PI != PE; ++PI) {
Value *Ptr = PI.getPointer();
MayAS->addMustAliasPtr(Ptr);
BasePtrMap.insert(std::make_pair(Ptr, MayAS));
}
continue;
}
assert(0 && "SCoPDetection pass should not allow May-Alias set!");
}
}

291
polly/lib/Pocc.cpp Normal file
View File

@ -0,0 +1,291 @@
//===- Pocc.cpp - Pocc interface ----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Pocc[1] interface.
//
// Pocc, the polyhedral compilation collection is a collection of polyhedral
// tools. It is used as an optimizer in polly
//
// [1] http://www-roc.inria.fr/~pouchet/software/pocc/
//
//===----------------------------------------------------------------------===//
#include "polly/Cloog.h"
#include "polly/LinkAllPasses.h"
#ifdef SCOPLIB_FOUND
#include "polly/ScopInfo.h"
#include "polly/Dependences.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/system_error.h"
#include "llvm/ADT/OwningPtr.h"
#include "polly/ScopLib.h"
#include "isl/dim.h"
#include "isl/map.h"
#include "isl/constraint.h"
using namespace llvm;
using namespace polly;
static cl::opt<bool>
PlutoTile("enable-pluto-tile",
cl::desc("Enable pluto tiling for polly"), cl::Hidden,
cl::value_desc("Pluto tiling enabled if true"),
cl::init(false));
static cl::opt<bool>
PlutoPrevector("enable-pluto-prevector",
cl::desc("Enable pluto prevectorization for polly"), cl::Hidden,
cl::value_desc("Pluto prevectorization enabled if true"),
cl::init(false));
static cl::opt<std::string>
PlutoFuse("pluto-fuse",
cl::desc(""), cl::Hidden,
cl::value_desc("Set fuse mode of Pluto"),
cl::init("maxfuse"));
namespace {
class Pocc : public ScopPass {
sys::Path plutoStderr;
sys::Path plutoStdout;
std::vector<const char*> arguments;
public:
static char ID;
explicit Pocc() : ScopPass(ID) {}
std::string getFileName(Region *R) const;
virtual bool runOnScop(Scop &S);
void printScop(llvm::raw_ostream &OS) const;
void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
char Pocc::ID = 0;
bool Pocc::runOnScop(Scop &S) {
Dependences *D = &getAnalysis<Dependences>();
// Only the final read statement in the SCoP. No need to optimize anything.
// (In case we would try, Pocc complains that there is no statement in the
// SCoP).
if (S.begin() + 1 == S.end())
return false;
// Create the scop file.
sys::Path tempDir = sys::Path::GetTemporaryDirectory();
sys::Path scopFile = tempDir;
scopFile.appendComponent("polly.scop");
scopFile.createFileOnDisk();
FILE *F = fopen(scopFile.c_str(), "w");
arguments.clear();
if (!F) {
errs() << "Cannot open file: " << tempDir.c_str() << "\n";
errs() << "Skipping export.\n";
return false;
}
ScopLib scoplib(&S);
scoplib.print(F);
fclose(F);
// Execute pocc
sys::Program program;
sys::Path pocc = sys::Program::FindProgramByName("pocc");
arguments.push_back("pocc");
arguments.push_back("--read-scop");
arguments.push_back(scopFile.c_str());
arguments.push_back("--pluto-tile-scat");
arguments.push_back("--candl-dep-isl-simp");
arguments.push_back("--cloogify-scheds");
arguments.push_back("--output-scop");
arguments.push_back("--pluto");
arguments.push_back("--pluto-bounds");
arguments.push_back("10");
arguments.push_back("--pluto-fuse");
arguments.push_back(PlutoFuse.c_str());
if (PlutoTile)
arguments.push_back("--pluto-tile");
if (PlutoPrevector)
arguments.push_back("--pluto-prevector");
arguments.push_back(0);
plutoStdout = tempDir;
plutoStdout.appendComponent("pluto.stdout");
plutoStderr = tempDir;
plutoStderr.appendComponent("pluto.stderr");
std::vector<sys::Path*> redirect;
redirect.push_back(0);
redirect.push_back(&plutoStdout);
redirect.push_back(&plutoStderr);
program.ExecuteAndWait(pocc, &arguments[0], 0,
(sys::Path const **) &redirect[0]);
// Read the created scop file
sys::Path newScopFile = tempDir;
newScopFile.appendComponent("polly.pocc.c.scop");
FILE *poccFile = fopen(newScopFile.c_str(), "r");
ScopLib newScoplib(&S, poccFile, D);
if (!newScoplib.updateScattering()) {
errs() << "Failure when calculating the optimization with "
"the following command: ";
for (std::vector<const char*>::const_iterator AI = arguments.begin(),
AE = arguments.end(); AI != AE; ++AI)
if (*AI)
errs() << " " << *AI;
errs() << "\n";
return false;
} else
fclose(poccFile);
if (!PlutoPrevector)
return false;
// Find the innermost dimension that is not a constant dimension. This
// dimension will be vectorized.
unsigned scatterDims = S.getScatterDim();
int lastLoop = scatterDims - 1;
while (lastLoop) {
bool isSingleValued = true;
for (Scop::iterator SI = S.begin(), SE = S.end(); SI != SE; ++SI) {
if ((*SI)->isFinalRead())
continue;
isl_map *scat = isl_map_copy((*SI)->getScattering());
isl_map *projected = isl_map_project_out(scat, isl_dim_out, lastLoop,
scatterDims - lastLoop);
if (!isl_map_is_bijective(projected)) {
isSingleValued = false;
break;
}
}
if (!isSingleValued)
break;
lastLoop--;
}
// Strip mine the innermost loop.
for (Scop::iterator SI = S.begin(), SE = S.end(); SI != SE; ++SI) {
if ((*SI)->isFinalRead())
continue;
isl_map *scat = (*SI)->getScattering();
int scatDims = isl_map_n_out(scat);
isl_dim *dim = isl_dim_alloc(S.getCtx(), S.getNumParams(), scatDims,
scatDims + 1);
isl_basic_map *map = isl_basic_map_universe(isl_dim_copy(dim));
for (int i = 0; i <= lastLoop - 1; i++) {
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_constraint_set_coefficient_si(c, isl_dim_in, i, 1);
isl_constraint_set_coefficient_si(c, isl_dim_out, i, -1);
map = isl_basic_map_add_constraint(map, c);
}
for (int i = lastLoop; i < scatDims; i++) {
isl_constraint *c = isl_equality_alloc(isl_dim_copy(dim));
isl_constraint_set_coefficient_si(c, isl_dim_in, i, 1);
isl_constraint_set_coefficient_si(c, isl_dim_out, i + 1, -1);
map = isl_basic_map_add_constraint(map, c);
}
isl_constraint *c;
int vectorWidth = 4;
c = isl_inequality_alloc(isl_dim_copy(dim));
isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop, -vectorWidth);
isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop + 1, 1);
map = isl_basic_map_add_constraint(map, c);
c = isl_inequality_alloc(isl_dim_copy(dim));
isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop, vectorWidth);
isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop + 1, -1);
isl_constraint_set_constant_si(c, vectorWidth - 1);
map = isl_basic_map_add_constraint(map, c);
isl_map *transform = isl_map_from_basic_map(map);
transform = isl_map_set_tuple_name(transform, isl_dim_out, "scattering");
transform = isl_map_set_tuple_name(transform, isl_dim_in, "scattering");
scat = isl_map_apply_range(scat, isl_map_copy(transform));
(*SI)->setScattering(scat);
}
return false;
}
void Pocc::printScop(raw_ostream &OS) const {
OwningPtr<MemoryBuffer> stdoutBuffer;
OwningPtr<MemoryBuffer> stderrBuffer;
OS << "Command line: ";
for (std::vector<const char*>::const_iterator AI = arguments.begin(),
AE = arguments.end(); AI != AE; ++AI)
if (*AI)
OS << " " << *AI;
OS << "\n";
if (error_code ec = MemoryBuffer::getFile(plutoStdout.c_str(), stdoutBuffer))
OS << "Could not open pocc stdout file: " + ec.message();
else {
OS << "pocc stdout: " << stdoutBuffer->getBufferIdentifier() << "\n";
OS << stdoutBuffer->getBuffer() << "\n";
}
if (error_code ec = MemoryBuffer::getFile(plutoStderr.c_str(), stderrBuffer))
OS << "Could not open pocc stderr file: " + ec.message();
else {
OS << "pocc stderr: " << plutoStderr.c_str() << "\n";
OS << stderrBuffer->getBuffer() << "\n";
}
}
void Pocc::getAnalysisUsage(AnalysisUsage &AU) const {
ScopPass::getAnalysisUsage(AU);
AU.addRequired<Dependences>();
}
static RegisterPass<Pocc> A("polly-optimize",
"Polly - Optimize the scop using pocc");
Pass* polly::createPoccPass() {
return new Pocc();
}
#endif /* SCOPLIB_FOUND */

View File

@ -0,0 +1,219 @@
//===- RegionSimplify.cpp -------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file converts refined regions detected by the RegionInfo analysis
// into simple regions.
//
//===----------------------------------------------------------------------===//
#include "polly/LinkAllPasses.h"
#include "llvm/Instructions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/RegionPass.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#define DEBUG_TYPE "region-simplify"
#include "llvm/Support/Debug.h"
using namespace llvm;
STATISTIC(NumEntries, "The # of created entry edges");
STATISTIC(NumExits, "The # of created exit edges");
namespace {
class RegionSimplify: public RegionPass {
// Remember the modified region.
Region *r;
void createSingleEntryEdge(Region *R);
void createSingleExitEdge(Region *R);
public:
static char ID;
explicit RegionSimplify() : RegionPass(ID), r(0) {}
virtual void print(raw_ostream &O, const Module *M) const;
virtual bool runOnRegion(Region *R, RGPassManager &RGM);
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
};
}
static RegisterPass<RegionSimplify>
X("polly-region-simplify", "Transform refined regions into simple regions");
char RegionSimplify::ID = 0;
namespace polly {
Pass *createRegionSimplifyPass() {
return new RegionSimplify();
}
}
void RegionSimplify::print(raw_ostream &O, const Module *M) const {
if (r == 0) return;
BasicBlock *enteringBlock = r->getEnteringBlock();
BasicBlock *exitingBlock = r->getExitingBlock();
O << "Region: " << r->getNameStr() << " Edges:\t";
if (enteringBlock)
O << "Entering: [" << enteringBlock->getNameStr() << " -> "
<< r->getEntry()->getName() << "], ";
if (exitingBlock) {
O << "Exiting: [" << exitingBlock->getNameStr() << " -> ";
if (r->getExit())
O << r->getExit()->getName();
else
O << "<return>";
O << "]";
}
O << "\n";
}
void RegionSimplify::getAnalysisUsage(AnalysisUsage &AU) const {
// Function SplitBlockPredecessors currently updates/preserves AliasAnalysis,
/// DominatorTree, LoopInfo, and LCCSA but no other analyses.
//AU.addPreserved<AliasAnalysis>(); Break SCEV-AA
AU.addPreserved<DominatorTree> ();
AU.addPreserved<LoopInfo>();
AU.addPreservedID(LCSSAID);
AU.addPreserved<RegionInfo> ();
AU.addRequired<RegionInfo> ();
}
// createSingleEntryEdge - Split the entry basic block of the given
// region after the last PHINode to form a single entry edge.
void RegionSimplify::createSingleEntryEdge(Region *R) {
BasicBlock *oldEntry = R->getEntry();
SmallVector<BasicBlock*, 4> Preds;
for (pred_iterator PI = pred_begin(oldEntry), PE = pred_end(oldEntry);
PI != PE; ++PI)
if (!R->contains(*PI))
Preds.push_back(*PI);
assert(Preds.size() && "This region has already a single entry edge");
BasicBlock *newEntry = SplitBlockPredecessors(oldEntry,
Preds.data(), Preds.size(),
".single_entry", this);
RegionInfo *RI = &getAnalysis<RegionInfo> ();
// We do not update entry node for children of this region.
// This make it easier to extract children regions because they do not share
// the entry node with their parents.
// all parent regions whose entry is oldEntry are updated with newEntry
Region *r = R->getParent();
// Put the new entry to R's parent.
RI->setRegionFor(newEntry,r);
while (r->getEntry() == oldEntry && !r->isTopLevelRegion()) {
r->replaceEntry(newEntry);
r = r->getParent();
}
// We do not update exit node for children of this region for the same reason
// of not updating entry node.
// All other regions whose exit is oldEntry are updated with new exit node
r = RI->getTopLevelRegion();
std::vector<Region *> RQ;
RQ.push_back(r);
while (!RQ.empty()){
r = RQ.back();
RQ.pop_back();
for (Region::const_iterator RI = r->begin(), RE = r->end(); RI!=RE; ++RI)
RQ.push_back(*RI);
if (r->getExit() == oldEntry && !R->contains(r))
r->replaceExit(newEntry);
}
}
// createSingleExitEdge - Split the exit basic of the given region
// to form a single exit edge.
void RegionSimplify::createSingleExitEdge(Region *R) {
BasicBlock *oldExit = R->getExit();
SmallVector<BasicBlock*, 4> Preds;
for (pred_iterator PI = pred_begin(oldExit), PE = pred_end(oldExit);
PI != PE; ++PI)
if (R->contains(*PI))
Preds.push_back(*PI);
DEBUG(dbgs() << "Going to create single exit for:\n");
DEBUG(R->print(dbgs(), true, 0, Region::PrintRN));
BasicBlock *newExit = SplitBlockPredecessors(oldExit,
Preds.data(), Preds.size(),
".single_exit", this);
RegionInfo *RI = &getAnalysis<RegionInfo>();
// We do not need to update entry nodes because this split happens inside
// this region and it affects only this region and all of its children.
// The new split node belongs to this region
RI->setRegionFor(newExit,R);
DEBUG(dbgs() << "Adding new exiting block: " << newExit->getName() << '\n');
// all children of this region whose exit is oldExit is changed to newExit
std::vector<Region *> RQ;
for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE; ++RI)
RQ.push_back(*RI);
while (!RQ.empty()){
R = RQ.back();
RQ.pop_back();
if (R->getExit() != oldExit)
continue;
for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE; ++RI)
RQ.push_back(*RI);
R->replaceExit(newExit);
DEBUG(dbgs() << "Replacing exit for:\n");
DEBUG(R->print(dbgs(), true, 0, Region::PrintRN));
}
DEBUG(dbgs() << "After split exit:\n");
DEBUG(R->print(dbgs(), true, 0, Region::PrintRN));
}
bool RegionSimplify::runOnRegion(Region *R, RGPassManager &RGM) {
r = 0;
if (!R->isTopLevelRegion()) {
// split entry node if the region has multiple entry edges
if (!(R->getEnteringBlock())
&& (pred_begin(R->getEntry()) != pred_end(R->getEntry()))) {
createSingleEntryEdge(R);
r = R;
++NumEntries;
}
// split exit node if the region has multiple exit edges
if (!(R->getExitingBlock())) {
createSingleExitEdge(R);
r = R;
++NumExits;
}
}
return r != 0;
}

View File

@ -0,0 +1,121 @@
//===- AffSCEVItTester.cpp - Test the affine scev itertor. ----------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Test the affine scev itertor.
//
//===----------------------------------------------------------------------===//
#include "polly/Support/AffineSCEVIterator.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/InstIterator.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
using namespace llvm;
using namespace polly;
static void printSCEVAffine(raw_ostream &OS, const SCEV* S,
ScalarEvolution *SE) {
for (AffineSCEVIterator I = affine_begin(S, SE), E = affine_end();
I != E; ++I) {
OS << *I->second << " * " << *I->first;
// The constant part of the SCEV will always be the last one.
if (!isa<SCEVConstant>(S))
OS << " + ";
}
}
namespace {
struct AffSCEVItTester : public FunctionPass {
static char ID;
ScalarEvolution *SE;
LoopInfo *LI;
Function *F;
explicit AffSCEVItTester() : FunctionPass(ID), SE(0), LI(0), F(0) {}
virtual bool runOnFunction(Function &F) {
SE = &getAnalysis<ScalarEvolution>();
LI = &getAnalysis<LoopInfo>();
this->F = &F;
return false;
}
virtual void print(raw_ostream &OS, const Module *M) const {
for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
if (SE->isSCEVable(I->getType())) {
OS << *I << '\n';
OS << " --> ";
const SCEV *SV = SE->getSCEV(&*I);
if (Loop *L = LI->getLoopFor(I->getParent()))
SV = SE->getSCEVAtScope(SV, L);
SV->print(OS);
OS << "\n";
OS << "affine function --> ";
printSCEVAffine(OS, SV, SE);
OS << "\n";
}
for (LoopInfo::iterator I = LI->begin(), E = LI->end(); I != E; ++I)
PrintLoopInfo(OS, *I);
}
void PrintLoopInfo(raw_ostream &OS, const Loop *L) const{
// Print all inner loops first
for (Loop::iterator I = L->begin(), E = L->end(); I != E; ++I)
PrintLoopInfo(OS, *I);
OS << "Loop ";
WriteAsOperand(OS, L->getHeader(), /*PrintType=*/false);
OS << ": ";
if (SE->hasLoopInvariantBackedgeTakenCount(L)) {
const SCEV *SV = SE->getBackedgeTakenCount(L);
OS << "backedge-taken count is ";
printSCEVAffine(OS, SV, SE);
OS << "\nloop count in scev ";
SV->print(OS);
OS << "\n";
}
else {
OS << "Unpredictable\n";
}
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<ScalarEvolution>();
AU.addRequired<LoopInfo>();
AU.setPreservesAll();
}
};
} // end namespace
char AffSCEVItTester::ID = 0;
RegisterPass<AffSCEVItTester> B("print-scev-affine",
"Print the SCEV expressions in affine form.",
true,
true);
namespace polly {
Pass *createAffSCEVItTesterPass() {
return new AffSCEVItTester();
}
}

View File

@ -0,0 +1,5 @@
add_polly_library(PollySupport
AffSCEVItTester.cpp
GICHelper.cpp
ScopHelper.cpp
)

View File

@ -0,0 +1,91 @@
//===- 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 "isl/set.h"
#include "isl/union_set.h"
#include "isl/map.h"
#include "isl/union_map.h"
using namespace llvm;
void polly::MPZ_from_APInt (mpz_t v, const APInt apint, bool is_signed) {
// There is no sign taken from the data, rop will simply be a positive
// integer. An application can handle any sign itself, and apply it for
// instance with mpz_neg.
APInt abs;
if (is_signed)
abs = apint.abs();
else
abs = apint;
const uint64_t *rawdata = abs.getRawData();
unsigned numWords = abs.getNumWords();
// TODO: Check if this is true for all platforms.
mpz_import(v, numWords, 1, sizeof (uint64_t), 0, 0, rawdata);
if (is_signed && apint.isNegative()) mpz_neg(v, v);
}
APInt polly::APInt_from_MPZ (const mpz_t mpz) {
uint64_t *p = NULL;
size_t sz;
p = (uint64_t*) mpz_export(p, &sz, 1, sizeof(uint64_t), 0, 0, mpz);
if (p) {
APInt A((unsigned)mpz_sizeinbase(mpz, 2), (unsigned)sz , p);
A = A.zext(A.getBitWidth() + 1);
if (mpz_sgn(mpz) == -1)
return -A;
else
return A;
} else {
uint64_t val = 0;
return APInt(1, 1, &val);
}
}
std::string polly::stringFromIslObj(/*__isl_keep*/ isl_map *map) {
isl_printer *p = isl_printer_to_str(isl_map_get_ctx(map));
isl_printer_print_map(p, map);
std::string string(isl_printer_get_str(p));
isl_printer_free(p);
return string;
}
std::string polly::stringFromIslObj(/*__isl_keep*/ isl_set *set) {
isl_printer *p = isl_printer_to_str(isl_set_get_ctx(set));
isl_printer_print_set(p, set);
std::string string(isl_printer_get_str(p));
isl_printer_free(p);
return string;
}
std::string polly::stringFromIslObj(/*__isl_keep*/ isl_union_map *umap) {
isl_printer *p = isl_printer_to_str(isl_union_map_get_ctx(umap));
isl_printer_print_union_map(p, umap);
std::string string(isl_printer_get_str(p));
isl_printer_free(p);
return string;
}
std::string polly::stringFromIslObj(/*__isl_keep*/ isl_union_set *uset) {
isl_printer *p = isl_printer_to_str(isl_union_set_get_ctx(uset));
isl_printer_print_union_set(p, uset);
std::string string(isl_printer_get_str(p));
isl_printer_free(p);
return string;
}

16
polly/lib/Support/Makefile Executable file
View File

@ -0,0 +1,16 @@
##===- polly/lib/Support/Makefile ----------------*- Makefile -*-===##
#
# Indicate where we are relative to the top of the source tree.
#
LEVEL=../..
LIBRARYNAME=pollysupport
BUILD_ARCHIVE = 1
CPP.Flags += $(POLLY_INC)
#
# Include Makefile.common so we know what to do.
#
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,280 @@
//===- 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 "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Support/CFG.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#define DEBUG_TYPE "polly-scop-helper"
#include "llvm/Support/Debug.h"
using namespace llvm;
namespace {
// Checks if a SCEV is invariant in a region. This is if all Values are
// referenced in this SCEV are defined outside the region.
class InvariantChecker: SCEVVisitor<InvariantChecker, bool> {
Region &R;
public:
bool visitConstant(const SCEVConstant *S) {
return true;
}
bool visitUnknown(const SCEVUnknown* S) {
Value *V = S->getValue();
// An Instruction defined outside the region is invariant.
if (Instruction *I = dyn_cast<Instruction>(V))
return !R.contains(I);
// A constant is invariant.
return true;
}
bool visitNAryExpr(const SCEVNAryExpr *S) {
for (SCEVNAryExpr::op_iterator OI = S->op_begin(), OE = S->op_end();
OI != OE; ++OI)
if (!visit(*OI))
return false;
return true;
}
bool visitMulExpr(const SCEVMulExpr* S) {
return visitNAryExpr(S);
}
bool visitCastExpr(const SCEVCastExpr *S) {
return visit(S->getOperand());
}
bool visitTruncateExpr(const SCEVTruncateExpr *S) {
return visit(S->getOperand());
}
bool visitZeroExtendExpr(const SCEVZeroExtendExpr *S) {
return visit(S->getOperand());
}
bool visitSignExtendExpr(const SCEVSignExtendExpr *S) {
return visit(S->getOperand());
}
bool visitAddExpr(const SCEVAddExpr *S) {
return visitNAryExpr(S);
}
bool visitAddRecExpr(const SCEVAddRecExpr *S) {
// Check if the addrec is contained in the region.
if (R.contains(S->getLoop()))
return false;
return visitNAryExpr(S);
}
bool visitUDivExpr(const SCEVUDivExpr *S) {
return visit(S->getLHS()) && visit(S->getRHS());
}
bool visitSMaxExpr(const SCEVSMaxExpr *S) {
return visitNAryExpr(S);
}
bool visitUMaxExpr(const SCEVUMaxExpr *S) {
return visitNAryExpr(S);
}
bool visitCouldNotCompute(const SCEVCouldNotCompute *S) {
llvm_unreachable("SCEV cannot be checked");
}
InvariantChecker(Region &RefRegion)
: R(RefRegion) {}
static bool isInvariantInRegion(const SCEV *S, Region &R) {
InvariantChecker Checker(R);
return Checker.visit(S);
}
};
}
// 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;
}
//===----------------------------------------------------------------------===//
// Helper functions
bool polly::isInvariant(const SCEV *S, Region &R) {
return InvariantChecker::isInvariantInRegion(S, R);
}
// Helper function to check parameter
bool polly::isParameter(const SCEV *Var, Region &RefRegion,
LoopInfo &LI, ScalarEvolution &SE) {
assert(Var && "Var can not be null!");
if (!isInvariant(Var, RefRegion))
return false;
if (isa<SCEVAddRecExpr>(Var))
return true;
if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(Var)) {
if (isa<PHINode>(U->getValue()))
return false;
if(isa<UndefValue>(U->getValue()))
return false;
return true;
}
if (const SCEVCastExpr *Cast = dyn_cast<SCEVCastExpr>(Var))
return isParameter(Cast->getOperand(), RefRegion, LI, SE);
return false;
}
bool polly::isIndVar(const SCEV *Var, Region &RefRegion,
LoopInfo &LI, ScalarEvolution &SE) {
const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(Var);
// AddRecExprs are no induction variables.
if (!AddRec) return false;
Loop *L = const_cast<Loop*>(AddRec->getLoop());
// Is the addrec an induction variable of a loop contained in the current
// region.
if (!RefRegion.contains(L))
return false;
DEBUG(dbgs() << "Find AddRec: " << *AddRec
<< " at region: " << RefRegion.getNameStr() << " as indvar\n");
return true;
}
bool polly::isIndVar(const Instruction *I, const LoopInfo *LI) {
Loop *L = LI->getLoopFor(I->getParent());
return L && I == L->getCanonicalInductionVariable();
}
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;
}
// Helper function for LLVM-IR about Scop
BasicBlock *polly::createSingleEntryEdge(Region *R, Pass *P) {
BasicBlock *BB = R->getEntry();
BasicBlock::iterator SplitIt = BB->begin();
while (isa<PHINode>(SplitIt))
++SplitIt;
BasicBlock *newBB = SplitBlock(BB, SplitIt, P);
for (BasicBlock::iterator PI = BB->begin(); isa<PHINode>(PI); ++PI) {
PHINode *PN = cast<PHINode>(PI);
PHINode *NPN =
PHINode::Create(PN->getType(), 2, PN->getName()+".ph", newBB->begin());
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) {
if (R->contains(*PI)) {
Value *V = PN->removeIncomingValue(*PI, false);
NPN->addIncoming(V, *PI);
}
}
PN->replaceAllUsesWith(NPN);
NPN->addIncoming(PN,BB);
}
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI)
if (R->contains(*PI))
(*PI)->getTerminator()->replaceUsesOfWith(BB, newBB);
return newBB;
}
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);
return SplitBlockPredecessors(BB, Preds.data(), Preds.size(), ".region", P);
}
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;
// SplitBlock updates DT, DF and LI.
BasicBlock *NewEntry = SplitBlock(EntryBlock, I, P);
if (RegionInfo *RI = P->getAnalysisIfAvailable<RegionInfo>())
RI->splitBlock(NewEntry, EntryBlock);
}

View File

@ -0,0 +1,24 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define void @f(i32* nocapture %a) nounwind {
entry:
%0 = tail call i32 (...)* @rnd() nounwind ; <i32> [#uses=2]
; CHECK: 1 * %0 + 0 * 1
%1 = icmp sgt i32 %0, 0 ; <i1> [#uses=1]
br i1 %1, label %bb, label %return
bb: ; preds = %bb, %entry
%i.03 = phi i32 [ 0, %entry ], [ %3, %bb ] ; <i32> [#uses=1]
; CHECK: 1 * {0,+,1}<nuw><nsw><%bb> + 0 * 1
%2 = tail call i32 (...)* @rnd() nounwind ; <i32> [#uses=0]
; CHECK: 1 * %2 + 0 * 1
%3 = add nsw i32 %i.03, 1 ; <i32> [#uses=2]
; CHECK: 1 * {0,+,1}<nuw><nsw><%bb> + 1 * 1
%exitcond = icmp eq i32 %3, %0 ; <i1> [#uses=1]
br i1 %exitcond, label %return, label %bb
return: ; preds = %bb, %entry
ret void
}
declare i32 @rnd(...)

View File

@ -0,0 +1,20 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define i32 @f(i64 %a, i64 %b, i64 %c, [8 x i32]* nocapture %x) nounwind readonly {
entry:
%0 = shl i64 %a, 1 ; <i64> [#uses=1]
%1 = add nsw i64 %0, %b ; <i64> [#uses=1]
; CHECK: 1 * %b + 2 * %a + 0 * 1
%2 = shl i64 %1, 1 ; <i64> [#uses=1]
; CHECK: 2 * %b + 4 * %a + 0 * 1
%3 = add i64 %2, 2 ; <i64> [#uses=1]
%4 = mul i64 %a, 3 ; <i64> [#uses=1]
%5 = shl i64 %b, 2 ; <i64> [#uses=1]
%6 = add nsw i64 %4, 2 ; <i64> [#uses=1]
%7 = add nsw i64 %6, %c ; <i64> [#uses=1]
%8 = add nsw i64 %7, %5 ; <i64> [#uses=1]
%9 = getelementptr inbounds [8 x i32]* %x, i64 %3, i64 %8 ; <i32*> [#uses=1]
; CHECK: 1 * %x + sizeof(i32) * %c + (35 * sizeof(i32)) * %a + (20 * sizeof(i32)) * %b + (18 * sizeof(i32)) * 1
%10 = load i32* %9, align 4 ; <i32> [#uses=1]
ret i32 %10
}

View File

@ -0,0 +1,44 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define void @f([8 x i32]* nocapture %x) nounwind {
entry:
br label %bb5.preheader
bb2: ; preds = %bb3.preheader, %bb2
%k.09 = phi i64 [ 0, %bb3.preheader ], [ %1, %bb2 ] ; <i64> [#uses=2]
%tmp19 = add i64 %k.09, %tmp18 ; <i64> [#uses=1]
%scevgep = getelementptr [8 x i32]* %x, i64 2, i64 %tmp19 ; <i32*> [#uses=1]
; CHECK: sizeof(i32) * {0,+,1}<nuw><nsw><%bb2> + (20 * sizeof(i32)) * {0,+,1}<%bb3.preheader> + (35 * sizeof(i32)) * {0,+,1}<%bb5.preheader> + 1 * %x + (18 * sizeof(i32)) * 1
%0 = tail call i32 (...)* @rnd() nounwind ; <i32> [#uses=1]
store i32 %0, i32* %scevgep, align 4
%1 = add nsw i64 %k.09, 1 ; <i64> [#uses=2]
%exitcond = icmp eq i64 %1, 64 ; <i1> [#uses=1]
br i1 %exitcond, label %bb4, label %bb2
bb4: ; preds = %bb2
%2 = add i64 %j.010, 1 ; <i64> [#uses=2]
%exitcond20 = icmp eq i64 %2, 64 ; <i1> [#uses=1]
br i1 %exitcond20, label %bb6, label %bb3.preheader
bb3.preheader: ; preds = %bb5.preheader, %bb4
%j.010 = phi i64 [ 0, %bb5.preheader ], [ %2, %bb4 ] ; <i64> [#uses=2]
%tmp21 = mul i64 %j.010, 20 ; <i64> [#uses=1]
%tmp18 = add i64 %tmp21, %tmp23 ; <i64> [#uses=1]
br label %bb2
bb6: ; preds = %bb4
%3 = add i64 %i.012, 1 ; <i64> [#uses=2]
%exitcond25 = icmp eq i64 %3, 64 ; <i1> [#uses=1]
br i1 %exitcond25, label %return, label %bb5.preheader
bb5.preheader: ; preds = %bb6, %entry
%i.012 = phi i64 [ 0, %entry ], [ %3, %bb6 ] ; <i64> [#uses=2]
%tmp = mul i64 %i.012, 35 ; <i64> [#uses=1]
%tmp23 = add i64 %tmp, 2 ; <i64> [#uses=1]
br label %bb3.preheader
return: ; preds = %bb6
ret void
}
declare i32 @rnd(...)

View File

@ -0,0 +1,20 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -analyze < %s | FileCheck %s
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, i32* nocapture %x) nounwind readnone {
entry:
%0 = shl i32 %a, 1 ; <i32> [#uses=1]
; CHECK: 2 * %a + 0 * 1
%1 = mul i32 %b, 3 ; <i32> [#uses=1]
; CHECK: 3 * %b + 0 * 1
%2 = shl i32 %d, 2 ; <i32> [#uses=1]
; CHECK: 4 * %d + 0 * 1
%3 = add nsw i32 %0, 5 ; <i32> [#uses=1]
; CHECK: 2 * %a + 5 * 1
%4 = add nsw i32 %3, %c ; <i32> [#uses=1]
; CHECK: 1 * %c + 2 * %a + 5 * 1
%5 = add nsw i32 %4, %1 ; <i32> [#uses=1]
; CHECK: 1 * %c + 3 * %b + 2 * %a + 5 * 1
%6 = add nsw i32 %5, %2 ; <i32> [#uses=1]
; CHECK: 1 * %c + 4 * %d + 3 * %b + 2 * %a + 5 * 1
ret i32 %6
}

View File

@ -0,0 +1,24 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -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"
target triple = "x86_64-unknown-linux-gnu"
define i32 @f(i32 %a, i32 %b, i32 %c, i64 %d, i8 signext %e, i32 %f, i32 %g, i32 %h) nounwind readnone {
entry:
%0 = mul i32 %a, 3 ; <i32> [#uses=1]
%1 = mul i32 %b, 5 ; <i32> [#uses=1]
%2 = mul i32 %1, %c ; <i32> [#uses=1]
; CHECK: 5 * (%b * %c) + 0 * 1
%3 = mul i32 %2, %f ; <i32> [#uses=1]
; CHECK: 5 * (%b * %c * %f) + 0 * 1
%4 = sext i8 %e to i32 ; <i32> [#uses=1]
%5 = shl i32 %4, 2 ; <i32> [#uses=1]
%6 = trunc i64 %d to i32 ; <i32> [#uses=1]
%7 = mul i32 %6, %h ; <i32> [#uses=1]
%8 = add nsw i32 %0, %g ; <i32> [#uses=1]
%9 = add nsw i32 %8, %5 ; <i32> [#uses=1]
%10 = add nsw i32 %9, %3 ; <i32> [#uses=1]
%11 = add nsw i32 %10, %7 ; <i32> [#uses=1]
; CHECK: 1 * %g + 1 * ((trunc i64 %d to i32) * %h) + 5 * (%b * %c * %f) + 4 * (sext i8 %e to i32) + 3 * %a + 0 * 1
ret i32 %11
}

View File

@ -0,0 +1,25 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -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"
target triple = "x86_64-unknown-linux-gnu"
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, i32* nocapture %x) nounwind {
entry:
br label %bb
bb: ; preds = %bb, %entry
%indvar = phi i64 [ 0, %entry ], [ %indvar.next, %bb ] ; <i64> [#uses=3]
; CHECK: 1 * {0,+,1}<%bb> + 0 * 1
%scevgep = getelementptr i32* %x, i64 %indvar ; <i32*> [#uses=1]
; CHECK: 4 * {0,+,1}<%bb> + 1 * %x + 0 * 1
%i.04 = trunc i64 %indvar to i32 ; <i32> [#uses=1]
; CHECK: 1 * {0,+,1}<%bb> + 0 * 1
store i32 %i.04, i32* %scevgep, align 4
%indvar.next = add i64 %indvar, 1 ; <i64> [#uses=2]
; CHECK: 1 * {0,+,1}<%bb> + 1 * 1
%exitcond = icmp eq i64 %indvar.next, 64 ; <i1> [#uses=1]
br i1 %exitcond, label %bb2, label %bb
bb2: ; preds = %bb
ret i32 %a
}

View File

@ -0,0 +1,38 @@
; RUN: opt %loadPolly %defaultOpts -print-scev-affine -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"
target triple = "x86_64-unknown-linux-gnu"
define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d, [4 x i32]* nocapture %x) nounwind {
entry:
br label %bb2.preheader
bb1: ; preds = %bb2.preheader, %bb1
%indvar = phi i64 [ 0, %bb2.preheader ], [ %indvar.next, %bb1 ] ; <i64> [#uses=3]
; CHECK: 1 * {0,+,1}<%bb1> + 0 * 1
%scevgep = getelementptr [4 x i32]* %x, i64 %indvar, i64 %0 ; <i32*> [#uses=1]
; CHECK: 16 * {0,+,1}<%bb1> + 4 * {0,+,1}<%bb2.preheader> + 1 * %x + 0 * 1
%tmp = mul i64 %indvar, %0 ; <i64> [#uses=1]
; CHECK: 1 * {0,+,{0,+,1}<%bb2.preheader>}<%bb1> + 0 * 1
%tmp13 = trunc i64 %tmp to i32 ; <i32> [#uses=1]
; CHECK: 1 * {0,+,{0,+,1}<%bb2.preheader>}<%bb1> + 0 * 1
store i32 %tmp13, i32* %scevgep, align 4
%indvar.next = add i64 %indvar, 1 ; <i64> [#uses=2]
; CHECK: 1 * {0,+,1}<%bb1> + 1 * 1
%exitcond = icmp eq i64 %indvar.next, 64 ; <i1> [#uses=1]
br i1 %exitcond, label %bb3, label %bb1
bb3: ; preds = %bb1
%indvar.next12 = add i64 %0, 1 ; <i64> [#uses=2]
; CHECK: 1 * {0,+,1}<%bb2.preheader> + 1 * 1
%exitcond14 = icmp eq i64 %indvar.next12, 64 ; <i1> [#uses=1]
br i1 %exitcond14, label %bb5, label %bb2.preheader
bb2.preheader: ; preds = %bb3, %entry
%0 = phi i64 [ 0, %entry ], [ %indvar.next12, %bb3 ] ; <i64> [#uses=3]
; CHECK: 1 * {0,+,1}<%bb2.preheader> + 0 * 1
br label %bb1
bb5: ; preds = %bb3
ret i32 %a
}

52
polly/test/CMakeLists.txt Normal file
View File

@ -0,0 +1,52 @@
set(POLLY_TEST_DIRECTORIES
"ScopInfo"
"AffineIterator"
"CodeGen"
"OpenMP"
"polybench")
set(LLVM_SOURCE_DIR "${LLVM_MAIN_SRC_DIR}")
set(LLVM_BINARY_DIR "${LLVM_BINARY_DIR}")
set(LLVM_TOOLS_DIR "${LLVM_TOOLS_BINARY_DIR}/")
set(LLVM_LIBS_DIR "${LLVM_BINARY_DIR}/lib")
set(POLLY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
set(POLLY_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/..")
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg)
include(FindPythonInterp)
if(PYTHONINTERP_FOUND)
set(POLLY_TEST_EXTRA_ARGS)
if (MSVC OR XCODE)
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 ${PYTHON_EXECUTABLE}
${LLVM_SOURCE_DIR}/utils/lit/lit.py
--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 opt LLVMPolly
COMMENT "Running Polly regression tests in ${testdir}")
endforeach()
add_custom_target(polly-test
COMMAND ${PYTHON_EXECUTABLE}
${LLVM_SOURCE_DIR}/utils/lit/lit.py
--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 opt LLVMPolly
COMMENT "Running Polly regression tests")
endif()

View File

@ -0,0 +1,20 @@
; RUN: opt %loadPolly %defaultOpts -polly-codegen < %s
; ModuleID = 'a'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
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
}

View File

@ -0,0 +1,44 @@
; RUN: opt %loadPolly %defaultOpts -polly-codegen < %s
; RUN: opt %loadPolly %defaultOpts -polly-detect -analyze %s | not FileCheck %s
; ModuleID = 'a'
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"
target triple = "i386-portbld-freebsd8.0"
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:

View File

@ -0,0 +1,28 @@
; RUN: opt %loadPolly %defaultOpts -polly-codegen < %s
; ModuleID = 'a'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-unknown-linux-gnu"
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
}

Some files were not shown because too many files have changed in this diff Show More