[Polly] Update isl to isl-0.27-77-g99a07a03 (#179350)

Update isl to include
https://repo.or.cz/isl.git/commit/99a07a039237f11bccc1ef80a7b6cc76ae5f98c5
which fixes #177808

Thanks @skimo-openhub for the fix and @Andarwinux for the crash report

Fixes: #177808
This commit is contained in:
Michael Kruse 2026-02-03 00:02:03 +01:00 committed by GitHub
parent 350b138313
commit cdab38f776
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 1467 additions and 616 deletions

View File

@ -1 +1 @@
isl-0.27
isl-0.27-77-g99a07a03

View File

@ -469,8 +469,8 @@ Use the system clang libraries installed in I<path>.
=back
It is best to use the latest release of the clang libraries (16.0),
although any release since 3.5 should work as well.
It is best to use the latest release of the clang libraries (21.1),
although any release since 3.9 should work as well.
Note that if you build the clang libraries from source,
then you need to make sure they are also installed (using C<make install>).
If the compiler that was used to compile the clang libraries
@ -5247,6 +5247,9 @@ return true if the objects are not the same.
__isl_keep isl_multi_id *mi2);
#include <isl/val.h>
isl_bool isl_multi_val_is_equal(
__isl_keep isl_multi_val *mv1,
__isl_keep isl_multi_val *mv2);
isl_bool isl_multi_val_plain_is_equal(
__isl_keep isl_multi_val *mv1,
__isl_keep isl_multi_val *mv2);
@ -6450,9 +6453,17 @@ variables, then the result of these operations is currently undefined.
__isl_take isl_map *map,
__isl_take isl_map_list *list);
#include <isl/union_set.h>
__isl_give isl_union_set *
isl_union_set_plain_unshifted_simple_hull(
__isl_take isl_union_set *uset);
#include <isl/union_map.h>
__isl_give isl_union_map *isl_union_map_simple_hull(
__isl_take isl_union_map *umap);
__isl_give isl_union_map *
isl_union_map_plain_unshifted_simple_hull(
__isl_take isl_union_map *umap);
These functions compute a single basic set or relation
that contains the whole input set or relation.
@ -6553,6 +6564,14 @@ The box can be copied and freed using the following functions.
__isl_null isl_fixed_box *isl_fixed_box_free(
__isl_take isl_fixed_box *box);
The following function checks whether two C<isl_fixed_box> objects
are obviously the same.
#include <isl/fixed_box.h>
isl_bool isl_fixed_box_plain_is_equal(
__isl_keep isl_fixed_box *box1,
__isl_keep isl_fixed_box *box2);
An object of type C<isl_fixed_box> can be read from input
using the following function.

View File

@ -288,6 +288,8 @@ struct isl_args {
#define ISL_ARG_ALL (1 << 0)
#define ISL_ARG_SKIP_HELP (1 << 1)
int isl_arg_str_list_append(int *n, const char ***list, const char *s);
void isl_args_set_defaults(struct isl_args *args, void *opt);
void isl_args_free(struct isl_args *args, void *opt);
int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt,

View File

@ -1742,6 +1742,7 @@ class fixed_box {
inline boolean is_valid() const;
inline isl::checked::multi_aff offset() const;
inline isl::checked::multi_aff get_offset() const;
inline boolean plain_is_equal(const isl::checked::fixed_box &box2) const;
inline isl::checked::multi_val size() const;
inline isl::checked::multi_val get_size() const;
inline isl::checked::space space() const;
@ -2586,6 +2587,7 @@ class multi_val {
inline isl::checked::multi_val flat_range_product(isl::checked::multi_val multi2) const;
inline boolean has_range_tuple_id() const;
inline boolean involves_nan() const;
inline boolean is_equal(const isl::checked::multi_val &mv2) const;
inline isl::checked::val_list list() const;
inline isl::checked::val_list get_list() const;
inline isl::checked::multi_val max(isl::checked::multi_val multi2) const;
@ -9037,6 +9039,12 @@ isl::checked::multi_aff fixed_box::get_offset() const
return offset();
}
boolean fixed_box::plain_is_equal(const isl::checked::fixed_box &box2) const
{
auto res = isl_fixed_box_plain_is_equal(get(), box2.get());
return manage(res);
}
isl::checked::multi_val fixed_box::size() const
{
auto res = isl_fixed_box_get_size(get());
@ -12843,6 +12851,12 @@ boolean multi_val::involves_nan() const
return manage(res);
}
boolean multi_val::is_equal(const isl::checked::multi_val &mv2) const
{
auto res = isl_multi_val_is_equal(get(), mv2.get());
return manage(res);
}
isl::checked::val_list multi_val::list() const
{
auto res = isl_multi_val_get_list(get());

View File

@ -1808,6 +1808,7 @@ class fixed_box {
inline bool is_valid() const;
inline isl::multi_aff offset() const;
inline isl::multi_aff get_offset() const;
inline bool plain_is_equal(const isl::fixed_box &box2) const;
inline isl::multi_val size() const;
inline isl::multi_val get_size() const;
inline isl::space space() const;
@ -2652,6 +2653,7 @@ class multi_val {
inline isl::multi_val flat_range_product(isl::multi_val multi2) const;
inline bool has_range_tuple_id() const;
inline bool involves_nan() const;
inline bool is_equal(const isl::multi_val &mv2) const;
inline isl::val_list list() const;
inline isl::val_list get_list() const;
inline isl::multi_val max(isl::multi_val multi2) const;
@ -10929,6 +10931,18 @@ isl::multi_aff fixed_box::get_offset() const
return offset();
}
bool fixed_box::plain_is_equal(const isl::fixed_box &box2) const
{
if (!ptr || box2.is_null())
exception::throw_invalid("NULL input", __FILE__, __LINE__);
auto saved_ctx = ctx();
options_scoped_set_on_error saved_on_error(saved_ctx, exception::on_error);
auto res = isl_fixed_box_plain_is_equal(get(), box2.get());
if (res < 0)
exception::throw_last_error(saved_ctx);
return res;
}
isl::multi_val fixed_box::size() const
{
if (!ptr)
@ -17158,6 +17172,18 @@ bool multi_val::involves_nan() const
return res;
}
bool multi_val::is_equal(const isl::multi_val &mv2) const
{
if (!ptr || mv2.is_null())
exception::throw_invalid("NULL input", __FILE__, __LINE__);
auto saved_ctx = ctx();
options_scoped_set_on_error saved_on_error(saved_ctx, exception::on_error);
auto res = isl_multi_val_is_equal(get(), mv2.get());
if (res < 0)
exception::throw_last_error(saved_ctx);
return res;
}
isl::val_list multi_val::list() const
{
if (!ptr)

View File

@ -12,6 +12,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <isl/arg.h>
@ -85,7 +86,7 @@ typedef enum {
isl_stat_error = -1,
isl_stat_ok = 0
} isl_stat;
isl_stat isl_stat_non_null(void *obj);
isl_stat isl_stat_non_null(const void *obj);
typedef enum {
isl_bool_error = -1,
isl_bool_false = 0,
@ -240,6 +241,21 @@ isl_stat prefix ## _set_ ## field(isl_ctx *ctx, const char *val) \
return isl_stat_ok; \
}
#define ISL_CTX_APPEND_STR_LIST_DEF(prefix,st,args,field_n,field) \
isl_stat prefix ## _append_ ## field(isl_ctx *ctx, const char *val) \
{ \
st *options; \
options = isl_ctx_peek_ ## prefix(ctx); \
if (!options) \
isl_die(ctx, isl_error_invalid, \
"isl_ctx does not reference " #prefix, \
return isl_stat_error); \
if (!val) \
return isl_stat_error; \
return isl_arg_str_list_append(&options->field_n, \
&options->field, val); \
}
#define ISL_CTX_GET_BOOL_DEF(prefix,st,args,field) \
ISL_CTX_GET_INT_DEF(prefix,st,args,field)

View File

@ -31,6 +31,10 @@ __isl_give isl_multi_val *isl_fixed_box_get_size(__isl_keep isl_fixed_box *box);
__isl_give isl_fixed_box *isl_fixed_box_copy(__isl_keep isl_fixed_box *box);
__isl_null isl_fixed_box *isl_fixed_box_free(__isl_take isl_fixed_box *box);
__isl_export
isl_bool isl_fixed_box_plain_is_equal(__isl_keep isl_fixed_box *box1,
__isl_keep isl_fixed_box *box2);
__isl_constructor
__isl_give isl_fixed_box *isl_fixed_box_read_from_str(isl_ctx *ctx,
const char *str);

View File

@ -82,6 +82,8 @@ __isl_give isl_union_map *isl_union_map_remove_redundancies(
__isl_take isl_union_map *umap);
__isl_give isl_union_map *isl_union_map_simple_hull(
__isl_take isl_union_map *umap);
__isl_give isl_union_map *isl_union_map_plain_unshifted_simple_hull(
__isl_take isl_union_map *umap);
__isl_export
__isl_give isl_union_map *isl_union_map_coalesce(
__isl_take isl_union_map *umap);

View File

@ -52,6 +52,8 @@ __isl_give isl_union_set *isl_union_set_remove_redundancies(
__isl_take isl_union_set *uset);
__isl_give isl_union_set *isl_union_set_simple_hull(
__isl_take isl_union_set *uset);
__isl_give isl_union_set *isl_union_set_plain_unshifted_simple_hull(
__isl_take isl_union_set *uset);
__isl_export
__isl_give isl_union_set *isl_union_set_coalesce(
__isl_take isl_union_set *uset);

View File

@ -153,6 +153,9 @@ __isl_give isl_printer *isl_printer_print_val(__isl_take isl_printer *p,
void isl_val_dump(__isl_keep isl_val *v);
__isl_give char *isl_val_to_str(__isl_keep isl_val *v);
__isl_export
isl_bool isl_multi_val_is_equal(__isl_keep isl_multi_val *mv1,
__isl_keep isl_multi_val *mv2);
isl_bool isl_multi_val_is_zero(__isl_keep isl_multi_val *mv);
__isl_overload

View File

@ -25,7 +25,7 @@ LT_INIT
AX_DETECT_CLANG
AC_SUBST([CONFIG_STATUS_DEPENDENCIES], [$LLVM_CONFIG])
AC_CONFIG_HEADERS(isl_config.h)
AC_CONFIG_HEADERS(isl_config.h include/isl-interface/config.h)
AC_CONFIG_FILES(Makefile)
AC_OUTPUT

View File

@ -689,12 +689,12 @@ std::string cpp_type_printer::generate_callback_args(int arg, QualType type,
int num_params;
callback = generator::extract_prototype(type);
num_params = callback->getNumArgs();
num_params = callback->getNumParams();
if (cpp)
num_params--;
for (long i = 0; i < num_params; i++) {
QualType type = callback->getArgType(i);
QualType type = callback->getParamType(i);
if (cpp)
type_str += param(arg + 1 + i, type);

View File

@ -38,52 +38,24 @@
#include <iostream>
#include <stdlib.h>
#include <type_traits>
#ifdef HAVE_ADT_OWNINGPTR_H
#include <llvm/ADT/OwningPtr.h>
#else
#include <memory>
#endif
#ifdef HAVE_LLVM_OPTION_ARG_H
#include <llvm/Option/Arg.h>
#endif
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/CommandLine.h>
#ifdef HAVE_TARGETPARSER_HOST_H
#include <llvm/TargetParser/Host.h>
#else
#include <llvm/Support/Host.h>
#endif
#include <llvm/Support/ManagedStatic.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/Basic/Builtins.h>
#include <clang/Basic/FileSystemOptions.h>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/TargetOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Basic/Version.h>
#include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h>
#include <clang/Driver/Tool.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
#include <clang/Basic/DiagnosticOptions.h>
#else
#include <clang/Frontend/DiagnosticOptions.h>
#endif
#include <clang/Basic/FileSystemOptions.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Frontend/Utils.h>
#include <clang/Lex/HeaderSearch.h>
#ifdef HAVE_LEX_PREPROCESSOROPTIONS_H
#include <clang/Lex/PreprocessorOptions.h>
#else
#include <clang/Frontend/PreprocessorOptions.h>
#endif
#include <clang/Lex/Preprocessor.h>
#include <clang/Parse/ParseAST.h>
#include <clang/Sema/Sema.h>
#include "isl-interface/clang_wrap.h"
#include "extract_interface.h"
#include "generator.h"
#include "python.h"
@ -98,10 +70,6 @@ using namespace clang::driver;
using namespace llvm::opt;
#endif
#ifdef HAVE_ADT_OWNINGPTR_H
#define unique_ptr llvm::OwningPtr
#endif
static llvm::cl::opt<string> InputFilename(llvm::cl::Positional,
llvm::cl::Required, llvm::cl::desc("<input file>"));
static llvm::cl::list<string> Includes("I",
@ -113,9 +81,6 @@ static llvm::cl::opt<string> OutputLanguage(llvm::cl::Required,
llvm::cl::desc("Bindings to generate"),
llvm::cl::value_desc("name"));
static const char *ResourceDir =
CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING;
/* Does decl have an attribute of the following form?
*
* __attribute__((annotate("name")))
@ -179,360 +144,59 @@ struct MyASTConsumer : public ASTConsumer {
}
};
#ifdef USE_ARRAYREF
#ifdef HAVE_CXXISPRODUCTION
static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
{
return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
"", false, false, Diags);
}
#elif defined(HAVE_ISPRODUCTION)
static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
{
return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
"", false, Diags);
}
#elif defined(DRIVER_CTOR_TAKES_DEFAULTIMAGENAME)
static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
{
return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
"", Diags);
}
#else
static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
{
return new Driver(binary, llvm::sys::getDefaultTargetTriple(), Diags);
}
#endif
namespace clang { namespace driver { class Job; } }
/* Clang changed its API from 3.5 to 3.6 and once more in 3.7.
* We fix this with a simple overloaded function here.
/* A class specializing the Wrap helper class for
* extracting the isl interface.
*/
struct ClangAPI {
static Job *command(Job *J) { return J; }
static Job *command(Job &J) { return &J; }
static Command *command(Command &C) { return &C; }
struct Extractor : public isl::clang::Wrap {
virtual TextDiagnosticPrinter *construct_printer() override;
virtual void suppress_errors(DiagnosticsEngine &Diags) override;
virtual void add_paths(HeaderSearchOptions &HSO) override;
virtual void add_macros(PreprocessorOptions &PO) override;
virtual void handle_error() override;
virtual bool handle(CompilerInstance *Clang) override;
};
#ifdef CREATE_FROM_ARGS_TAKES_ARRAYREF
/* Call CompilerInvocation::CreateFromArgs with the right arguments.
* In this case, an ArrayRef<const char *>.
/* Construct a TextDiagnosticPrinter.
*/
static void create_from_args(CompilerInvocation &invocation,
const ArgStringList *args, DiagnosticsEngine &Diags)
TextDiagnosticPrinter *Extractor::construct_printer(void)
{
CompilerInvocation::CreateFromArgs(invocation, *args, Diags);
return new TextDiagnosticPrinter(llvm::errs(), getDiagnosticOptions());
}
#else
/* Call CompilerInvocation::CreateFromArgs with the right arguments.
* In this case, two "const char *" pointers.
/* Suppress any errors, if needed.
*/
static void create_from_args(CompilerInvocation &invocation,
const ArgStringList *args, DiagnosticsEngine &Diags)
void Extractor::suppress_errors(DiagnosticsEngine &Diags)
{
CompilerInvocation::CreateFromArgs(invocation, args->data() + 1,
args->data() + args->size(),
Diags);
}
#endif
#ifdef CLANG_SYSROOT
/* Set sysroot if required.
*
* If CLANG_SYSROOT is defined, then set it to this value.
/* Add required search paths to "HSO".
*/
static void set_sysroot(ArgStringList &args)
void Extractor::add_paths(HeaderSearchOptions &HSO)
{
args.push_back("-isysroot");
args.push_back(CLANG_SYSROOT);
for (llvm::cl::list<string>::size_type i = 0; i < Includes.size(); ++i)
isl::clang::add_path(HSO, Includes[i]);
}
#else
/* Set sysroot if required.
*
* If CLANG_SYSROOT is not defined, then it does not need to be set.
/* Add required macro definitions to "PO".
*/
static void set_sysroot(ArgStringList &args)
void Extractor::add_macros(PreprocessorOptions &PO)
{
PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))");
PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))");
PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))");
PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))");
PO.addMacroDef("__isl_overload="
"__attribute__((annotate(\"isl_overload\"))) "
"__attribute__((annotate(\"isl_export\")))");
PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))");
PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))");
}
#endif
/* Create a CompilerInvocation object that stores the command line
* arguments constructed by the driver.
* The arguments are mainly useful for setting up the system include
* paths on newer clangs and on some platforms.
/* Handle an error opening the file.
*/
static CompilerInvocation *construct_invocation(const char *filename,
DiagnosticsEngine &Diags)
void Extractor::handle_error()
{
const char *binary = CLANG_PREFIX"/bin/clang";
const unique_ptr<Driver> driver(construct_driver(binary, Diags));
std::vector<const char *> Argv;
Argv.push_back(binary);
Argv.push_back(filename);
const unique_ptr<Compilation> compilation(
driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv)));
JobList &Jobs = compilation->getJobs();
Command *cmd = cast<Command>(ClangAPI::command(*Jobs.begin()));
if (strcmp(cmd->getCreator().getName(), "clang"))
return NULL;
ArgStringList args = cmd->getArguments();
set_sysroot(args);
CompilerInvocation *invocation = new CompilerInvocation;
create_from_args(*invocation, &args, Diags);
return invocation;
}
#else
static CompilerInvocation *construct_invocation(const char *filename,
DiagnosticsEngine &Diags)
{
return NULL;
}
#endif
#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
static TextDiagnosticPrinter *construct_printer(void)
{
return new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions());
}
#else
static TextDiagnosticPrinter *construct_printer(void)
{
DiagnosticOptions DO;
return new TextDiagnosticPrinter(llvm::errs(), DO);
}
#endif
#ifdef CREATETARGETINFO_TAKES_SHARED_PTR
static TargetInfo *create_target_info(CompilerInstance *Clang,
DiagnosticsEngine &Diags)
{
shared_ptr<TargetOptions> TO = Clang->getInvocation().TargetOpts;
TO->Triple = llvm::sys::getDefaultTargetTriple();
return TargetInfo::CreateTargetInfo(Diags, TO);
}
#elif defined(CREATETARGETINFO_TAKES_POINTER)
static TargetInfo *create_target_info(CompilerInstance *Clang,
DiagnosticsEngine &Diags)
{
TargetOptions &TO = Clang->getTargetOpts();
TO.Triple = llvm::sys::getDefaultTargetTriple();
return TargetInfo::CreateTargetInfo(Diags, &TO);
}
#else
static TargetInfo *create_target_info(CompilerInstance *Clang,
DiagnosticsEngine &Diags)
{
TargetOptions &TO = Clang->getTargetOpts();
TO.Triple = llvm::sys::getDefaultTargetTriple();
return TargetInfo::CreateTargetInfo(Diags, TO);
}
#endif
#ifdef CREATEDIAGNOSTICS_TAKES_ARG
static void create_diagnostics(CompilerInstance *Clang)
{
Clang->createDiagnostics(0, NULL, construct_printer());
}
#else
static void create_diagnostics(CompilerInstance *Clang)
{
Clang->createDiagnostics(construct_printer());
}
#endif
#ifdef CREATEPREPROCESSOR_TAKES_TUKIND
static void create_preprocessor(CompilerInstance *Clang)
{
Clang->createPreprocessor(TU_Complete);
}
#else
static void create_preprocessor(CompilerInstance *Clang)
{
Clang->createPreprocessor();
}
#endif
#ifdef ADDPATH_TAKES_4_ARGUMENTS
/* Add "Path" to the header search options.
*
* Do not take into account sysroot, i.e., set ignoreSysRoot to true.
*/
void add_path(HeaderSearchOptions &HSO, string Path)
{
HSO.AddPath(Path, frontend::Angled, false, true);
}
#else
/* Add "Path" to the header search options.
*
* Do not take into account sysroot, i.e., set IsSysRootRelative to false.
*/
void add_path(HeaderSearchOptions &HSO, string Path)
{
HSO.AddPath(Path, frontend::Angled, true, false, false);
}
#endif
#ifdef HAVE_SETMAINFILEID
template <typename T>
static void create_main_file_id(SourceManager &SM, const T &file)
{
SM.setMainFileID(SM.createFileID(file, SourceLocation(),
SrcMgr::C_User));
}
#else
static void create_main_file_id(SourceManager &SM, const FileEntry *file)
{
SM.createMainFileID(file);
}
#endif
#ifdef SETLANGDEFAULTS_TAKES_5_ARGUMENTS
#include "set_lang_defaults_arg4.h"
static void set_lang_defaults(CompilerInstance *Clang)
{
PreprocessorOptions &PO = Clang->getPreprocessorOpts();
TargetOptions &TO = Clang->getTargetOpts();
llvm::Triple T(TO.Triple);
SETLANGDEFAULTS::setLangDefaults(Clang->getLangOpts(), IK_C, T,
setLangDefaultsArg4(PO),
LangStandard::lang_unspecified);
}
#else
static void set_lang_defaults(CompilerInstance *Clang)
{
CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
LangStandard::lang_unspecified);
}
#endif
#ifdef SETINVOCATION_TAKES_SHARED_PTR
static void set_invocation(CompilerInstance *Clang,
CompilerInvocation *invocation)
{
Clang->setInvocation(std::make_shared<CompilerInvocation>(*invocation));
}
#else
static void set_invocation(CompilerInstance *Clang,
CompilerInvocation *invocation)
{
Clang->setInvocation(invocation);
}
#endif
/* Helper function for ignore_error that only gets enabled if T
* (which is either const FileEntry * or llvm::ErrorOr<const FileEntry *>)
* has getError method, i.e., if it is llvm::ErrorOr<const FileEntry *>.
*/
template <class T>
static const FileEntry *ignore_error_helper(const T obj, int,
int[1][sizeof(obj.getError())])
{
return *obj;
}
/* Helper function for ignore_error that is always enabled,
* but that only gets selected if the variant above is not enabled,
* i.e., if T is const FileEntry *.
*/
template <class T>
static const FileEntry *ignore_error_helper(const T obj, long, void *)
{
return obj;
}
/* Given either a const FileEntry * or a llvm::ErrorOr<const FileEntry *>,
* extract out the const FileEntry *.
*/
template <class T>
static const FileEntry *ignore_error(const T obj)
{
return ignore_error_helper(obj, 0, NULL);
}
/* This is identical to std::void_t in C++17.
*/
template< class... >
using void_t = void;
/* A template class with value true if "T" has a getFileRef method.
*/
template <class T, class = void>
struct HasGetFileRef : public std::false_type {};
template <class T>
struct HasGetFileRef<T, ::void_t<decltype(&T::getFileRef)>> :
public std::true_type {};
/* Return the FileEntryRef/FileEntry corresponding to the given file name
* in the given compiler instances, ignoring any error.
*
* If T (= FileManager) has a getFileRef method, then call that and
* return a FileEntryRef.
* Otherwise, call getFile and return a FileEntry (pointer).
*/
template <typename T,
typename std::enable_if<HasGetFileRef<T>::value, bool>::type = true>
static auto getFile(T& obj, const std::string &filename)
-> decltype(*obj.getFileRef(filename))
{
auto file = obj.getFileRef(filename);
assert(file);
return *file;
}
template <typename T,
typename std::enable_if<!HasGetFileRef<T>::value, bool>::type = true>
static const FileEntry *getFile(T& obj, const std::string &filename)
{
const FileEntry *file = ignore_error(obj.getFile(filename));
assert(file);
return file;
assert(false);
}
/* Create an interface generator for the selected language and
@ -567,64 +231,36 @@ static void generate(MyASTConsumer &consumer, SourceManager &SM)
gen->generate();
}
int main(int argc, char *argv[])
/* Parse the current source file, returning true if no error was encountered.
*/
bool Extractor::handle(CompilerInstance *Clang)
{
llvm::cl::ParseCommandLineOptions(argc, argv);
CompilerInstance *Clang = new CompilerInstance();
create_diagnostics(Clang);
DiagnosticsEngine &Diags = Clang->getDiagnostics();
Diags.setSuppressSystemWarnings(true);
TargetInfo *target = create_target_info(Clang, Diags);
Clang->setTarget(target);
set_lang_defaults(Clang);
CompilerInvocation *invocation =
construct_invocation(InputFilename.c_str(), Diags);
if (invocation)
set_invocation(Clang, invocation);
Clang->createFileManager();
Clang->createSourceManager(Clang->getFileManager());
HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts();
LangOptions &LO = Clang->getLangOpts();
PreprocessorOptions &PO = Clang->getPreprocessorOpts();
HSO.ResourceDir = ResourceDir;
for (llvm::cl::list<string>::size_type i = 0; i < Includes.size(); ++i)
add_path(HSO, Includes[i]);
PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))");
PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))");
PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))");
PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))");
PO.addMacroDef("__isl_overload="
"__attribute__((annotate(\"isl_overload\"))) "
"__attribute__((annotate(\"isl_export\")))");
PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))");
PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))");
create_preprocessor(Clang);
Preprocessor &PP = Clang->getPreprocessor();
PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), LO);
auto file = getFile(Clang->getFileManager(), InputFilename);
create_main_file_id(Clang->getSourceManager(), file);
Clang->createASTContext();
MyASTConsumer consumer;
Sema *sema = new Sema(PP, Clang->getASTContext(), consumer);
Diags.getClient()->BeginSourceFile(LO, &PP);
DiagnosticsEngine &Diags = Clang->getDiagnostics();
Diags.getClient()->BeginSourceFile(Clang->getLangOpts(), &PP);
ParseAST(*sema);
Diags.getClient()->EndSourceFile();
generate(consumer, Clang->getSourceManager());
delete sema;
delete Clang;
return !Diags.hasErrorOccurred();
}
int main(int argc, char *argv[])
{
llvm::cl::ParseCommandLineOptions(argc, argv);
Extractor extractor;
bool ok = extractor.invoke(InputFilename.c_str());
llvm::llvm_shutdown();
if (Diags.hasErrorOccurred())
if (!ok)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}

View File

@ -796,7 +796,7 @@ const FunctionProtoType *generator::extract_prototype(QualType type)
*/
int generator::prototype_n_args(QualType type)
{
return extract_prototype(type)->getNumArgs();
return extract_prototype(type)->getNumParams();
}
/* Return the function name suffix for the type of "param".

View File

@ -0,0 +1,425 @@
#include <isl-interface/config.h>
#include <memory>
#ifdef HAVE_LLVM_OPTION_ARG_H
#include <llvm/Option/Arg.h>
#endif
#ifdef HAVE_TARGETPARSER_HOST_H
#include <llvm/TargetParser/Host.h>
#else
#include <llvm/Support/Host.h>
#endif
#include <clang/AST/ASTContext.h>
#include <clang/Basic/Builtins.h>
#include <clang/Basic/DiagnosticOptions.h>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/TargetOptions.h>
#include <clang/Basic/TargetInfo.h>
#include <clang/Basic/Version.h>
#include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h>
#include <clang/Driver/Tool.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/CompilerInvocation.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Lex/HeaderSearch.h>
#include <clang/Lex/PreprocessorOptions.h>
#include <clang/Lex/Preprocessor.h>
namespace clang { namespace driver { class Job; } }
namespace isl {
namespace clang {
using namespace ::clang;
using namespace ::clang::driver;
#ifdef HAVE_LLVM_OPTION_ARG_H
using namespace llvm::opt;
#endif
#ifndef ISL_CLANG_RESOURCE_DIR
#define ISL_CLANG_RESOURCE_DIR \
ISL_CLANG_PREFIX "/lib/clang/" CLANG_VERSION_STRING
#endif
static const char *ResourceDir = ISL_CLANG_RESOURCE_DIR;
static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
{
return new Driver(binary, llvm::sys::getDefaultTargetTriple(), Diags);
}
/* Clang changed its API from 3.5 to 3.6 and once more in 3.7.
* We fix this with a simple overloaded function here.
*/
struct ClangAPI {
static Job *command(Job *J) { return J; }
static Job *command(Job &J) { return &J; }
static Command *command(Command &C) { return &C; }
};
#ifdef CREATE_FROM_ARGS_TAKES_ARRAYREF
/* Call CompilerInvocation::CreateFromArgs with the right arguments.
* In this case, an ArrayRef<const char *>.
*/
static void create_from_args(CompilerInvocation &invocation,
const ArgStringList *args, DiagnosticsEngine &Diags)
{
CompilerInvocation::CreateFromArgs(invocation, *args, Diags);
}
#else
/* Call CompilerInvocation::CreateFromArgs with the right arguments.
* In this case, two "const char *" pointers.
*/
static void create_from_args(CompilerInvocation &invocation,
const ArgStringList *args, DiagnosticsEngine &Diags)
{
CompilerInvocation::CreateFromArgs(invocation, args->data() + 1,
args->data() + args->size(),
Diags);
}
#endif
#ifdef ISL_CLANG_SYSROOT
/* Set sysroot if required.
*
* If ISL_CLANG_SYSROOT is defined, then set it to this value.
*/
static void set_sysroot(ArgStringList &args)
{
args.push_back("-isysroot");
args.push_back(ISL_CLANG_SYSROOT);
}
#else
/* Set sysroot if required.
*
* If ISL_CLANG_SYSROOT is not defined, then it does not need to be set.
*/
static void set_sysroot(ArgStringList &args)
{
}
#endif
/* Create a CompilerInvocation object that stores the command line
* arguments constructed by the driver.
* The arguments are mainly useful for setting up the system include
* paths on newer clangs and on some platforms.
*/
static void construct_invocation(CompilerInstance *Clang,
const char *filename, DiagnosticsEngine &Diags)
{
const char *binary = ISL_CLANG_PREFIX"/bin/clang";
const std::unique_ptr<Driver> driver(construct_driver(binary, Diags));
std::vector<const char *> Argv;
Argv.push_back(binary);
Argv.push_back(filename);
const std::unique_ptr<Compilation> compilation(
driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv)));
JobList &Jobs = compilation->getJobs();
Command *cmd = cast<Command>(ClangAPI::command(*Jobs.begin()));
if (strcmp(cmd->getCreator().getName(), "clang"))
return;
ArgStringList args = cmd->getArguments();
set_sysroot(args);
create_from_args(Clang->getInvocation(), &args, Diags);
}
#ifdef CREATETARGETINFO_TAKES_SHARED_PTR
static TargetInfo *create_target_info(CompilerInstance *Clang,
DiagnosticsEngine &Diags)
{
std::shared_ptr<TargetOptions> TO = Clang->getInvocation().TargetOpts;
TO->Triple = llvm::sys::getDefaultTargetTriple();
return TargetInfo::CreateTargetInfo(Diags, TO);
}
#else
static TargetInfo *create_target_info(CompilerInstance *Clang,
DiagnosticsEngine &Diags)
{
TargetOptions &TO = Clang->getTargetOpts();
TO.Triple = llvm::sys::getDefaultTargetTriple();
return TargetInfo::CreateTargetInfo(Diags, TO);
}
#endif
#ifdef CREATEDIAGNOSTICS_TAKES_VFS
static void create_diagnostics(CompilerInstance *Clang)
{
Clang->createDiagnostics(*llvm::vfs::getRealFileSystem());
}
#else
static void create_diagnostics(CompilerInstance *Clang)
{
Clang->createDiagnostics();
}
#endif
static void create_preprocessor(CompilerInstance *Clang)
{
Clang->createPreprocessor(TU_Complete);
}
/* Add "Path" to the header search options.
*
* Do not take into account sysroot, i.e., set ignoreSysRoot to true.
*/
static void add_path(HeaderSearchOptions &HSO, std::string Path)
{
HSO.AddPath(Path, frontend::Angled, false, true);
}
template <typename T>
static void create_main_file_id(SourceManager &SM, const T &file)
{
SM.setMainFileID(SM.createFileID(file, SourceLocation(),
SrcMgr::C_User));
}
#ifdef SETLANGDEFAULTS_TAKES_5_ARGUMENTS
#include "isl-interface/set_lang_defaults_arg4.h"
static void set_lang_defaults(CompilerInstance *Clang)
{
PreprocessorOptions &PO = Clang->getPreprocessorOpts();
TargetOptions &TO = Clang->getTargetOpts();
llvm::Triple T(TO.Triple);
SETLANGDEFAULTS::setLangDefaults(Clang->getLangOpts(), IK_C, T,
setLangDefaultsArg4(PO),
LangStandard::lang_unspecified);
}
#else
static void set_lang_defaults(CompilerInstance *Clang)
{
CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
LangStandard::lang_unspecified);
}
#endif
/* Helper function for ignore_error that only gets enabled if T
* (which is either const FileEntry * or llvm::ErrorOr<const FileEntry *>)
* has getError method, i.e., if it is llvm::ErrorOr<const FileEntry *>.
*/
template <class T>
static const FileEntry *ignore_error_helper(const T obj, int,
int[1][sizeof(obj.getError())])
{
return *obj;
}
/* Helper function for ignore_error that is always enabled,
* but that only gets selected if the variant above is not enabled,
* i.e., if T is const FileEntry *.
*/
template <class T>
static const FileEntry *ignore_error_helper(const T obj, long, void *)
{
return obj;
}
/* Given either a const FileEntry * or a llvm::ErrorOr<const FileEntry *>,
* extract out the const FileEntry *.
*/
template <class T>
static const FileEntry *ignore_error(const T obj)
{
return ignore_error_helper(obj, 0, NULL);
}
/* Define a template class "CLASS" with value true
* if "EXPR" is valid for its template argument (available as "U" in "EXPR").
*/
#define ISL_VALID_EXPR_FOR_TEMPLATE_ARG(CLASS, EXPR) \
template <typename T> \
struct CLASS { \
private: \
template <typename U> \
static auto test(int) -> decltype(EXPR, std::true_type()); \
\
template <typename> \
static std::false_type test(...); \
\
public: \
using type = decltype(test<T>(0)); \
static constexpr bool value = type::value; \
};
/* A template class with value true if the template argument
* has a getFileRef method.
*/
ISL_VALID_EXPR_FOR_TEMPLATE_ARG(HasGetFileRef,
std::declval<U>().getFileRef(std::declval<const std::string &>()))
/* Return a wrapper around the FileEntryRef/FileEntry
* corresponding to the given file name. The wrapper evaluates
* to false if an error occurs.
*
* If T (= FileManager) has a getFileRef method, then call that and
* return an llvm::Expected<clang::FileEntryRef>.
* Otherwise, call getFile and return a FileEntry (pointer) embedded
* in an llvm::ErrorOr.
*/
template <typename T,
typename std::enable_if<HasGetFileRef<T>::value, bool>::type = true>
static auto getFile(T& obj, const std::string &filename)
-> decltype(obj.getFileRef(filename))
{
return obj.getFileRef(filename);
}
template <typename T,
typename std::enable_if<!HasGetFileRef<T>::value, bool>::type = true>
static llvm::ErrorOr<const FileEntry *> getFile(T& obj,
const std::string &filename)
{
const FileEntry *file = ignore_error(obj.getFile(filename));
if (!file)
return std::error_code();
return file;
}
/* A template class with value true if the constructor of the template argument
* takes a reference to a DiagnosticOptions object.
*/
ISL_VALID_EXPR_FOR_TEMPLATE_ARG(TakesDiagnosticOptionsRef,
new U(llvm::errs(), std::declval<DiagnosticOptions &>()))
/* Return the type of the DiagnosticOptions argument of the constructor of "T".
*
* If TakesDiagnosticOptionsRef holds, then this is a reference
* to a DiagnosticOptions object.
* Otherwise, it is a pointer to such an object.
*/
template <typename T,
typename std::enable_if<TakesDiagnosticOptionsRef<T>::value,
bool>::type = true>
static DiagnosticOptions &diag_opts_type();
template <typename T,
typename std::enable_if<!TakesDiagnosticOptionsRef<T>::value,
bool>::type = true>
static DiagnosticOptions *diag_opts_type();
/* A helper class handling the invocation of clang on a file and
* allowing a derived class to perform the actual parsing
* in an overridden handle() method.
* Other virtual methods allow different kinds of configuration.
*/
struct Wrap {
/* The type of the DiagnosticOptions argument
* of the TextDiagnosticPrinter constructor.
*/
using DiagOptsType = decltype(diag_opts_type<TextDiagnosticPrinter>());
/* A local DiagnosticOptions object that is used
* if TextDiagnosticPrinter takes a reference
* to a DiagnosticOptions object.
*/
DiagnosticOptions DiagOpts;
/* Return a valid DiagnosticOptions argument
* for the constructor of "T".
* If "T" takes a reference, then
* this is a reference to the DiagOpts field.
* Otherwise, it is a pointer to a new object.
*/
template <typename T,
typename std::enable_if<TakesDiagnosticOptionsRef<T>::value,
bool>::type = true>
DiagnosticOptions &getDiagOpts() {
return DiagOpts;
}
template <typename T,
typename std::enable_if<!TakesDiagnosticOptionsRef<T>::value,
bool>::type = true>
DiagnosticOptions *getDiagOpts() {
return new DiagnosticOptions();
}
/* Return a valid DiagnosticOptions argument for
* the TextDiagnosticPrinter constructor.
* If TextDiagnosticPrinter takes a reference, then
* this is a reference to the DiagOpts field.
* Otherwise, it is a pointer to a new object.
*/
DiagOptsType getDiagnosticOptions() {
return getDiagOpts<TextDiagnosticPrinter>();
}
/* Construct a TextDiagnosticPrinter. */
virtual TextDiagnosticPrinter *construct_printer() = 0;
/* Suppress any errors, if needed. */
virtual void suppress_errors(DiagnosticsEngine &Diags) = 0;
/* Add required search paths to "HSO". */
virtual void add_paths(HeaderSearchOptions &HSO) = 0;
/* Add required macro definitions to "PO". */
virtual void add_macros(PreprocessorOptions &PO) = 0;
/* Handle an error opening the file. */
virtual void handle_error() = 0;
/* Parse the file, returning true if no error was encountered. */
virtual bool handle(CompilerInstance *Clang) = 0;
/* Invoke clang on "filename", passing control to the handle() method
* for parsing.
*/
bool invoke(const char *filename) {
CompilerInstance *Clang = new CompilerInstance();
create_diagnostics(Clang);
DiagnosticsEngine &Diags = Clang->getDiagnostics();
Diags.setSuppressSystemWarnings(true);
suppress_errors(Diags);
TargetInfo *target = create_target_info(Clang, Diags);
Clang->setTarget(target);
set_lang_defaults(Clang);
construct_invocation(Clang, filename, Diags);
Diags.setClient(construct_printer());
Clang->createFileManager();
Clang->createSourceManager(Clang->getFileManager());
HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts();
LangOptions &LO = Clang->getLangOpts();
PreprocessorOptions &PO = Clang->getPreprocessorOpts();
HSO.ResourceDir = ResourceDir;
HSO.AddPath(ISL_CLANG_RESOURCE_DIR "/include",
clang::frontend::System, false, false);
add_paths(HSO);
add_macros(PO);
create_preprocessor(Clang);
Preprocessor &PP = Clang->getPreprocessor();
PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
LO);
auto file = getFile(Clang->getFileManager(), filename);
if (!file) {
handle_error();
delete Clang;
return false;
}
create_main_file_id(Clang->getSourceManager(), *file);
Clang->createASTContext();
bool ok = handle(Clang);
delete Clang;
return ok;
}
};
}
}

View File

@ -0,0 +1,16 @@
#ifndef ISL_CLANG_WRAP_CONFIG_H
#define ISL_CLANG_WRAP_CONFIG_H
#undef CREATE_FROM_ARGS_TAKES_ARRAYREF
#undef CREATEDIAGNOSTICS_TAKES_VFS
#undef CREATETARGETINFO_TAKES_SHARED_PTR
#undef HAVE_LLVM_OPTION_ARG_H
#undef HAVE_TARGETPARSER_HOST_H
#undef IK_C
#undef ISL_CLANG_PREFIX
#undef ISL_CLANG_RESOURCE_DIR
#undef ISL_CLANG_SYSROOT
#undef SETLANGDEFAULTS
#undef SETLANGDEFAULTS_TAKES_5_ARGUMENTS
#endif

View File

@ -12850,6 +12850,22 @@ class fixed_box(object):
return obj
def get_offset(arg0):
return arg0.offset()
def plain_is_equal(arg0, arg1):
try:
if not arg0.__class__ is fixed_box:
arg0 = fixed_box(arg0)
except:
raise
try:
if not arg1.__class__ is fixed_box:
arg1 = fixed_box(arg1)
except:
raise
ctx = arg0.ctx
res = isl.isl_fixed_box_plain_is_equal(arg0.ptr, arg1.ptr)
if res < 0:
raise Error
return bool(res)
def size(arg0):
try:
if not arg0.__class__ is fixed_box:
@ -12880,6 +12896,7 @@ isl.isl_fixed_box_read_from_str.argtypes = [Context, c_char_p]
isl.isl_fixed_box_is_valid.argtypes = [c_void_p]
isl.isl_fixed_box_get_offset.restype = c_void_p
isl.isl_fixed_box_get_offset.argtypes = [c_void_p]
isl.isl_fixed_box_plain_is_equal.argtypes = [c_void_p, c_void_p]
isl.isl_fixed_box_get_size.restype = c_void_p
isl.isl_fixed_box_get_size.argtypes = [c_void_p]
isl.isl_fixed_box_get_space.restype = c_void_p
@ -13889,6 +13906,22 @@ class multi_val(object):
if res < 0:
raise Error
return bool(res)
def is_equal(arg0, arg1):
try:
if not arg0.__class__ is multi_val:
arg0 = multi_val(arg0)
except:
raise
try:
if not arg1.__class__ is multi_val:
arg1 = multi_val(arg1)
except:
raise
ctx = arg0.ctx
res = isl.isl_multi_val_is_equal(arg0.ptr, arg1.ptr)
if res < 0:
raise Error
return bool(res)
def list(arg0):
try:
if not arg0.__class__ is multi_val:
@ -14164,6 +14197,7 @@ isl.isl_multi_val_flat_range_product.restype = c_void_p
isl.isl_multi_val_flat_range_product.argtypes = [c_void_p, c_void_p]
isl.isl_multi_val_has_range_tuple_id.argtypes = [c_void_p]
isl.isl_multi_val_involves_nan.argtypes = [c_void_p]
isl.isl_multi_val_is_equal.argtypes = [c_void_p, c_void_p]
isl.isl_multi_val_get_list.restype = c_void_p
isl.isl_multi_val_get_list.argtypes = [c_void_p]
isl.isl_multi_val_max.restype = c_void_p

View File

@ -1936,7 +1936,7 @@ void plain_cpp_generator::impl_printer::print_callback_body(int indent,
callback = extract_prototype(ptype);
rtype = callback->getReturnType();
num_params = callback->getNumArgs();
num_params = callback->getNumParams();
last_idx = ::to_string(num_params - 1);

View File

@ -215,7 +215,7 @@ void python_generator::print_callback(ParmVarDecl *param, int arg)
QualType type = param->getOriginalType();
const FunctionProtoType *fn = extract_prototype(type);
QualType return_type = fn->getReturnType();
unsigned n_arg = fn->getNumArgs();
unsigned n_arg = fn->getNumParams();
printf(" exc_info = [None]\n");
printf(" fn = CFUNCTYPE(");
@ -224,7 +224,7 @@ void python_generator::print_callback(ParmVarDecl *param, int arg)
else
printf("c_void_p");
for (unsigned i = 0; i < n_arg - 1; ++i) {
if (!is_isl_type(fn->getArgType(i)))
if (!is_isl_type(fn->getParamType(i)))
die("Argument has non-isl type");
printf(", c_void_p");
}
@ -238,11 +238,11 @@ void python_generator::print_callback(ParmVarDecl *param, int arg)
printf("):\n");
for (unsigned i = 0; i < n_arg - 1; ++i) {
string arg_type;
arg_type = type2python(extract_type(fn->getArgType(i)));
arg_type = type2python(extract_type(fn->getParamType(i)));
printf(" cb_arg%d = %s(ctx=arg0.ctx, ptr=",
i, arg_type.c_str());
if (!callback_takes_argument(param, i))
print_copy(fn->getArgType(i));
print_copy(fn->getParamType(i));
printf("(cb_arg%d))\n", i);
}
printf(" try:\n");

View File

@ -1647,7 +1647,7 @@ static int total_params(const Method &method)
auto callback_type = callback->getType();
auto proto = generator::extract_prototype(callback_type);
n += proto->getNumArgs() - 1;
n += proto->getNumParams() - 1;
n -= 1;
}
@ -1729,10 +1729,10 @@ static void print_callback_args(std::ostream &os,
const std::function<void(const std::string &type,
const std::string &name)> &print_arg)
{
auto n_arg = callback->getNumArgs() - 1;
auto n_arg = callback->getNumParams() - 1;
Method::print_arg_list(os, 0, n_arg, [&] (int i) {
auto type = callback->getArgType(i);
auto type = callback->getParamType(i);
auto name = "arg" + std::to_string(i);
auto cpptype = type_printer.param(shift + i, type);
@ -2709,7 +2709,7 @@ const std::string callback_name(const Method &method)
auto type = method.callbacks.at(0)->getType();
auto callback = cpp_generator::extract_prototype(type);
auto arg_type = plain_type(callback->getArgType(0));
auto arg_type = plain_type(callback->getParamType(0));
return generator::drop_suffix(method.name, "_" + arg_type);
}

View File

@ -974,19 +974,25 @@ static int parse_str_option(struct isl_arg *decl, char **arg,
return 0;
}
static int isl_arg_str_list_append(struct isl_arg *decl, void *opt,
int isl_arg_str_list_append(int *n, const char ***list, const char *s)
{
const char **new_list;
new_list = realloc(*list, (*n + 1) * sizeof(char *));
if (!new_list)
return -1;
*list = new_list;
new_list[*n] = strdup(s);
return isl_stat_non_null(new_list[(*n)++]);
}
static int arg_str_list_append(struct isl_arg *decl, void *opt,
const char *s)
{
int *n = (int *)(((char *) opt) + decl->u.str_list.offset_n);
char **list = *(char ***)(((char *) opt) + decl->offset);
const char ***list = (const char ***)(((char *) opt) + decl->offset);
list = realloc(list, (*n + 1) * sizeof(char *));
if (!list)
return -1;
*(char ***)(((char *) opt) + decl->offset) = list;
list[*n] = strdup(s);
(*n)++;
return 0;
return isl_arg_str_list_append(n, list, s);
}
static int parse_str_list_option(struct isl_arg *decl, char **arg,
@ -1000,12 +1006,12 @@ static int parse_str_list_option(struct isl_arg *decl, char **arg,
return 0;
if (has_argument) {
isl_arg_str_list_append(decl, opt, s);
arg_str_list_append(decl, opt, s);
return 1;
}
if (arg[1]) {
isl_arg_str_list_append(decl, opt, arg[1]);
arg_str_list_append(decl, opt, arg[1]);
return 2;
}

View File

@ -207,27 +207,65 @@ isl_bool isl_fixed_box_is_valid(__isl_keep isl_fixed_box *box)
/* Return the offsets of the box "box".
*/
__isl_give isl_multi_aff *isl_fixed_box_get_offset(
static __isl_keep isl_multi_aff *isl_fixed_box_peek_offset(
__isl_keep isl_fixed_box *box)
{
if (!box)
return NULL;
return isl_multi_aff_copy(box->offset);
return box->offset;
}
/* Return a copy of the offsets of the box "box".
*/
__isl_give isl_multi_aff *isl_fixed_box_get_offset(
__isl_keep isl_fixed_box *box)
{
return isl_multi_aff_copy(isl_fixed_box_peek_offset(box));
}
/* Return the sizes of the box "box".
*/
__isl_give isl_multi_val *isl_fixed_box_get_size(__isl_keep isl_fixed_box *box)
static __isl_keep isl_multi_val *isl_fixed_box_peek_size(
__isl_keep isl_fixed_box *box)
{
if (!box)
return NULL;
return isl_multi_val_copy(box->size);
return box->size;
}
/* Return a copy of the sizes of the box "box".
*/
__isl_give isl_multi_val *isl_fixed_box_get_size(__isl_keep isl_fixed_box *box)
{
return isl_multi_val_copy(isl_fixed_box_peek_size(box));
}
/* Is "box1" obviously equal to "box2"?
*
* That is, does it have the same size and obviously the same offset?
*/
isl_bool isl_fixed_box_plain_is_equal(__isl_keep isl_fixed_box *box1,
__isl_keep isl_fixed_box *box2)
{
isl_multi_aff *offset1, *offset2;
isl_multi_val *size1, *size2;
isl_bool equal;
size1 = isl_fixed_box_peek_size(box1);
size2 = isl_fixed_box_peek_size(box2);
equal = isl_multi_val_is_equal(size1, size2);
if (equal < 0 || !equal)
return equal;
offset1 = isl_fixed_box_peek_offset(box1);
offset2 = isl_fixed_box_peek_offset(box2);
return isl_multi_aff_plain_is_equal(offset1, offset2);
}
/* Data used in set_dim_extent and compute_size_in_direction.
*
* "bset" is a wrapped copy of the basic map that has the selected
* output dimension as range.
* output dimension as range, without any contraction.
* "pos" is the position of the variable representing the output dimension,
* i.e., the variable for which the size should be computed. This variable
* is also the last variable in "bset".
@ -235,34 +273,167 @@ __isl_give isl_multi_val *isl_fixed_box_get_size(__isl_keep isl_fixed_box *box)
* (infinity if no offset was found so far).
* "offset" is the offset corresponding to the best size
* (NULL if no offset was found so far).
*
* If "expand" is not NULL, then it maps a contracted version of "bset"
* to the original "bset", while "domain_map" maps the space of "bset"
* to the domain of the wrapped map.
*/
struct isl_size_info {
isl_basic_set *bset;
isl_size pos;
isl_val *size;
isl_aff *offset;
isl_multi_aff *expand;
isl_multi_aff *domain_map;
};
/* Detect any stride in the single output dimension of "map" and
* set the fields of "info" used in exploiting this stride.
* If no (non-trivial) stride can be found, then set those fields to NULL.
*
* If there is a non-trivial stride, then the single output dimension i
* is of the form
*
* i = offset + stride * i'
*
* Construct a function that maps i' to i.
* Note that the offset may depend on the domain of the map,
* so it needs to be of the form
*
* [D -> [i']] -> [i]
*
* In fact, it is more convenient for the function to be of the form
*
* [D -> [i']] -> [D -> [i]]
*
* First construct helper functions
*
* [D -> [i]] -> D
* [D -> [i]] -> [i]
*
* Plug in [D -> [i]] -> D into the offset (defined on D) to obtain
* the offset defined on [D -> [i]] and add stride times [D -> [i]] -> [i].
* This produces the function
*
* [D -> [i']] = [offset + stride i']
*
* Combine it with [D -> [i]] -> D again to obtain the desired result.
*/
static __isl_give isl_map *isl_size_info_detect_stride(
struct isl_size_info *info, __isl_take isl_map *map)
{
isl_stride_info *si;
isl_val *stride;
isl_aff *offset;
isl_bool is_one;
isl_multi_aff *domain_map, *id;
isl_multi_aff *expand;
info->expand = NULL;
info->domain_map = NULL;
si = isl_map_get_range_stride_info(map, 0);
stride = isl_stride_info_get_stride(si);
is_one = isl_val_is_one(stride);
if (is_one < 0 || is_one) {
isl_val_free(stride);
isl_stride_info_free(si);
return is_one < 0 ? isl_map_free(map) : map;
}
offset = isl_stride_info_get_offset(si);
isl_stride_info_free(si);
domain_map = isl_space_domain_map_multi_aff(isl_aff_get_space(offset));
id = isl_space_range_map_multi_aff(isl_aff_get_space(offset));
offset = isl_aff_pullback_multi_aff(offset,
isl_multi_aff_copy(domain_map));
expand = isl_multi_aff_scale_val(id, stride);
expand = isl_multi_aff_add(expand, isl_multi_aff_from_aff(offset));
expand = isl_multi_aff_range_product(isl_multi_aff_copy(domain_map),
expand);
info->expand = expand;
info->domain_map = domain_map;
if (!expand || !domain_map)
return isl_map_free(map);
return map;
}
/* If any stride was detected in the single output dimension
* in the wrapped map in "bset" (i.e., if info->expand is set),
* then plug in the expansion to obtain a description in terms
* of an output dimension without stride.
* Otherwise, return the original "bset".
*/
static __isl_give isl_basic_set *isl_size_info_contract(
struct isl_size_info *info, __isl_take isl_basic_set *bset)
{
if (!info->expand)
return bset;
bset = isl_basic_set_preimage_multi_aff(bset,
isl_multi_aff_copy(info->expand));
return bset;
}
/* Given an affine function "aff" that maps the space of "bset"
* to a value in the (possibly) contracted space,
* expand it back to the original space.
* The value of "aff" only depends on the domain of wrapped relation
* inside "bset".
*
* If info->expand is not set, then no contraction was applied and
* "aff" is returned.
*
* Otherwise, combine "aff" of the form [D -> [*]] -> [v'(D)]
* with [D -> [*]] -> D to obtain [D -> [*]] -> [D -> [v'(D)]].
* Apply the expansion [D -> [i']] = [D -> [offset + stride * i']]
* to obtain [D -> [*]] -> [D -> [offset + stride * v'(D)]] and
* extract out [D -> [*]] -> [offset + stride * v'(D)].
*/
static __isl_give isl_aff *isl_size_info_expand(
struct isl_size_info *info, __isl_take isl_aff *aff)
{
isl_multi_aff *ma;
if (!info->expand)
return aff;
ma = isl_multi_aff_from_aff(aff);
ma = isl_multi_aff_range_product(isl_multi_aff_copy(info->domain_map),
ma);
ma = isl_multi_aff_pullback_multi_aff(isl_multi_aff_copy(info->expand),
ma);
ma = isl_multi_aff_range_factor_range(ma);
aff = isl_multi_aff_get_at(ma, 0);
isl_multi_aff_free(ma);
return aff;
}
/* Free all memory allocated for "info".
*/
static void isl_size_info_clear(struct isl_size_info *info)
{
isl_val_free(info->size);
isl_aff_free(info->offset);
isl_basic_set_free(info->bset);
isl_multi_aff_free(info->expand);
isl_multi_aff_free(info->domain_map);
}
/* Is "c" a suitable bound on dimension "pos" for use as a lower bound
* of a fixed-size range.
* In particular, it needs to be a lower bound on "pos".
* In order for the final offset not to be too complicated,
* the constraint itself should also not involve any integer divisions.
*/
static isl_bool is_suitable_bound(__isl_keep isl_constraint *c, unsigned pos)
{
isl_size n_div;
isl_bool is_bound, any_divs;
is_bound = isl_constraint_is_lower_bound(c, isl_dim_set, pos);
if (is_bound < 0 || !is_bound)
return is_bound;
n_div = isl_constraint_dim(c, isl_dim_div);
if (n_div < 0)
return isl_bool_error;
any_divs = isl_constraint_involves_dims(c, isl_dim_div, 0, n_div);
return isl_bool_not(any_divs);
return isl_constraint_is_lower_bound(c, isl_dim_set, pos);
}
/* Given a constraint from the basic set describing the bounds on
@ -271,6 +442,10 @@ static isl_bool is_suitable_bound(__isl_keep isl_constraint *c, unsigned pos)
* upper bound. If so, and if this bound is smaller than any bound
* derived from earlier constraints, set the size to this bound on
* the expression and the lower bound to ceil(b(x)/m).
*
* If any contraction was applied, then the lower bound ceil(b(x)/m)
* is defined in the contracted space, so it needs to be expanded
* first before applying it to the original space.
*/
static isl_stat compute_size_in_direction(__isl_take isl_constraint *c,
void *user)
@ -289,6 +464,7 @@ static isl_stat compute_size_in_direction(__isl_take isl_constraint *c,
aff = isl_constraint_get_bound(c, isl_dim_set, info->pos);
aff = isl_aff_ceil(aff);
aff = isl_size_info_expand(info, aff);
lb = isl_aff_copy(aff);
@ -326,10 +502,17 @@ static isl_stat compute_size_in_direction(__isl_take isl_constraint *c,
* then invalidate the box. Otherwise, set the offset and size
* in the given direction by those that correspond to the smallest size.
*
* If the output dimension is strided, then scale it down before
* looking for lower bounds. The size computation is however performed
* in the original space.
*
* Note that while evaluating the size corresponding to a lower bound,
* an affine expression is constructed from the lower bound.
* This lower bound may therefore not have any unknown local variables.
* Eliminate any unknown local variables up front.
* Furthermore, the lower bound can clearly not involve
* (any local variables that involve) the output dimension itself,
* so any such local variables are eliminated as well.
* No such restriction needs to be imposed on the set over which
* the size is computed.
*/
@ -347,14 +530,18 @@ static __isl_give isl_fixed_box *set_dim_extent(__isl_take isl_fixed_box *box,
ctx = isl_map_get_ctx(map);
map = isl_map_copy(map);
map = isl_map_project_onto(map, isl_dim_out, pos, 1);
map = isl_size_info_detect_stride(&info, map);
info.size = isl_val_infty(ctx);
info.offset = NULL;
info.pos = isl_map_dim(map, isl_dim_in);
info.bset = isl_basic_map_wrap(isl_map_simple_hull(map));
bset = isl_basic_set_copy(info.bset);
bset = isl_size_info_contract(&info, bset);
bset = isl_basic_set_remove_unknown_divs(bset);
if (info.pos < 0)
bset = isl_basic_set_free(bset);
bset = isl_basic_set_remove_divs_involving_dims(bset, isl_dim_set,
info.pos, 1);
if (isl_basic_set_foreach_constraint(bset,
&compute_size_in_direction, &info) < 0)
box = isl_fixed_box_free(box);
@ -367,9 +554,7 @@ static __isl_give isl_fixed_box *set_dim_extent(__isl_take isl_fixed_box *box,
info.offset, info.size);
else
box = isl_fixed_box_invalidate(box);
isl_val_free(info.size);
isl_aff_free(info.offset);
isl_basic_set_free(info.bset);
isl_size_info_clear(&info);
return box;
}

View File

@ -31,7 +31,7 @@ isl_stat isl_stat_non_error_bool(isl_bool b)
* That is, return isl_stat_ok if "obj" is non_NULL and
* isl_stat_error otherwise.
*/
isl_stat isl_stat_non_null(void *obj)
isl_stat isl_stat_non_null(const void *obj)
{
if (obj != NULL)
return isl_stat_ok;

View File

@ -71,6 +71,17 @@ static void swap_inequality(__isl_keep isl_basic_map *bmap, int a, int b)
}
}
/* Scale down the inequality constraint "ineq" of length "len"
* by a factor of "f".
* All the coefficients, except the constant term,
* are assumed to be multiples of "f".
*/
static void scale_down_inequality(isl_int *ineq, isl_int f, unsigned len)
{
isl_int_fdiv_q(ineq[0], ineq[0], f);
isl_seq_scale_down(ineq + 1, ineq + 1, f, len);
}
/* Scale down the inequality constraint "ineq" of length "len"
* by a factor of "f".
* All the coefficients, except the constant term,
@ -81,7 +92,7 @@ static void swap_inequality(__isl_keep isl_basic_map *bmap, int a, int b)
* If scaling is performed then take into account that the constraint
* is modified (not simply based on an equality constraint).
*/
static __isl_give isl_basic_map *scale_down_inequality(
static __isl_give isl_basic_map *scale_down_bmap_inequality(
__isl_take isl_basic_map *bmap, int ineq, isl_int f, unsigned len)
{
if (!bmap)
@ -90,8 +101,7 @@ static __isl_give isl_basic_map *scale_down_inequality(
if (isl_int_is_zero(f) || isl_int_is_one(f))
return bmap;
isl_int_fdiv_q(bmap->ineq[ineq][0], bmap->ineq[ineq][0], f);
isl_seq_scale_down(bmap->ineq[ineq] + 1, bmap->ineq[ineq] + 1, f, len);
scale_down_inequality(bmap->ineq[ineq], f, len);
bmap = isl_basic_map_modify_inequality(bmap, 0);
@ -144,7 +154,7 @@ __isl_give isl_basic_map *isl_basic_map_normalize_constraints(
}
if (ISL_F_ISSET(bmap, ISL_BASIC_MAP_RATIONAL))
isl_int_gcd(gcd, gcd, bmap->ineq[i][0]);
bmap = scale_down_inequality(bmap, i, gcd, total);
bmap = scale_down_bmap_inequality(bmap, i, gcd, total);
if (!bmap)
goto error;
}
@ -399,7 +409,7 @@ static __isl_give isl_basic_map *eliminate_var_using_equality(
mark_progress(progress);
isl_seq_elim(bmap->ineq[k], eq, 1+pos, 1+total, NULL);
isl_seq_gcd(bmap->ineq[k], 1 + total, &ctx->normalize_gcd);
bmap = scale_down_inequality(bmap, k, ctx->normalize_gcd,
bmap = scale_down_bmap_inequality(bmap, k, ctx->normalize_gcd,
total);
bmap = isl_basic_map_modify_inequality(bmap, equivalent);
if (!bmap)
@ -886,6 +896,47 @@ static isl_bool constraint_index_is_redundant(struct isl_constraint_index *ci,
return isl_int_ge(ineq[0], (*ci->index[h])[0]);
}
/* Look for pairs of inequality constraints in "bmap"
* that are opposite to each other apart from the constant term.
* "ci" contains a hash table of the inequality constraints of "bmap".
* Return an array of size equal to the number of inequality constraints
* with as entries either
* - zero, if the constraint has no opposite, or
* - 1 + the position of the opposite constraint.
*/
static int *detect_opposites(struct isl_constraint_index *ci,
__isl_keep isl_basic_map *bmap)
{
isl_size n_ineq;
int k, l, h;
isl_ctx *ctx;
int *opposite;
n_ineq = isl_basic_map_n_inequality(bmap);
if (n_ineq < 0)
return NULL;
ctx = isl_basic_map_get_ctx(bmap);
opposite = isl_calloc_array(ctx, int, n_ineq);
if (!opposite)
return NULL;
for (k = 0; k < n_ineq - 1; ++k) {
if (opposite[k])
continue;
isl_seq_neg(bmap->ineq[k] + 1, bmap->ineq[k] + 1, ci->total);
h = hash_index(ci, bmap, k);
isl_seq_neg(bmap->ineq[k] + 1, bmap->ineq[k] + 1, ci->total);
if (!ci->index[h])
continue;
l = ci->index[h] - &bmap->ineq[0];
opposite[k] = 1 + l;
opposite[l] = 1 + k;
}
return opposite;
}
/* If we can eliminate more than one div, then we need to make
* sure we do it from last div to first div, in order not to
* change the position of the other divs that still need to
@ -1263,12 +1314,12 @@ error:
}
static __isl_give isl_basic_map *set_div_from_lower_bound(
__isl_take isl_basic_map *bmap, int div, int ineq)
__isl_take isl_basic_map *bmap, int div, isl_int *ineq)
{
unsigned total = isl_basic_map_offset(bmap, isl_dim_div);
isl_seq_neg(bmap->div[div] + 1, bmap->ineq[ineq], total + bmap->n_div);
isl_int_set(bmap->div[div][0], bmap->ineq[ineq][total + div]);
isl_seq_neg(bmap->div[div] + 1, ineq, total + bmap->n_div);
isl_int_set(bmap->div[div][0], ineq[total + div]);
isl_int_add(bmap->div[div][1], bmap->div[div][1], bmap->div[div][0]);
isl_int_sub_ui(bmap->div[div][1], bmap->div[div][1], 1);
isl_int_set_si(bmap->div[div][1 + total + div], 0);
@ -1283,36 +1334,43 @@ static __isl_give isl_basic_map *set_div_from_lower_bound(
* terms of the unknown div.
*/
static isl_bool ok_to_set_div_from_bound(__isl_keep isl_basic_map *bmap,
int div, int ineq)
int div, isl_int *ineq)
{
int j;
unsigned total = isl_basic_map_offset(bmap, isl_dim_div);
isl_size v_div = isl_basic_map_var_offset(bmap, isl_dim_div);
isl_size n_div = isl_basic_map_dim(bmap, isl_dim_div);
if (v_div < 0 || n_div < 0)
return isl_bool_error;
/* Not defined in terms of unknown divs */
for (j = 0; j < bmap->n_div; ++j) {
for (j = 0; j < n_div; ++j) {
isl_bool unknown;
if (div == j)
continue;
if (isl_int_is_zero(bmap->ineq[ineq][total + j]))
if (isl_int_is_zero(ineq[1 + v_div + j]))
continue;
if (isl_int_is_zero(bmap->div[j][0]))
return isl_bool_false;
unknown = isl_basic_map_div_is_marked_unknown(bmap, j);
if (unknown < 0 || unknown)
return isl_bool_not(unknown);
}
/* No other div defined in terms of this one => avoid loops */
for (j = 0; j < bmap->n_div; ++j) {
for (j = 0; j < n_div; ++j) {
if (div == j)
continue;
if (isl_int_is_zero(bmap->div[j][0]))
continue;
if (!isl_int_is_zero(bmap->div[j][1 + total + div]))
if (!isl_int_is_zero(bmap->div[j][1 + 1 + v_div + div]))
return isl_bool_false;
}
return isl_bool_true;
}
/* Would an expression for div "div" based on inequality "ineq" of "bmap"
* be a better expression than the current one?
/* Would an expression for div "div" based on inequality "ineq"
* be a better expression than the current one in "bmap"?
*
* If we do not have any expression yet, then any expression would be better.
* Otherwise we check if the last variable involved in the inequality
@ -1320,28 +1378,52 @@ static isl_bool ok_to_set_div_from_bound(__isl_keep isl_basic_map *bmap,
* than the last variable involved in the current div expression.
*/
static isl_bool better_div_constraint(__isl_keep isl_basic_map *bmap,
int div, int ineq)
int div, isl_int *ineq)
{
unsigned total = isl_basic_map_offset(bmap, isl_dim_div);
isl_size n_div = isl_basic_map_dim(bmap, isl_dim_div);
int last_div;
int last_ineq;
isl_bool unknown;
if (n_div < 0)
return isl_bool_error;
if (isl_int_is_zero(bmap->div[div][0]))
return isl_bool_true;
unknown = isl_basic_map_div_is_marked_unknown(bmap, div);
if (unknown < 0 || unknown)
return unknown;
if (isl_seq_any_non_zero(bmap->ineq[ineq] + total + div + 1,
n_div - (div + 1)))
if (isl_seq_any_non_zero(ineq + total + div + 1, n_div - (div + 1)))
return isl_bool_false;
last_ineq = isl_seq_last_non_zero(bmap->ineq[ineq], total + div);
last_ineq = isl_seq_last_non_zero(ineq, total + div);
last_div = isl_seq_last_non_zero(bmap->div[div] + 1, total + n_div);
return last_ineq < last_div;
}
/* Given a lower bound "ineq" on local variable "div" of "bmap"
* that could in theory be used to define an integer division expression,
* do so if it is better than the current expression (if any) and
* if there is no risk of introducing circular definitions.
* Set *progress if anything is changed.
*/
static __isl_give isl_basic_map *set_div_from_lower_bound_if_better(
__isl_take isl_basic_map *bmap, int div, isl_int *ineq, int *progress)
{
isl_bool set_div;
set_div = better_div_constraint(bmap, div, ineq);
if (set_div >= 0 && set_div)
set_div = ok_to_set_div_from_bound(bmap, div, ineq);
if (set_div < 0)
return isl_basic_map_free(bmap);
if (!set_div)
return bmap;
bmap = set_div_from_lower_bound(bmap, div, ineq);
mark_progress(progress);
return bmap;
}
/* Is the sequence of "len" coefficients "ineq" equal to "res"
* plus some non-trivial coefficients that are all a multiple of some number
* greater than "sum"?
@ -1691,7 +1773,7 @@ static __isl_give isl_basic_map *check_for_residues(
continue;
isl_seq_sub(bmap->ineq[i], bmap->ineq[c], 1 + total);
bmap = scale_down_inequality(bmap, i, ctx->normalize_gcd,
bmap = scale_down_bmap_inequality(bmap, i, ctx->normalize_gcd,
total);
if (!bmap)
return NULL;
@ -1701,6 +1783,260 @@ static __isl_give isl_basic_map *check_for_residues(
return bmap;
}
/* Given constraints of the form
*
* -n f + g + m n e + c1 >= 0 (l)
* g + c3 >= 0 (i)
* -g + c4 >= 0 (j)
*
* with e the local variable at position "div",
* does the following condition hold?
*
* c3 + c4 + (c1 - c3) % n < m n
*
* "v_div" is the position of the first local variable.
*/
static int is_residue_div_pair(__isl_take isl_basic_map *bmap,
int l, int div, unsigned v_div, int i, int j, isl_int n)
{
isl_int tmp;
int ok;
isl_int_init(tmp);
isl_int_sub(tmp, bmap->ineq[l][0], bmap->ineq[i][0]);
isl_int_fdiv_r(tmp, tmp, n);
isl_int_add(tmp, tmp, bmap->ineq[i][0]);
isl_int_add(tmp, tmp, bmap->ineq[j][0]);
ok = isl_int_lt(tmp, bmap->ineq[l][1 + v_div + div]);
isl_int_clear(tmp);
return ok;
}
/* Given a lower bound constraint at position "l" of "bmap"
* on local variable "div" such that the sum of the constant terms
* of this constraint and the corresponding upper bound is equal to "sum",
* as well as a separate pair of opposite constraints "i" and "j"
* such that the sum of their constant terms is smaller than
* the coefficient of "div" in "l",
* check if this pair can be used to derive a reduced expression
* for the local variable.
* "total" is the total number of variables.
* "v_div" is the position of the first local variable.
* Set *progress if anything is changed.
*
* In particular, let l be the constraint
*
* -n f + g + m n e + c1 >= 0
*
* The opposite constraint is
*
* n f - g - m n e + c2 >= 0
*
* with c1 + c2 equal to "sum".
*
* The constraints i and j are of the form
*
* h + c3 >= 0
* -h + c4 >= 0
*
* with c3 + c4 < m n.
* First check that h is equal to g for some n greater than "sum".
* The constraints i and j are then of the form
*
* g + c3 >= 0
* -g + c4 >= 0
*
* From constraint "l" and its opposite,
*
* g + m n e - c2 <= n f <= g + m n e + c1
*
* combined with the fact that c1 + c2 < n, the following expression
* can be obtained:
*
* f = floor((g + m n e + c1)/n) = floor((g + c1)/n) + m e
*
* Replacing c1 with
*
* c1 = c3 + (c1 - c3) = c3 + n floor((c1 - c3)/n) + (c1 - c3) % n
*
* results in
*
* f = floor((g + c3 + (c1 - c3) % n)/n) + floor((c1 - c3)/n) + m e
*
* From the constraints i and j, together with c3 + c4 < m n,
*
* 0 <= g + c3 < m n
*
* Since (c1 - c3) % n is non-negative,
*
* 0 <= g + c3 + (c1 - c3) % n
*
* holds as well. However,
*
* g + c3 + (c1 - c3) % n < m n
*
* may not necessarily hold. It is however the case if
*
* c3 + c4 + (c1 - c3) % n < m n
*
* holds, which is checked in is_residue_div_pair.
*
* Given
*
* 0 <= g + c3 + (c1 - c3) % n < m n
*
* also
*
* 0 <= floor((g + c3 + (c1 - c3) % n) / n) < m
*
* holds.
*
* So,
*
* f = floor((g + c3 + (c1 - c3) % n)/n) + floor((c1 - c3)/n) + m e
*
* and
*
* 0 <= floor((g + c3 + (c1 - c3) % n) / n) < m
*
* This means
*
* f - floor((c1 - c3)/n)
*
* is equal to a multiple of m plus a value between 0 and m - 1.
* That is,
*
* e = floor((f - floor((c1 - c3)/n))/m)
*
* Construct the inequality constraint
*
* -n f + m n e + c1 - c3 >= 0
*
* scale it down to
*
* -f + m e + floor((c1 - c3)/n) >= 0
*
* and add m - 1, to obtain
*
* -f + m e + floor((c1 - c3)/n) + m - 1 >= 0
*
* This constraint can then be used by set_div_from_lower_bound_if_better
* to obtain
*
* e = floor((f - floor((c1 - c3)/n))/m)
*
* Adding m - 1 is needed to be able to reuse set_div_from_lower_bound,
* which subtracts this amount from the constraint (by adding it
* to the negated constraint).
*/
static __isl_give isl_basic_map *set_residue_div(__isl_take isl_basic_map *bmap,
int l, isl_int sum, int div,
unsigned v_div, unsigned total, int i, int j, int *progress)
{
isl_ctx *ctx;
isl_vec *v;
if (!bmap)
return NULL;
ctx = isl_basic_map_get_ctx(bmap);
if (!is_residue(bmap->ineq[i], bmap->ineq[l], sum, total,
&ctx->normalize_gcd))
return bmap;
if (!is_residue_div_pair(bmap, l, div, v_div, i, j, ctx->normalize_gcd))
return bmap;
v = isl_vec_alloc(ctx, 1 + total);
if (!v)
return isl_basic_map_free(bmap);
isl_seq_cpy(v->el, bmap->ineq[l], 1 + total);
isl_seq_sub(v->el, bmap->ineq[i], 1 + total);
scale_down_inequality(v->el, ctx->normalize_gcd, total);
isl_int_add(v->el[0], v->el[0], v->el[1 + v_div + div]);
isl_int_sub_ui(v->el[0], v->el[0], 1);
bmap = set_div_from_lower_bound_if_better(bmap, div, v->el, progress);
isl_vec_free(v);
return bmap;
}
/* Given a lower bound constraint at position "l" of "bmap"
* on local variable "div" such that the sum of the constant terms
* of this constraint and the corresponding upper bound is equal to "sum",
* check if some other pair of constraints can be found in "opposite"
* that can be used to derive a reduced expression for the local variable.
* "opposite" describes all pairs of opposite constraints.
* It is an array of size equal to the number of inequality constraints
* with as entries either
* - zero, if the constraint has no opposite, or
* - 1 + the position of the opposite constraint.
* Set *progress if anything is changed.
*
* In particular, let l be the constraint
*
* -n f + g + m n e + c1 >= 0
*
* The opposite constraint is
*
* n f - g - m n e + c2 >= 0
*
* with c1 + c2 equal to "sum".
*
* Look for a pair of constraints
*
* g + c3 >= 0
* -g + c4 >= 0
*
* with c3 + c4 < m n that can be used to obtain a reduced expression for e.
* First look for any pair of constraints with constant terms
* that satisfy c3 + c4 < m n and then check whether either of them
* can be used in this way.
*/
static __isl_give isl_basic_map *check_for_residue_div(
__isl_take isl_basic_map *bmap, int *opposite, int l, isl_int sum,
int div, int *progress)
{
int i;
isl_size n, v_div, total;
isl_ctx *ctx;
v_div = isl_basic_map_var_offset(bmap, isl_dim_div);
total = isl_basic_map_dim(bmap, isl_dim_all);
n = isl_basic_map_n_inequality(bmap);
if (v_div < 0 || total < 0 || n < 0)
return isl_basic_map_free(bmap);
ctx = isl_basic_map_get_ctx(bmap);
for (i = 0; i < n; ++i) {
int j;
if (i == l)
continue;
if (!opposite[i])
continue;
j = opposite[i] - 1;
if (j < i)
continue;
if (j == l)
continue;
if (!isl_int_is_zero(bmap->ineq[i][1 + v_div + div]))
continue;
isl_int_add(ctx->normalize_gcd,
bmap->ineq[i][0], bmap->ineq[j][0]);
if (isl_int_ge(ctx->normalize_gcd,
bmap->ineq[l][1 + v_div + div]))
continue;
bmap = set_residue_div(bmap, l, sum, div, v_div, total, i, j,
progress);
bmap = set_residue_div(bmap, l, sum, div, v_div, total, j, i,
progress);
}
return bmap;
}
/* Given two constraints "k" and "l" that are opposite to each other,
* except for the constant term, check if we can use them
* to obtain an expression for one of the hitherto unknown divs or
@ -1708,46 +2044,66 @@ static __isl_give isl_basic_map *check_for_residues(
* "sum" is the sum of the constant terms of the constraints.
* If this sum is strictly smaller than the coefficient of one
* of the divs, then this pair can be used to define the div.
* To avoid the introduction of circular definitions of divs, we
* do not use the pair if the resulting expression would refer to
* any other undefined divs or if any known div is defined in
* terms of the unknown div.
* Use the lower bound of this pair if it is better than
* any previously known expression and
* if there is no risk of introducing circular definitions.
* If, moreover, this coefficient is a non-trivial multiple
* of a value greater than the sum and if some other pair of constraints
* can be found that can be used to eliminate coefficients
* that are not a multiple of this value, then a more simplified
* expression can be obtained.
* "opposite" describes all pairs of opposite constraints.
* It is an array of size equal to the number of inequality constraints
* with as entries either
* - zero, if the constraint has no opposite, or
* - 1 + the position of the opposite constraint.
*/
static __isl_give isl_basic_map *check_for_div_constraints(
__isl_take isl_basic_map *bmap, int k, int l, isl_int sum,
int *progress)
__isl_take isl_basic_map *bmap, int *opposite,
int k, int l, isl_int sum, int *progress)
{
int i;
unsigned total = isl_basic_map_offset(bmap, isl_dim_div);
isl_size n_div = isl_basic_map_dim(bmap, isl_dim_div);
for (i = 0; i < bmap->n_div; ++i) {
isl_bool set_div;
if (n_div < 0)
return isl_basic_map_free(bmap);
for (i = 0; i < n_div; ++i) {
int div_set = 0;
int c;
if (isl_int_is_zero(bmap->ineq[k][total + i]))
continue;
if (isl_int_abs_ge(sum, bmap->ineq[k][total + i]))
continue;
set_div = better_div_constraint(bmap, i, k);
if (set_div >= 0 && set_div)
set_div = ok_to_set_div_from_bound(bmap, i, k);
if (set_div < 0)
return isl_basic_map_free(bmap);
if (!set_div)
break;
if (isl_int_is_pos(bmap->ineq[k][total + i]))
bmap = set_div_from_lower_bound(bmap, i, k);
c = k;
else
bmap = set_div_from_lower_bound(bmap, i, l);
c = l;
if (isl_int_ge(sum, bmap->ineq[c][total + i]))
continue;
bmap = check_for_residue_div(bmap, opposite, c, sum, i,
&div_set);
bmap = set_div_from_lower_bound_if_better(bmap, i,
bmap->ineq[c], &div_set);
if (!bmap)
return NULL;
if (!div_set)
continue;
mark_progress(progress);
break;
}
return bmap;
}
/* Look for pairs of constraints that have equal or opposite coefficients.
* For each pair of constraints with equal coefficients, only keep
* the one which imposes the most stringent constraint, i.e.,
* the one with the smallest constant term.
/* Exploit the pairs of inequality constraints of "bmap"
* with opposite coefficients. They are described by "opposite",
* an array of size equal to the number of inequality constraints
* with as entries either
* - zero, if the constraint has no opposite, or
* - 1 + the position of the opposite constraint.
* Detect (better) integer division expressions if "detect_divs" is set.
* Set *progress if any progress is made.
*
* For each pair of constraints with opposite coefficients,
* consider the sum of the constant terms.
* If the sum is smaller than zero, then the constraints conflict.
@ -1757,6 +2113,65 @@ static __isl_give isl_basic_map *check_for_div_constraints(
* can be used to simplify any other constraints and/or,
* if "detect_divs" is set, whether a (better) integer division definition
* can be read off from the pair.
*
* Only check each pair once (with k < l).
*/
static __isl_give isl_basic_map *exploit_opposite_constraints(
__isl_take isl_basic_map *bmap, int *opposite,
int *progress, int detect_divs)
{
int k, l;
isl_int sum;
if (!opposite)
return bmap;
isl_int_init(sum);
for (k = 0; bmap && k < bmap->n_ineq-1; ++k) {
if (!opposite[k])
continue;
l = opposite[k] - 1;
if (l < k)
continue;
isl_int_add(sum, bmap->ineq[k][0], bmap->ineq[l][0]);
if (isl_int_is_pos(sum)) {
int residue = 0;
bmap = check_for_residues(bmap, k, l, sum, &residue);
if (detect_divs)
bmap = check_for_div_constraints(bmap, opposite,
k, l, sum, progress);
if (!residue)
continue;
mark_progress(progress);
break;
}
if (isl_int_is_zero(sum)) {
/* We need to break out of the loop after these
* changes since the contents of the hash
* will no longer be valid.
* Plus, we probably we want to regauss first.
*/
mark_progress(progress);
isl_basic_map_drop_inequality(bmap, l);
isl_basic_map_inequality_to_equality(bmap, k);
} else
bmap = isl_basic_map_set_to_empty(bmap);
break;
}
isl_int_clear(sum);
free(opposite);
return bmap;
}
/* Look for pairs of constraints that have equal or opposite coefficients.
* Detect (better) integer division expressions if "detect_divs" is set.
*
* For each pair of constraints with equal coefficients, only keep
* the one which imposes the most stringent constraint, i.e.,
* the one with the smallest constant term.
* Detect opposite constraints and handle them
* in exploit_opposite_constraints.
*/
__isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
__isl_take isl_basic_map *bmap, int *progress, int detect_divs)
@ -1764,7 +2179,7 @@ __isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
struct isl_constraint_index ci;
int k, l, h;
isl_size total = isl_basic_map_dim(bmap, isl_dim_all);
isl_int sum;
int *opposite;
if (total < 0 || bmap->n_ineq <= 1)
return bmap;
@ -1786,44 +2201,10 @@ __isl_give isl_basic_map *isl_basic_map_remove_duplicate_constraints(
isl_basic_map_drop_inequality(bmap, k);
--k;
}
isl_int_init(sum);
for (k = 0; bmap && k < bmap->n_ineq-1; ++k) {
isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
h = hash_index(&ci, bmap, k);
isl_seq_neg(bmap->ineq[k]+1, bmap->ineq[k]+1, total);
if (!ci.index[h])
continue;
l = ci.index[h] - &bmap->ineq[0];
isl_int_add(sum, bmap->ineq[k][0], bmap->ineq[l][0]);
if (isl_int_is_pos(sum)) {
int residue = 0;
bmap = check_for_residues(bmap, k, l, sum, &residue);
if (detect_divs)
bmap = check_for_div_constraints(bmap, k, l,
sum, progress);
if (!residue)
continue;
mark_progress(progress);
break;
}
if (isl_int_is_zero(sum)) {
/* We need to break out of the loop after these
* changes since the contents of the hash
* will no longer be valid.
* Plus, we probably we want to regauss first.
*/
mark_progress(progress);
isl_basic_map_drop_inequality(bmap, l);
isl_basic_map_inequality_to_equality(bmap, k);
} else
bmap = isl_basic_map_set_to_empty(bmap);
break;
}
isl_int_clear(sum);
opposite = detect_opposites(&ci, bmap);
constraint_index_free(&ci);
return bmap;
return exploit_opposite_constraints(bmap, opposite, progress,
detect_divs);
}
/* Detect all pairs of inequalities that form an equality.
@ -5636,11 +6017,13 @@ static __isl_give isl_basic_map *isl_basic_map_drop_redundant_divs_ineq(
if (defined)
set_div = isl_bool_false;
else
set_div = ok_to_set_div_from_bound(bmap, i, last_pos);
set_div = ok_to_set_div_from_bound(bmap, i,
bmap->ineq[last_pos]);
if (set_div < 0)
return isl_basic_map_free(bmap);
if (set_div) {
bmap = set_div_from_lower_bound(bmap, i, last_pos);
bmap = set_div_from_lower_bound(bmap, i,
bmap->ineq[last_pos]);
return drop_redundant_divs_again(bmap, pairs, 1);
}
pairs[i] = 0;
@ -6087,8 +6470,14 @@ __isl_give isl_basic_map *isl_basic_map_reduce_coefficients(
ISL_F_CLR(bmap, ISL_BASIC_MAP_NO_REDUNDANT);
bmap = isl_basic_map_detect_inequality_pairs(bmap, &progress);
if (progress) {
isl_bool empty;
bmap = isl_basic_map_gauss(bmap, NULL);
bmap = reduce_coefficients(bmap, &data);
empty = isl_basic_map_plain_is_empty(bmap);
if (empty < 0)
goto error;
if (!empty)
bmap = reduce_coefficients(bmap, &data);
bmap = eliminate_divs_eq(bmap, &progress);
}
}

View File

@ -1567,63 +1567,6 @@ static int test_simple_hull(struct isl_ctx *ctx)
return 0;
}
/* Inputs for isl_set_get_simple_fixed_box_hull tests.
* "set" is the input set.
* "offset" is the expected box offset.
* "size" is the expected box size.
*/
static struct {
const char *set;
const char *offset;
const char *size;
} box_hull_tests[] = {
{ "{ S[x, y] : 0 <= x, y < 10 }", "{ S[0, 0] }", "{ S[10, 10] }" },
{ "[N] -> { S[x, y] : N <= x, y < N + 10 }",
"[N] -> { S[N, N] }", "{ S[10, 10] }" },
{ "{ S[x, y] : 0 <= x + y, x - y < 10 }",
"{ S[0, -4] }", "{ S[10, 9] }" },
{ "{ [i=0:10] : exists (e0, e1: 3e1 >= 1 + 2e0 and "
"8e1 <= -1 + 5i - 5e0 and 2e1 >= 1 + 2i - 5e0) }",
"{ [3] }", "{ [8] }" },
{ "[N] -> { [w = 0:17] : exists (e0: w < 2N and "
"-1 + w <= e0 <= w and 2e0 >= N + w and w <= 2e0 <= 15 + w) }",
"[N] -> { [N] }", "{ [9] }" },
};
/* Perform basic isl_set_get_simple_fixed_box_hull tests.
*/
static int test_box_hull(struct isl_ctx *ctx)
{
int i;
for (i = 0; i < ARRAY_SIZE(box_hull_tests); ++i) {
const char *str;
isl_stat r;
isl_set *set;
isl_multi_aff *offset;
isl_multi_val *size;
isl_fixed_box *box;
set = isl_set_read_from_str(ctx, box_hull_tests[i].set);
box = isl_set_get_simple_fixed_box_hull(set);
offset = isl_fixed_box_get_offset(box);
size = isl_fixed_box_get_size(box);
str = box_hull_tests[i].offset;
r = multi_aff_check_plain_equal(offset, str);
str = box_hull_tests[i].size;
if (r >= 0)
r = multi_val_check_plain_equal(size, str);
isl_multi_aff_free(offset);
isl_multi_val_free(size);
isl_fixed_box_free(box);
isl_set_free(set);
if (r < 0)
return -1;
}
return 0;
}
void test_convex_hull_case(struct isl_ctx *ctx, const char *name)
{
char *filename;
@ -10800,7 +10743,6 @@ struct {
{ "recession cone", &test_recession_cone },
{ "affine hull", &test_affine_hull },
{ "simple_hull", &test_simple_hull },
{ "box hull", &test_box_hull },
{ "coalesce", &test_coalesce },
{ "factorize", &test_factorize },
{ "subset", &test_subset },

View File

@ -101,6 +101,9 @@ struct ternary {
* The spelling depends on the isl type and
* in particular on whether an equality method is available or
* whether only obvious equality can be tested.
*
* Since isl::multi_val has both an is_equal and a plain_is_equal,
* use a specific overload for isl::multi_val that calls is_equal.
*/
template <typename T, typename std::decay<decltype(
std::declval<T>().is_equal(std::declval<T>()))>::type = true>
@ -114,6 +117,10 @@ static bool is_equal(const T &a, const T &b)
{
return a.plain_is_equal(b);
}
static bool is_equal(const isl::multi_val &a, const isl::multi_val &b)
{
return a.is_equal(b);
}
/* A helper macro for throwing an isl::exception_invalid with message "msg".
*/
@ -431,6 +438,52 @@ static void test_fixed_power(isl::ctx ctx)
});
}
/* Perform basic simple fixed box hull tests.
*/
static void test_box_hull(isl::ctx ctx)
{
C(&isl::set::simple_fixed_box_hull, {
{ "{ S[x, y] : 0 <= x, y < 10 }",
"{ offset: { S[0, 0] }, size: { S[10, 10] } }" },
{ "[N] -> { S[x, y] : N <= x, y < N + 10 }",
"{ offset: [N] -> { S[(N), (N)] }, size: { S[10, 10] } }" },
{ "{ S[x, y] : 0 <= x + y, x - y < 10 }",
"{ offset: { S[0, -4] }, size: { S[10, 9] } }" },
{ "{ [i=0:10] : exists (e0, e1: 3e1 >= 1 + 2e0 and "
"8e1 <= -1 + 5i - 5e0 and 2e1 >= 1 + 2i - 5e0) }",
"{ offset: { [3] }, size: { [8] } }" },
{ "[N] -> { [w = 0:17] : exists (e0: w < 2N and "
"-1 + w <= e0 <= w and 2e0 >= N + w and w <= 2e0 <= 15 + w) }",
"{ offset: [N] -> { [N] }, size: { [9] } }" },
{ "[N] -> { [N//2:N//2+4] }",
"{ offset: [N] -> { [N//2] }, size: { [5] } }" },
{ "[N] -> { [N//2+N//3:N//2+N//3+4] }",
"{ offset: [N] -> { [N//2+N//3] }, size: { [5] } }" },
{ "[N] -> { [a=0:59, b=0:1] : 15N - a <= 60b <= 59 + 15N - a and "
"-22 + 20b <= 20*floor((-1 + 15N - a)/60) < 20b and "
"60*floor((-1 + 15N - a)/60) <= -46 + 15N - a }",
"{ offset: [N] -> { [(15*((N) mod 4)), (floor((N)/4))] }, "
"size: { [15, 1] } }" },
{ "{ [i=-3:7] : i mod 4 = 0 }",
"{ offset: { [(0)] }, size: { [5] } }" },
{ "[N] -> { [i, N - 4i] : -14 + N <= 16i <= 1 + N }",
"{ offset: [N] -> { [(floor((1 + N)/16)), "
"(4 + N + 4*floor((-2 - N)/16))] }, "
"size: { [1, 1] } }" },
});
C(&isl::map::range_simple_fixed_box_hull, {
{ "{ [N] -> [i, N - 4i] : -14 + N <= 16i <= 1 + N }",
"{ offset: { [N] -> [(floor((1 + N)/16)), "
"(4 + N + 4*floor((-2 - N)/16))] }, "
"size: { [1, 1] } }" },
{ "{ [N] -> [i, j] : 4j = N - i and -1 + 3N <= 4i <= 14 + 3N }",
"{ offset: { [N] -> [(4 + N + 4*floor((-2 - N)/16)), "
"(floor((1 + N)/16))] }, "
"size: { [1, 1] } }" },
});
}
/* Perform some basic intersection tests.
*/
static void test_intersect(isl::ctx ctx)
@ -913,6 +966,7 @@ static std::vector<std::pair<const char *, void (*)(isl::ctx)>> tests =
{ "conversion", &test_conversion },
{ "preimage", &test_preimage },
{ "fixed power", &test_fixed_power },
{ "box hull", &test_box_hull },
{ "intersect", &test_intersect },
{ "lexmin", &test_lexmin },
{ "gist", &test_gist },

View File

@ -2198,6 +2198,45 @@ __isl_give isl_union_set *isl_union_set_simple_hull(
return isl_union_map_simple_hull(uset);
}
/* Compute a superset of the convex hull of "map" that is described
* by only the constraints in the constituents of "map" and
* return the result as an isl_map.
* In particular, the result is composed of constraints that appear
* in each of the basic maps of "map".
*/
static __isl_give isl_map *isl_map_plain_unshifted_simple_hull_map(
__isl_take isl_map *map)
{
return isl_map_from_basic_map(isl_map_plain_unshifted_simple_hull(map));
}
/* For each map in "umap", compute a superset of the convex hull
* that is described by only the constraints in the constituents of that map and
* collect the results.
* In particular, each result is composed of constraints that appear
* in each of the basic maps of the corresponding map.
*/
__isl_give isl_union_map *isl_union_map_plain_unshifted_simple_hull(
__isl_take isl_union_map *umap)
{
return total(umap, &isl_map_plain_unshifted_simple_hull_map);
}
/* For each set in "uset", compute a superset of the convex hull
* that is described by only the constraints in the constituents of that set and
* collect the results.
* In particular, each result is composed of constraints that appear
* in each of the basic sets of the corresponding set.
*/
__isl_give isl_union_set *isl_union_set_plain_unshifted_simple_hull(
__isl_take isl_union_set *uset)
{
isl_union_map *umap;
umap = isl_union_map_plain_unshifted_simple_hull(uset_to_umap(uset));
return uset_from_umap(umap);
}
static __isl_give isl_union_map *inplace(__isl_take isl_union_map *umap,
__isl_give isl_map *(*fn)(__isl_take isl_map *))
{

View File

@ -1589,6 +1589,17 @@ __isl_give isl_val *isl_val_zero_on_domain(__isl_take isl_local_space *ls)
#include <isl_multi_tuple_id_templ.c>
#include <isl_multi_zero_templ.c>
/* Is "mv1" equal to "mv2"?
*
* Call the generic isl_multi_val_plain_is_equal, which compares values
* using isl_val_plain_is_equal, i.e., isl_val_eq.
*/
isl_bool isl_multi_val_is_equal(__isl_keep isl_multi_val *mv1,
__isl_keep isl_multi_val *mv2)
{
return isl_multi_val_plain_is_equal(mv1, mv2);
}
/* Does "mv" consist of only zeros?
*/
isl_bool isl_multi_val_is_zero(__isl_keep isl_multi_val *mv)

View File

@ -0,0 +1,19 @@
if (p_0 >= p_1 + 1) {
for (int c0 = 0; c0 <= p_1 - 4 * floord(p_1 + 2, 4); c0 += 1)
Stmt2(c0);
if (4 * floord(p_1 + 2, 4) >= p_1 + 1)
for (int c0 = 0; c0 <= p_1 - 4 * floord(p_1 + 2, 4) + 4; c0 += 1)
Stmt2(c0);
} else if (p_0 >= p_1 + 4 * floord(p_0 - p_1, 4) + 1) {
for (int c0 = 0; c0 <= p_0 - 4 * floord(p_0 + 2, 4); c0 += 1)
Stmt2(c0);
if (4 * floord(p_0 + 2, 4) >= p_0 + 1)
for (int c0 = 0; c0 <= p_0 - 4 * floord(p_0 + 2, 4) + 4; c0 += 1)
Stmt2(c0);
} else if (4 * floord(p_0 + 2, 4) >= p_0 + 1) {
for (int c0 = 0; c0 <= p_0 - 4 * floord(p_0 + 2, 4) + 4; c0 += 1)
Stmt2(c0);
} else {
for (int c0 = 0; c0 <= p_0 - 4 * floord(p_0 + 2, 4); c0 += 1)
Stmt2(c0);
}

View File

@ -0,0 +1,7 @@
# A Polly generated test case that would cause a failure
# in isl_basic_map_reduce_coefficients in an earlier version of isl.
domain: "[p_0, p_1] -> { Stmt2[i0] : i0 >= 0 and ((p_1 < p_0 and 4*floor((2 + p_1)/4) <= p_1 - i0) or (p_1 >= p_0 and 4*floor((p_0 - p_1)/4) < p_0 - p_1 and 4*floor((2 + p_0)/4) <= p_0 - i0) or (p_1 < p_0 and p_1 < 4*floor((2 + p_1)/4) <= 4 + p_1 - i0 and 4*floor((p_0 - p_1)/4) < p_0 - p_1) or (p_1 >= p_0 and 4*floor((p_0 - p_1)/4) < p_0 - p_1 and p_0 < 4*floor((2 + p_0)/4) <= 4 + p_0 - i0) or ((2 + p_0) mod 4 = 6 + p_1 + 4*floor((-1 - p_1)/4) and p_1 >= p_0 and -4 - p_1 + i0 <= 4*floor((-1 - p_1)/4) <= -3 - p_1) or ((2 + p_0) mod 4 = 2 + p_1 + 4*floor((1 - p_1)/4) and p_1 >= p_0 and 4*floor((1 - p_1)/4) >= -4 - p_1 + i0 and 4*floor((1 - p_1)/4) < -p_1) or ((-p_0 + p_1) mod 4 = 0 and p_1 <= -4 + p_0 and p_1 < 4*floor((2 + p_1)/4) <= 4 + p_1 - i0)) }"
child:
context: "[p_0, p_1] -> { [] : p_0 >= -2147483648 and p_0 <= 2147483647 and p_1 >= -2147483648 and p_1 <= 2147483647 }"
child:
schedule: "[p_0, p_1] -> [{ Stmt2[i0] -> [(i0)] }]"