add support for structs
authorSven Verdoolaege <skimo@kotnet.org>
Thu, 8 Aug 2013 12:50:08 +0000 (8 14:50 +0200)
committerSven Verdoolaege <skimo@kotnet.org>
Wed, 16 Oct 2013 13:22:18 +0000 (16 15:22 +0200)
A member access is represented by an index expression and access
relation with a wrapped range.  The domain of the wrapped range
represents the structure, while the range of the wrapped range
represents the member.  The domain may in turn be a wrapped relation
in case of nested member accesses.
For example, an access of the form

s.f[i].a[j]

is represented as

{ S_0[i, j] -> s_f_a[s_f[s[] -> f[i]] -> a[j]] }

We also keep track of all the structure definitions involved
as some users may need to print these definitions.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
30 files changed:
clang.cc
clang.h
emit.c
include/pet.h
parse.c
scan.cc
scan.h
scop.c
scop_plus.cc
scop_plus.h
tests/struct1.c [new file with mode: 0644]
tests/struct1.scop [new file with mode: 0644]
tests/struct10.c [new file with mode: 0644]
tests/struct10.scop [new file with mode: 0644]
tests/struct2.c [new file with mode: 0644]
tests/struct2.scop [new file with mode: 0644]
tests/struct3.c [new file with mode: 0644]
tests/struct3.scop [new file with mode: 0644]
tests/struct4.c [new file with mode: 0644]
tests/struct4.scop [new file with mode: 0644]
tests/struct5.c [new file with mode: 0644]
tests/struct5.scop [new file with mode: 0644]
tests/struct6.c [new file with mode: 0644]
tests/struct6.scop [new file with mode: 0644]
tests/struct7.c [new file with mode: 0644]
tests/struct7.scop [new file with mode: 0644]
tests/struct8.c [new file with mode: 0644]
tests/struct8.scop [new file with mode: 0644]
tests/struct9.c [new file with mode: 0644]
tests/struct9.scop [new file with mode: 0644]

index fca093b..a04e111 100644 (file)
--- a/clang.cc
+++ b/clang.cc
@@ -1,5 +1,6 @@
 /*
  * Copyright 2011      Leiden University. All rights reserved.
+ * Copyright 2013 Ecole Normale Superieure. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -51,3 +52,13 @@ QualType pet_clang_base_type(QualType qt)
        }
        return qt;
 }
+
+/* Given a record type, return the corresponding RecordDecl.
+ */
+RecordDecl *pet_clang_record_decl(QualType T)
+{
+       const Type *type = T->getCanonicalTypeInternal().getTypePtr();
+       const RecordType *record;
+       record = cast<RecordType>(type);
+       return record->getDecl();
+}
diff --git a/clang.h b/clang.h
index 8592ed8..f69bfb3 100644 (file)
--- a/clang.h
+++ b/clang.h
@@ -4,5 +4,6 @@
 #include <clang/AST/Type.h>
 
 clang::QualType pet_clang_base_type(clang::QualType qt);
+clang::RecordDecl *pet_clang_record_decl(clang::QualType T);
 
 #endif
diff --git a/emit.c b/emit.c
index 30bdaba..9e92662 100644 (file)
--- a/emit.c
+++ b/emit.c
@@ -296,6 +296,11 @@ static int emit_array(yaml_emitter_t *emitter, struct pet_array *array)
        if (emit_named_int(emitter, "element_size", array->element_size) < 0)
                return -1;
 
+       if (array->element_is_record)
+               if (emit_named_int(emitter, "element_is_record",
+                                       array->element_is_record) < 0)
+                       return -1;
+
        if (array->live_out) {
                if (emit_string(emitter, "live_out") < 0)
                        return -1;
index bacf469..ed24e01 100644 (file)
@@ -109,6 +109,13 @@ enum pet_ter_arg_type {
  * Each dimension in this space corresponds to the value of the
  * corresponding argument.
  *
+ * The ranges of the index expressions and access relations may
+ * also be wrapped relations, in which case the expression represents
+ * a member access, with the structure represented by the domain
+ * of this wrapped relation and the member represented by the range.
+ * In case of nested member accesses, the domain is itself a wrapped
+ * relation.
+ *
  * If the data space is unnamed (and 1D), then it represents
  * the set of integers.  That is, the access represents a value that
  * is equal to the index.
@@ -208,6 +215,8 @@ struct pet_type {
  * and may be NULL if no such constraints were specified by the user
  *
  * element_size is the size in bytes of each array element
+ * element_type is the type of the array elements.
+ * element_is_record is set if this type is a record type.
  *
  * live_out is set if the array appears in a live-out pragma
  *
@@ -223,6 +232,7 @@ struct pet_array {
        isl_set *extent;
        isl_set *value_bounds;
        char *element_type;
+       int element_is_record;
        int element_size;
        int live_out;
        int uniquely_defined;
diff --git a/parse.c b/parse.c
index 6b8cd50..2c978e9 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -233,6 +233,10 @@ static struct pet_array *extract_array(isl_ctx *ctx, yaml_document_t *document,
                                        extract_string(ctx, document, value);
                if (!strcmp((char *) key->data.scalar.value, "element_size"))
                        array->element_size = extract_int(ctx, document, value);
+               if (!strcmp((char *) key->data.scalar.value,
+                               "element_is_record"))
+                       array->element_is_record =
+                                       extract_int(ctx, document, value);
                if (!strcmp((char *) key->data.scalar.value, "live_out"))
                        array->live_out = extract_int(ctx, document, value);
                if (!strcmp((char *) key->data.scalar.value,
diff --git a/scan.cc b/scan.cc
index 82c2a6a..8322d3e 100644 (file)
--- a/scan.cc
+++ b/scan.cc
@@ -813,6 +813,15 @@ __isl_give isl_pw_aff *PetScan::extract_affine(ArraySubscriptExpr *expr)
        return nested_access(expr);
 }
 
+/* Affine expressions are not supposed to contain member accesses,
+ * but if nesting is allowed, we return a parameter corresponding
+ * to the member access.
+ */
+__isl_give isl_pw_aff *PetScan::extract_affine(MemberExpr *expr)
+{
+       return nested_access(expr);
+}
+
 /* Extract an affine expression from a conditional operation.
  */
 __isl_give isl_pw_aff *PetScan::extract_affine(ConditionalOperator *expr)
@@ -848,6 +857,8 @@ __isl_give isl_pw_aff *PetScan::extract_affine(Expr *expr)
                return extract_affine(cast<CallExpr>(expr));
        case Stmt::ArraySubscriptExprClass:
                return extract_affine(cast<ArraySubscriptExpr>(expr));
+       case Stmt::MemberExprClass:
+               return extract_affine(cast<MemberExpr>(expr));
        case Stmt::ConditionalOperatorClass:
                return extract_affine(cast<ConditionalOperator>(expr));
        default:
@@ -879,6 +890,9 @@ static int array_depth(const Type *type)
 /* Return the depth of the array accessed by the index expression "index".
  * If "index" is an affine expression, i.e., if it does not access
  * any array, then return 1.
+ * If "index" represent a member access, i.e., if its range is a wrapped
+ * relation, then return the sum of the depth of the array of structures
+ * and that of the member inside the structure.
  */
 static int extract_depth(__isl_keep isl_multi_pw_aff *index)
 {
@@ -888,6 +902,22 @@ static int extract_depth(__isl_keep isl_multi_pw_aff *index)
        if (!index)
                return -1;
 
+       if (isl_multi_pw_aff_range_is_wrapping(index)) {
+               int domain_depth, range_depth;
+               isl_multi_pw_aff *domain, *range;
+
+               domain = isl_multi_pw_aff_copy(index);
+               domain = isl_multi_pw_aff_range_factor_domain(domain);
+               domain_depth = extract_depth(domain);
+               isl_multi_pw_aff_free(domain);
+               range = isl_multi_pw_aff_copy(index);
+               range = isl_multi_pw_aff_range_factor_range(range);
+               range_depth = extract_depth(range);
+               isl_multi_pw_aff_free(range);
+
+               return domain_depth + range_depth;
+       }
+
        if (!isl_multi_pw_aff_has_tuple_id(index, isl_dim_out))
                return 1;
 
@@ -956,6 +986,8 @@ __isl_give isl_multi_pw_aff *PetScan::extract_index(Expr *expr)
                return extract_index(cast<ArraySubscriptExpr>(expr));
        case Stmt::IntegerLiteralClass:
                return extract_index(cast<IntegerLiteral>(expr));
+       case Stmt::MemberExprClass:
+               return extract_index(cast<MemberExpr>(expr));
        default:
                unsupported(expr);
        }
@@ -965,6 +997,8 @@ __isl_give isl_multi_pw_aff *PetScan::extract_index(Expr *expr)
 /* Given a partial index expression "base" and an extra index "index",
  * append the extra index to "base" and return the result.
  * Additionally, add the constraints that the extra index is non-negative.
+ * If "index" represent a member access, i.e., if its range is a wrapped
+ * relation, then we recursively extend the range of this nested relation.
  */
 static __isl_give isl_multi_pw_aff *subscript(__isl_take isl_multi_pw_aff *base,
        __isl_take isl_pw_aff *index)
@@ -972,6 +1006,24 @@ static __isl_give isl_multi_pw_aff *subscript(__isl_take isl_multi_pw_aff *base,
        isl_id *id;
        isl_set *domain;
        isl_multi_pw_aff *access;
+       int member_access;
+
+       member_access = isl_multi_pw_aff_range_is_wrapping(base);
+       if (member_access < 0)
+               goto error;
+       if (member_access) {
+               isl_multi_pw_aff *domain, *range;
+               isl_id *id;
+
+               id = isl_multi_pw_aff_get_tuple_id(base, isl_dim_out);
+               domain = isl_multi_pw_aff_copy(base);
+               domain = isl_multi_pw_aff_range_factor_domain(domain);
+               range = isl_multi_pw_aff_range_factor_range(base);
+               range = subscript(range, index);
+               access = isl_multi_pw_aff_range_product(domain, range);
+               access = isl_multi_pw_aff_set_tuple_id(access, isl_dim_out, id);
+               return access;
+       }
 
        id = isl_multi_pw_aff_get_tuple_id(base, isl_dim_set);
        index = isl_pw_aff_from_range(index);
@@ -982,6 +1034,10 @@ static __isl_give isl_multi_pw_aff *subscript(__isl_take isl_multi_pw_aff *base,
        access = isl_multi_pw_aff_set_tuple_id(access, isl_dim_set, id);
 
        return access;
+error:
+       isl_multi_pw_aff_free(base);
+       isl_pw_aff_free(index);
+       return NULL;
 }
 
 /* Extract an index expression from the given array subscript expression.
@@ -1016,6 +1072,108 @@ __isl_give isl_multi_pw_aff *PetScan::extract_index(ArraySubscriptExpr *expr)
        return access;
 }
 
+/* Construct a name for a member access by concatenating the name
+ * of the array of structures and the member, separated by an underscore.
+ *
+ * The caller is responsible for freeing the result.
+ */
+static char *member_access_name(isl_ctx *ctx, const char *base,
+       const char *field)
+{
+       int len;
+       char *name;
+
+       len = strlen(base) + 1 + strlen(field);
+       name = isl_alloc_array(ctx, char, len + 1);
+       if (!name)
+               return NULL;
+       snprintf(name, len + 1, "%s_%s", base, field);
+
+       return name;
+}
+
+/* Given an index expression "base" for an element of an array of structures
+ * and an expression "field" for the field member being accessed, construct
+ * an index expression for an access to that member of the given structure.
+ * In particular, take the range product of "base" and "field" and
+ * attach a name to the result.
+ */
+static __isl_give isl_multi_pw_aff *member(__isl_take isl_multi_pw_aff *base,
+       __isl_take isl_multi_pw_aff *field)
+{
+       isl_ctx *ctx;
+       isl_multi_pw_aff *access;
+       const char *base_name, *field_name;
+       char *name;
+
+       ctx = isl_multi_pw_aff_get_ctx(base);
+
+       base_name = isl_multi_pw_aff_get_tuple_name(base, isl_dim_out);
+       field_name = isl_multi_pw_aff_get_tuple_name(field, isl_dim_out);
+       name = member_access_name(ctx, base_name, field_name);
+
+       access = isl_multi_pw_aff_range_product(base, field);
+
+       access = isl_multi_pw_aff_set_tuple_name(access, isl_dim_out, name);
+       free(name);
+
+       return access;
+}
+
+/* Extract an index expression from a member expression.
+ *
+ * If the base access (to the structure containing the member)
+ * is of the form
+ *
+ *     [] -> A[..]
+ *
+ * and the member is called "f", then the member access is of
+ * the form
+ *
+ *     [] -> A_f[A[..] -> f[]]
+ *
+ * If the member access is to an anonymous struct, then simply return
+ *
+ *     [] -> A[..]
+ *
+ * If the member access in the source code is of the form
+ *
+ *     A->f
+ *
+ * then it is treated as
+ *
+ *     A[0].f
+ */
+__isl_give isl_multi_pw_aff *PetScan::extract_index(MemberExpr *expr)
+{
+       Expr *base = expr->getBase();
+       FieldDecl *field = cast<FieldDecl>(expr->getMemberDecl());
+       isl_multi_pw_aff *base_access, *field_access;
+       isl_id *id;
+       isl_space *space;
+
+       base_access = extract_index(base);
+
+       if (expr->isArrow()) {
+               isl_space *space = isl_space_params_alloc(ctx, 0);
+               isl_local_space *ls = isl_local_space_from_space(space);
+               isl_aff *aff = isl_aff_zero_on_domain(ls);
+               isl_pw_aff *index = isl_pw_aff_from_aff(aff);
+               base_access = subscript(base_access, index);
+       }
+
+       if (field->isAnonymousStructOrUnion())
+               return base_access;
+
+       id = isl_id_alloc(ctx, field->getName().str().c_str(), field);
+       space = isl_multi_pw_aff_get_domain_space(base_access);
+       space = isl_space_from_domain(space);
+       space = isl_space_set_tuple_id(space, isl_dim_out, id);
+       field_access = isl_multi_pw_aff_zero(space);
+
+       return member(base_access, field_access);
+}
+
 /* Check if "expr" calls function "minmax" with two arguments and if so
  * make lhs and rhs refer to these two arguments.
  */
@@ -1510,7 +1668,7 @@ struct pet_scop *PetScan::extract(DeclStmt *stmt)
        decl = stmt->getSingleDecl();
        vd = cast<VarDecl>(decl);
 
-       array = extract_array(ctx, vd);
+       array = extract_array(ctx, vd, NULL);
        if (array)
                array->declared = 1;
        scop_decl = kill(stmt, array);
@@ -1661,6 +1819,7 @@ struct pet_expr *PetScan::extract_expr(CallExpr *expr)
                Expr *arg = expr->getArg(i);
                int is_addr = 0;
                pet_expr *main_arg;
+               Stmt::StmtClass sc;
 
                if (arg->getStmtClass() == Stmt::ImplicitCastExprClass) {
                        ImplicitCastExpr *ice = cast<ImplicitCastExpr>(arg);
@@ -1680,7 +1839,9 @@ struct pet_expr *PetScan::extract_expr(CallExpr *expr)
                                        pet_op_address_of, res->args[i]);
                if (!res->args[i])
                        goto error;
-               if (arg->getStmtClass() == Stmt::ArraySubscriptExprClass &&
+               sc = arg->getStmtClass();
+               if ((sc == Stmt::ArraySubscriptExprClass ||
+                    sc == Stmt::MemberExprClass) &&
                    array_depth(arg->getType().getTypePtr()) > 0)
                        is_addr = 1;
                if (is_addr && main_arg->type == pet_expr_access) {
@@ -1731,6 +1892,7 @@ struct pet_expr *PetScan::extract_expr(Expr *expr)
        case Stmt::ArraySubscriptExprClass:
        case Stmt::DeclRefExprClass:
        case Stmt::IntegerLiteralClass:
+       case Stmt::MemberExprClass:
                return extract_access_expr(expr);
        case Stmt::FloatingLiteralClass:
                return extract_expr(cast<FloatingLiteral>(expr));
@@ -5084,6 +5246,15 @@ static QualType get_array_type(ValueDecl *decl)
        return T;
 }
 
+/* Does "decl" have definition that we can keep track of in a pet_type?
+ */
+static bool has_printable_definition(RecordDecl *decl)
+{
+       if (!decl->getDeclName())
+               return false;
+       return decl->getLexicalDeclContext() == decl->getDeclContext();
+}
+
 /* Construct and return a pet_array corresponding to the variable "decl".
  * In particular, initialize array->extent to
  *
@@ -5091,8 +5262,16 @@ static QualType get_array_type(ValueDecl *decl)
  *
  * and then call set_upper_bounds to set the upper bounds on the indices
  * based on the type of the variable.
+ *
+ * If the base type is that of a record with a top-level definition and
+ * if "types" is not null, then the RecordDecl corresponding to the type
+ * is added to "types".
+ *
+ * If the base type is that of a record with no top-level definition,
+ * then we replace it by "<subfield>".
  */
-struct pet_array *PetScan::extract_array(isl_ctx *ctx, ValueDecl *decl)
+struct pet_array *PetScan::extract_array(isl_ctx *ctx, ValueDecl *decl,
+       lex_recorddecl_set *types)
 {
        struct pet_array *array;
        QualType qt = get_array_type(decl);
@@ -5121,24 +5300,144 @@ struct pet_array *PetScan::extract_array(isl_ctx *ctx, ValueDecl *decl)
                return NULL;
 
        name = base.getAsString();
+
+       if (types && base->isRecordType()) {
+               RecordDecl *decl = pet_clang_record_decl(base);
+               if (has_printable_definition(decl))
+                       types->insert(decl);
+               else
+                       name = "<subfield>";
+       }
+
        array->element_type = strdup(name.c_str());
+       array->element_is_record = base->isRecordType();
        array->element_size = decl->getASTContext().getTypeInfo(base).first / 8;
 
        return array;
 }
 
+/* Construct and return a pet_array corresponding to the sequence
+ * of declarations "decls".
+ * If the sequence contains a single declaration, then it corresponds
+ * to a simple array access.  Otherwise, it corresponds to a member access,
+ * with the declaration for the substructure following that of the containing
+ * structure in the sequence of declarations.
+ * We start with the outermost substructure and then combine it with
+ * information from the inner structures.
+ *
+ * Additionally, keep track of all required types in "types".
+ */
+struct pet_array *PetScan::extract_array(isl_ctx *ctx,
+       vector<ValueDecl *> decls, lex_recorddecl_set *types)
+{
+       struct pet_array *array;
+       vector<ValueDecl *>::iterator it;
+
+       it = decls.begin();
+
+       array = extract_array(ctx, *it, types);
+
+       for (++it; it != decls.end(); ++it) {
+               struct pet_array *parent;
+               const char *base_name, *field_name;
+               char *product_name;
+
+               parent = array;
+               array = extract_array(ctx, *it, types);
+               if (!array)
+                       return pet_array_free(parent);
+
+               base_name = isl_set_get_tuple_name(parent->extent);
+               field_name = isl_set_get_tuple_name(array->extent);
+               product_name = member_access_name(ctx, base_name, field_name);
+
+               array->extent = isl_set_product(isl_set_copy(parent->extent),
+                                               array->extent);
+               if (product_name)
+                       array->extent = isl_set_set_tuple_name(array->extent,
+                                                               product_name);
+               array->context = isl_set_intersect(array->context,
+                                               isl_set_copy(parent->context));
+
+               pet_array_free(parent);
+               free(product_name);
+
+               if (!array->extent || !array->context || !product_name)
+                       return pet_array_free(array);
+       }
+
+       return array;
+}
+
+/* Add a pet_type corresponding to "decl" to "scop, provided
+ * it is a member of "types" and it has not been added before
+ * (i.e., it is not a member of "types_done".
+ *
+ * Since we want the user to be able to print the types
+ * in the order in which they appear in the scop, we need to
+ * make sure that types of fields in a structure appear before
+ * that structure.  We therefore call ourselves recursively
+ * on the types of all record subfields.
+ */
+static struct pet_scop *add_type(isl_ctx *ctx, struct pet_scop *scop,
+       RecordDecl *decl, Preprocessor &PP, lex_recorddecl_set &types,
+       lex_recorddecl_set &types_done)
+{
+       string s;
+       llvm::raw_string_ostream S(s);
+       RecordDecl::field_iterator it;
+
+       if (types.find(decl) == types.end())
+               return scop;
+       if (types_done.find(decl) != types_done.end())
+               return scop;
+
+       for (it = decl->field_begin(); it != decl->field_end(); ++it) {
+               RecordDecl *record;
+               QualType type = it->getType();
+
+               if (!type->isRecordType())
+                       continue;
+               record = pet_clang_record_decl(type);
+               scop = add_type(ctx, scop, record, PP, types, types_done);
+       }
+
+       if (strlen(decl->getName().str().c_str()) == 0)
+               return scop;
+
+       decl->print(S, PrintingPolicy(PP.getLangOpts()));
+       S.str();
+
+       scop->types[scop->n_type] = pet_type_alloc(ctx,
+                                   decl->getName().str().c_str(), s.c_str());
+       if (!scop->types[scop->n_type])
+               return pet_scop_free(scop);
+
+       types_done.insert(decl);
+
+       scop->n_type++;
+
+       return scop;
+}
+
 /* Construct a list of pet_arrays, one for each array (or scalar)
  * accessed inside "scop", add this list to "scop" and return the result.
  *
  * The context of "scop" is updated with the intersection of
  * the contexts of all arrays, i.e., constraints on the parameters
  * that ensure that the arrays have a valid (non-negative) size.
+ *
+ * If the any of the extracted arrays refers to a member access,
+ * then also add the required types to "scop".
  */
 struct pet_scop *PetScan::scan_arrays(struct pet_scop *scop)
 {
        int i;
-       set<ValueDecl *> arrays;
-       set<ValueDecl *>::iterator it;
+       set<vector<ValueDecl *> > arrays;
+       set<vector<ValueDecl *> >::iterator it;
+       lex_recorddecl_set types;
+       lex_recorddecl_set types_done;
+       lex_recorddecl_set::iterator types_it;
        int n_array;
        struct pet_array **scop_arrays;
 
@@ -5159,7 +5458,8 @@ struct pet_scop *PetScan::scan_arrays(struct pet_scop *scop)
 
        for (it = arrays.begin(), i = 0; it != arrays.end(); ++it, ++i) {
                struct pet_array *array;
-               scop->arrays[n_array + i] = array = extract_array(ctx, *it);
+               array = extract_array(ctx, *it, &types);
+               scop->arrays[n_array + i] = array;
                if (!scop->arrays[n_array + i])
                        goto error;
                scop->n_array++;
@@ -5169,6 +5469,16 @@ struct pet_scop *PetScan::scan_arrays(struct pet_scop *scop)
                        goto error;
        }
 
+       if (types.size() == 0)
+               return scop;
+
+       scop->types = isl_alloc_array(ctx, struct pet_type *, types.size());
+       if (!scop->types)
+               goto error;
+
+       for (types_it = types.begin(); types_it != types.end(); ++types_it)
+               scop = add_type(ctx, scop, *types_it, PP, types, types_done);
+
        return scop;
 error:
        pet_scop_free(scop);
diff --git a/scan.h b/scan.h
index 8c52a65..5b8e29b 100644 (file)
--- a/scan.h
+++ b/scan.h
@@ -21,6 +21,20 @@ struct ScopLoc {
        unsigned end;
 };
 
+/* Compare two RecordDecl pointers based on their names.
+ */
+struct less_name {
+       bool operator()(const clang::RecordDecl *x,
+                       const clang::RecordDecl *y) {
+               return x->getNameAsString().compare(y->getNameAsString()) < 0;
+       }
+};
+
+/* A sorted set of RecordDecl pointers.  The actual order is not important,
+ * only that it is consistent across platforms.
+ */
+typedef std::set<clang::RecordDecl *, less_name> lex_recorddecl_set;
+
 struct PetScan {
        clang::Preprocessor &PP;
        clang::ASTContext &ast_context;
@@ -91,7 +105,11 @@ private:
        struct pet_scop *scan(clang::Stmt *stmt);
 
        struct pet_scop *scan_arrays(struct pet_scop *scop);
-       struct pet_array *extract_array(isl_ctx *ctx, clang::ValueDecl *decl);
+       struct pet_array *extract_array(isl_ctx *ctx, clang::ValueDecl *decl,
+               lex_recorddecl_set *types);
+       struct pet_array *extract_array(isl_ctx *ctx,
+               std::vector<clang::ValueDecl *> decls,
+               lex_recorddecl_set *types);
        struct pet_array *set_upper_bounds(struct pet_array *array,
                const clang::Type *type, int pos);
 
@@ -176,6 +194,7 @@ private:
        __isl_give isl_multi_pw_aff *extract_index(clang::ValueDecl *decl);
        __isl_give isl_multi_pw_aff *extract_index(
                clang::IntegerLiteral *expr);
+       __isl_give isl_multi_pw_aff *extract_index(clang::MemberExpr *expr);
 
        __isl_give isl_val *extract_int(clang::Expr *expr);
        __isl_give isl_val *extract_int(clang::ParenExpr *expr);
@@ -204,6 +223,7 @@ private:
        __isl_give isl_pw_aff *extract_affine(clang::ParenExpr *expr);
        __isl_give isl_pw_aff *extract_affine(clang::CallExpr *expr);
        __isl_give isl_pw_aff *extract_affine(clang::ArraySubscriptExpr *expr);
+       __isl_give isl_pw_aff *extract_affine(clang::MemberExpr *expr);
        __isl_give isl_pw_aff *extract_affine(clang::ConditionalOperator *expr);
 
        __isl_give isl_pw_aff *extract_implicit_condition(clang::Expr *expr);
diff --git a/scop.c b/scop.c
index bdb99c0..81c2f14 100644 (file)
--- a/scop.c
+++ b/scop.c
@@ -181,13 +181,28 @@ struct pet_expr *pet_expr_from_index(__isl_take isl_multi_pw_aff *index)
 
 /* Extend the range of "access" with "n" dimensions, retaining
  * the tuple identifier on this range.
+ *
+ * If "access" represents a member access, then extend the range
+ * of the member.
  */
 static __isl_give isl_map *extend_range(__isl_take isl_map *access, int n)
 {
        isl_id *id;
 
        id = isl_map_get_tuple_id(access, isl_dim_out);
-       access = isl_map_add_dims(access, isl_dim_out, n);
+
+       if (!isl_map_range_is_wrapping(access)) {
+               access = isl_map_add_dims(access, isl_dim_out, n);
+       } else {
+               isl_map *domain;
+
+               domain = isl_map_copy(access);
+               domain = isl_map_range_factor_domain(domain);
+               access = isl_map_range_factor_range(access);
+               access = extend_range(access, n);
+               access = isl_map_range_product(domain, access);
+       }
+
        access = isl_map_set_tuple_id(access, isl_dim_out, id);
 
        return access;
@@ -522,6 +537,9 @@ int pet_expr_is_affine(struct pet_expr *expr)
 }
 
 /* Return the identifier of the array accessed by "expr".
+ *
+ * If "expr" represents a member access, then return the identifier
+ * of the outer structure array.
  */
 __isl_give isl_id *pet_expr_access_get_id(struct pet_expr *expr)
 {
@@ -529,6 +547,21 @@ __isl_give isl_id *pet_expr_access_get_id(struct pet_expr *expr)
                return NULL;
        if (expr->type != pet_expr_access)
                return NULL;
+
+       if (isl_map_range_is_wrapping(expr->acc.access)) {
+               isl_space *space;
+               isl_id *id;
+
+               space = isl_map_get_space(expr->acc.access);
+               space = isl_space_range(space);
+               while (space && isl_space_is_wrapping(space))
+                       space = isl_space_domain(isl_space_unwrap(space));
+               id = isl_space_get_tuple_id(space, isl_dim_set);
+               isl_space_free(space);
+
+               return id;
+       }
+
        return isl_map_get_tuple_id(expr->acc.access, isl_dim_out);
 }
 
@@ -937,8 +970,9 @@ void pet_array_dump(struct pet_array *array)
        isl_set_dump(array->context);
        isl_set_dump(array->extent);
        isl_set_dump(array->value_bounds);
-       fprintf(stderr, "%s %s\n", array->element_type,
-               array->live_out ? "live-out" : "");
+       fprintf(stderr, "%s%s%s\n", array->element_type,
+               array->element_is_record ? " element-is-record" : "",
+               array->live_out ? " live-out" : "");
 }
 
 /* Alloc a pet_scop structure, with extra room for information that
@@ -1552,6 +1586,8 @@ int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
                return 0;
        if (strcmp(array1->element_type, array2->element_type))
                return 0;
+       if (array1->element_is_record != array2->element_is_record)
+               return 0;
        if (array1->live_out != array2->live_out)
                return 0;
        if (array1->uniquely_defined != array2->uniquely_defined)
@@ -1837,6 +1873,7 @@ static __isl_give isl_multi_pw_aff *index_internalize_iv(
 
 /* Does the index expression "index" reference a virtual array, i.e.,
  * one with user pointer equal to NULL?
+ * A virtual array does not have any members.
  */
 static int index_is_virtual_array(__isl_keep isl_multi_pw_aff *index)
 {
@@ -1845,6 +1882,8 @@ static int index_is_virtual_array(__isl_keep isl_multi_pw_aff *index)
 
        if (!isl_multi_pw_aff_has_tuple_id(index, isl_dim_out))
                return 0;
+       if (isl_multi_pw_aff_range_is_wrapping(index))
+               return 0;
        id = isl_multi_pw_aff_get_tuple_id(index, isl_dim_out);
        is_virtual = !isl_id_get_user(id);
        isl_id_free(id);
@@ -1854,6 +1893,7 @@ static int index_is_virtual_array(__isl_keep isl_multi_pw_aff *index)
 
 /* Does the access relation "access" reference a virtual array, i.e.,
  * one with user pointer equal to NULL?
+ * A virtual array does not have any members.
  */
 static int access_is_virtual_array(__isl_keep isl_map *access)
 {
@@ -1862,6 +1902,8 @@ static int access_is_virtual_array(__isl_keep isl_map *access)
 
        if (!isl_map_has_tuple_id(access, isl_dim_out))
                return 0;
+       if (isl_map_range_is_wrapping(access))
+               return 0;
        id = isl_map_get_tuple_id(access, isl_dim_out);
        is_virtual = !isl_id_get_user(id);
        isl_id_free(id);
@@ -3506,6 +3548,59 @@ static int is_kill(struct pet_stmt *stmt)
        return stmt->body->op == pet_op_kill;
 }
 
+/* Compute a mapping from all arrays (of structs) in scop
+ * to their innermost arrays.
+ *
+ * In particular, for each array of a primitive type, the result
+ * contains the identity mapping on that array.
+ * For each array involving member accesses, the result
+ * contains a mapping from the elements of any intermediate array of structs
+ * to all corresponding elements of the innermost nested arrays.
+ */
+static __isl_give isl_union_map *compute_to_inner(struct pet_scop *scop)
+{
+       int i;
+       isl_union_map *to_inner;
+
+       to_inner = isl_union_map_empty(isl_set_get_space(scop->context));
+
+       for (i = 0; i < scop->n_array; ++i) {
+               struct pet_array *array = scop->arrays[i];
+               isl_set *set;
+               isl_map *map, *gist;
+
+               if (array->element_is_record)
+                       continue;
+
+               map = isl_set_identity(isl_set_copy(array->extent));
+
+               set = isl_map_domain(isl_map_copy(map));
+               gist = isl_map_copy(map);
+               gist = isl_map_gist_domain(gist, isl_set_copy(set));
+               to_inner = isl_union_map_add_map(to_inner, gist);
+
+               while (set && isl_set_is_wrapping(set)) {
+                       isl_id *id;
+                       isl_map *wrapped;
+
+                       id = isl_set_get_tuple_id(set);
+                       wrapped = isl_set_unwrap(set);
+                       wrapped = isl_map_domain_map(wrapped);
+                       wrapped = isl_map_set_tuple_id(wrapped, isl_dim_in, id);
+                       map = isl_map_apply_domain(map, wrapped);
+                       set = isl_map_domain(isl_map_copy(map));
+                       gist = isl_map_copy(map);
+                       gist = isl_map_gist_domain(gist, isl_set_copy(set));
+                       to_inner = isl_union_map_add_map(to_inner, gist);
+               }
+
+               isl_set_free(set);
+               isl_map_free(map);
+       }
+
+       return to_inner;
+}
+
 /* Collect and return all read access relations (if "read" is set)
  * and/or all write access relations (if "write" is set) in "scop".
  * If "kill" is set, then we only add the arguments of kill operations.
@@ -3513,6 +3608,8 @@ static int is_kill(struct pet_stmt *stmt)
  * performed.  Otherwise, we add all potential accesses.
  * If "tag" is set, then the access relations are tagged with
  * the corresponding reference identifiers.
+ * For accesses to structures, the returned access relation accesses
+ * all individual fields in the structures.
  */
 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
        int read, int write, int kill, int must, int tag)
@@ -3520,6 +3617,7 @@ static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
        int i;
        isl_union_map *accesses;
        isl_union_set *arrays;
+       isl_union_map *to_inner;
 
        if (!scop)
                return NULL;
@@ -3547,6 +3645,9 @@ static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
        }
        accesses = isl_union_map_intersect_range(accesses, arrays);
 
+       to_inner = compute_to_inner(scop);
+       accesses = isl_union_map_apply_range(accesses, to_inner);
+
        return accesses;
 }
 
index 1a9563e..19f9202 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2011 Leiden University. All rights reserved.
+ * Copyright 2013 Ecole Normale Superieure. All rights reserved.
  * 
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  */ 
 
 #include <set>
+#include <vector>
 
+#include "clang.h"
 #include "scop_plus.h"
 
 using namespace std;
 using namespace clang;
 
-/* If the array being accessed has a NULL ValueDecl, then it
+/* And the sequence of nested arrays of structures "ancestors"
+ * to "arrays".  The final element in the sequence may be a leaf
+ * and may therefore refer to a primitive type rather than a record type.
+ *
+ * Futhermore, if the innermost array in the sequence is an array of structures
+ * then recursively call collect_sub_arrays for all subfields of this
+ * structure.
+ */
+static void collect_sub_arrays(ValueDecl *decl, vector<ValueDecl *> ancestors,
+       set<vector<ValueDecl *> > &arrays)
+{
+       QualType type = decl->getType();
+       RecordDecl *record;
+       RecordDecl::field_iterator it;
+
+       arrays.insert(ancestors);
+
+       type = pet_clang_base_type(type);
+
+       if (!type->isRecordType())
+               return;
+
+       record = pet_clang_record_decl(type);
+
+       for (it = record->field_begin(); it != record->field_end(); ++it) {
+               FieldDecl *field = *it;
+               bool anonymous = field->isAnonymousStructOrUnion();
+
+               if (!anonymous)
+                       ancestors.push_back(field);
+               collect_sub_arrays(field, ancestors, arrays);
+               if (!anonymous)
+                       ancestors.pop_back();
+       }
+}
+
+/* Extract one or more sequences of declarations from the access expression
+ * "expr" and them to "arrays".
+ *
+ * If "expr" represents an array access, then the extracted sequence
+ * contains a single element corresponding to the array declaration.
+ * Otherwise, if "expr" represents a member access, then the extracted
+ * sequences contain an element for the outer array of structures and
+ * for each nested array or scalar.  One such sequence is (recursively)
+ * added for each member of the accessed outer array.
+ *
+ * If the array being accessed has a NULL ValueDecl, then it
  * is a virtual scalar.  We don't need to collect such scalars
  * because they are added to the scop of the statement writing
  * to the scalar.
  */
 static void access_collect_arrays(struct pet_expr *expr,
-       set<ValueDecl *> &arrays)
+       set<vector<ValueDecl *> > &arrays)
 {
        isl_id *id;
+       isl_space *space;
        ValueDecl *decl;
+       vector<ValueDecl *> ancestors;
 
        if (pet_expr_is_affine(expr))
                return;
-       id = pet_expr_access_get_id(expr);
+
+       space = isl_map_get_space(expr->acc.access);
+       space = isl_space_range(space);
+
+       while (space && isl_space_is_wrapping(space))
+               space = isl_space_domain(isl_space_unwrap(space));
+
+       id = isl_space_get_tuple_id(space, isl_dim_set);
+       isl_space_free(space);
        if (!id)
                return;
 
        decl = (ValueDecl *)isl_id_get_user(id);
        isl_id_free(id);
 
-       if (decl)
-               arrays.insert(decl);
+       if (!decl)
+               return;
+
+       ancestors.push_back(decl);
+       collect_sub_arrays(decl, ancestors, arrays);
 }
 
-static void expr_collect_arrays(struct pet_expr *expr, set<ValueDecl *> &arrays)
+static void expr_collect_arrays(struct pet_expr *expr,
+       set<vector<ValueDecl *> > &arrays)
 {
        if (!expr)
                return;
@@ -74,7 +137,8 @@ static void expr_collect_arrays(struct pet_expr *expr, set<ValueDecl *> &arrays)
                access_collect_arrays(expr, arrays);
 }
 
-static void stmt_collect_arrays(struct pet_stmt *stmt, set<ValueDecl *> &arrays)
+static void stmt_collect_arrays(struct pet_stmt *stmt,
+       set<vector<ValueDecl *> > &arrays)
 {
        if (!stmt)
                return;
@@ -88,8 +152,16 @@ static void stmt_collect_arrays(struct pet_stmt *stmt, set<ValueDecl *> &arrays)
 /* Collect the set of all accessed arrays (or scalars) in "scop",
  * except those that already appear in scop->arrays,
  * and put them in "arrays".
+ *
+ * Each accessed array is represented by a sequence of nested
+ * array declarations, one for the outer array of structures
+ * and one for each member access.
+ *
+ * The arrays that already appear in scop->arrays are assumed
+ * to be simple arrays, represented by a sequence of a single element.
  */
-void pet_scop_collect_arrays(struct pet_scop *scop, set<ValueDecl *> &arrays)
+void pet_scop_collect_arrays(struct pet_scop *scop,
+       set<vector<ValueDecl *> > &arrays)
 {
        if (!scop)
                return;
@@ -99,10 +171,14 @@ void pet_scop_collect_arrays(struct pet_scop *scop, set<ValueDecl *> &arrays)
 
        for (int i = 0; i < scop->n_array; ++i) {
                ValueDecl *decl;
+               vector<ValueDecl *> ancestors;
+
                isl_id *id = isl_set_get_tuple_id(scop->arrays[i]->extent);
                decl = (ValueDecl *)isl_id_get_user(id);
                isl_id_free(id);
 
-               arrays.erase(decl);
+               ancestors.push_back(decl);
+
+               arrays.erase(ancestors);
        }
 }
index e788e1a..aaee707 100644 (file)
@@ -2,11 +2,12 @@
 #define PET_SCOP_PLUS_H
 
 #include <set>
+#include <vector>
 #include <clang/AST/Decl.h>
 
 #include "scop.h"
 
 void pet_scop_collect_arrays(struct pet_scop *scop,
-                               std::set<clang::ValueDecl *> &arrays);
+       std::set<std::vector<clang::ValueDecl *> > &arrays);
 
 #endif
diff --git a/tests/struct1.c b/tests/struct1.c
new file mode 100644 (file)
index 0000000..ac23aec
--- /dev/null
@@ -0,0 +1,12 @@
+struct s {
+       int a;
+};
+
+void foo()
+{
+       struct s s;
+
+#pragma scop
+       s.a = 5;
+#pragma endscop
+}
diff --git a/tests/struct1.scop b/tests/struct1.scop
new file mode 100644 (file)
index 0000000..49e03ae
--- /dev/null
@@ -0,0 +1,36 @@
+start: 50
+end: 89
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    int a;\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[] }'
+  element_type: struct s
+  element_size: 4
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_a[s[] -> a[]] }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 10
+  domain: '{ S_0[] }'
+  schedule: '{ S_0[] -> [0] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[] -> s_a[s[] -> a[]] }'
+      index: '{ S_0[] -> s_a[s[] -> a[]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: access
+      relation: '{ S_0[] -> [5] }'
+      index: '{ S_0[] -> [(5)] }'
+      reference: __pet_ref_1
+      read: 1
+      write: 0
diff --git a/tests/struct10.c b/tests/struct10.c
new file mode 100644 (file)
index 0000000..8b13c22
--- /dev/null
@@ -0,0 +1,10 @@
+struct s {
+       int a;
+};
+
+void foo(int A[10], struct s s)
+{
+#pragma scop
+       A[s.a] = 5;
+#pragma endscop
+}
diff --git a/tests/struct10.scop b/tests/struct10.scop
new file mode 100644 (file)
index 0000000..bde1b5b
--- /dev/null
@@ -0,0 +1,47 @@
+start: 57
+end: 99
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    int a;\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ A[i0] : i0 >= 0 }'
+  element_type: int
+  element_size: 4
+- context: '{  :  }'
+  extent: '{ s[] }'
+  element_type: struct s
+  element_size: 4
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_a[s[] -> a[]] }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 8
+  domain: '{ S_0[] }'
+  schedule: '{ S_0[] -> [0] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ [S_0[] -> [i0]] -> A[i0] : i0 >= 0 }'
+      index: '{ [S_0[] -> [i0]] -> A[((i0) : i0 >= 0)] }'
+      reference: __pet_ref_1
+      read: 0
+      write: 1
+      arguments:
+      - type: access
+        relation: '{ S_0[] -> s_a[s[] -> a[]] }'
+        index: '{ S_0[] -> s_a[s[] -> a[]] }'
+        reference: __pet_ref_0
+        read: 1
+        write: 0
+    - type: access
+      relation: '{ S_0[] -> [5] }'
+      index: '{ S_0[] -> [(5)] }'
+      reference: __pet_ref_2
+      read: 1
+      write: 0
diff --git a/tests/struct2.c b/tests/struct2.c
new file mode 100644 (file)
index 0000000..2af9f93
--- /dev/null
@@ -0,0 +1,14 @@
+struct s {
+       int a;
+};
+
+void foo()
+{
+       struct s s[10][20];
+
+#pragma scop
+       for (int i = 0; i < 10; ++i)
+               for (int j = 0; j < 20; ++j)
+                       s[i][j].a = 5;
+#pragma endscop
+}
diff --git a/tests/struct2.scop b/tests/struct2.scop
new file mode 100644 (file)
index 0000000..f26ef15
--- /dev/null
@@ -0,0 +1,37 @@
+start: 58
+end: 166
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    int a;\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[i0, i1] : i0 >= 0 and i1 >= 0 and i0 <= 9 and i1 <= 19 }'
+  element_type: struct s
+  element_size: 4
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_a[s[i0, i1] -> a[]] : i0 >= 0 and i1 >= 0 and i0 <= 9 and i1 <= 19
+    }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 12
+  domain: '{ S_0[i, j] : i >= 0 and i <= 9 and j >= 0 and j <= 19 }'
+  schedule: '{ S_0[i, j] -> [0, i, j] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[i, j] -> s_a[s[i, j] -> a[]] }'
+      index: '{ S_0[i, j] -> s_a[s[(i), (j)] -> a[]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: access
+      relation: '{ S_0[i, j] -> [5] }'
+      index: '{ S_0[i, j] -> [(5)] }'
+      reference: __pet_ref_1
+      read: 1
+      write: 0
diff --git a/tests/struct3.c b/tests/struct3.c
new file mode 100644 (file)
index 0000000..e2f0cf8
--- /dev/null
@@ -0,0 +1,16 @@
+struct s {
+       int a[30][40];
+};
+
+void foo()
+{
+       struct s s[10][20];
+
+#pragma scop
+       for (int i = 0; i < 10; ++i)
+               for (int j = 0; j < 20; ++j)
+                       for (int k = 0; k < 30; ++k)
+                               for (int l = 0; l < 40; ++l)
+                                       s[i][j].a[k][l] = i + j + k + l;
+#pragma endscop
+}
diff --git a/tests/struct3.scop b/tests/struct3.scop
new file mode 100644 (file)
index 0000000..d4e6b1e
--- /dev/null
@@ -0,0 +1,65 @@
+start: 66
+end: 259
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    int a[30][40];\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[i0, i1] : i0 >= 0 and i1 >= 0 and i0 <= 9 and i1 <= 19 }'
+  element_type: struct s
+  element_size: 4800
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_a[s[i0, i1] -> a[i2, i3]] : i0 >= 0 and i1 >= 0 and i0 <= 9 and i1
+    <= 19 and i2 >= 0 and i3 >= 0 and i2 <= 29 and i3 <= 39 }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 14
+  domain: '{ S_0[i, j, k, l] : i >= 0 and i <= 9 and j >= 0 and j <= 19 and k >= 0
+    and k <= 29 and l >= 0 and l <= 39 }'
+  schedule: '{ S_0[i, j, k, l] -> [0, i, j, k, l] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[i, j, k, l] -> s_a[s[i, j] -> a[k, l]] }'
+      index: '{ S_0[i, j, k, l] -> s_a[s[(i), (j)] -> a[(k), (l)]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: binary
+      operation: +
+      arguments:
+      - type: binary
+        operation: +
+        arguments:
+        - type: binary
+          operation: +
+          arguments:
+          - type: access
+            relation: '{ S_0[i, j, k, l] -> [i] }'
+            index: '{ S_0[i, j, k, l] -> [(i)] }'
+            reference: __pet_ref_1
+            read: 1
+            write: 0
+          - type: access
+            relation: '{ S_0[i, j, k, l] -> [j] }'
+            index: '{ S_0[i, j, k, l] -> [(j)] }'
+            reference: __pet_ref_2
+            read: 1
+            write: 0
+        - type: access
+          relation: '{ S_0[i, j, k, l] -> [k] }'
+          index: '{ S_0[i, j, k, l] -> [(k)] }'
+          reference: __pet_ref_3
+          read: 1
+          write: 0
+      - type: access
+        relation: '{ S_0[i, j, k, l] -> [l] }'
+        index: '{ S_0[i, j, k, l] -> [(l)] }'
+        reference: __pet_ref_4
+        read: 1
+        write: 0
diff --git a/tests/struct4.c b/tests/struct4.c
new file mode 100644 (file)
index 0000000..2a68673
--- /dev/null
@@ -0,0 +1,16 @@
+struct s {
+       struct {
+               int a[10];
+       } f[10];
+};
+
+void foo()
+{
+       struct s s;
+
+#pragma scop
+       for (int i = 0; i < 10; ++i)
+               for (int j = 0; j < 10; ++j)
+                       s.f[i].a[j] = i * j;
+#pragma endscop
+}
diff --git a/tests/struct4.scop b/tests/struct4.scop
new file mode 100644 (file)
index 0000000..cd8976a
--- /dev/null
@@ -0,0 +1,51 @@
+start: 75
+end: 189
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    struct {\n        int a[10];\n    } f[10];\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[] }'
+  element_type: struct s
+  element_size: 400
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_f[s[] -> f[i0]] : i0 >= 0 and i0 <= 9 }'
+  element_type: <subfield>
+  element_size: 40
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_f_a[s_f[s[] -> f[i0]] -> a[i1]] : i0 >= 0 and i0 <= 9 and i1 >= 0 and
+    i1 <= 9 }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 14
+  domain: '{ S_0[i, j] : i >= 0 and i <= 9 and j >= 0 and j <= 9 }'
+  schedule: '{ S_0[i, j] -> [0, i, j] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[i, j] -> s_f_a[s_f[s[] -> f[i]] -> a[j]] }'
+      index: '{ S_0[i, j] -> s_f_a[s_f[s[] -> f[(i)]] -> a[(j)]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: binary
+      operation: '*'
+      arguments:
+      - type: access
+        relation: '{ S_0[i, j] -> [i] }'
+        index: '{ S_0[i, j] -> [(i)] }'
+        reference: __pet_ref_1
+        read: 1
+        write: 0
+      - type: access
+        relation: '{ S_0[i, j] -> [j] }'
+        index: '{ S_0[i, j] -> [(j)] }'
+        reference: __pet_ref_2
+        read: 1
+        write: 0
diff --git a/tests/struct5.c b/tests/struct5.c
new file mode 100644 (file)
index 0000000..e9a35c8
--- /dev/null
@@ -0,0 +1,16 @@
+struct s {
+       struct f {
+               int a[10];
+       } f[10];
+};
+
+void foo()
+{
+       struct s s;
+
+#pragma scop
+       for (int i = 0; i < 10; ++i)
+               for (int j = 0; j < 10; ++j)
+                       s.f[i].a[j] = i * j;
+#pragma endscop
+}
diff --git a/tests/struct5.scop b/tests/struct5.scop
new file mode 100644 (file)
index 0000000..a5cff70
--- /dev/null
@@ -0,0 +1,52 @@
+start: 77
+end: 191
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    struct f {\n        int a[10];\n    };\n    struct
+    f f[10];\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[] }'
+  element_type: struct s
+  element_size: 400
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_f[s[] -> f[i0]] : i0 >= 0 and i0 <= 9 }'
+  element_type: <subfield>
+  element_size: 40
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_f_a[s_f[s[] -> f[i0]] -> a[i1]] : i0 >= 0 and i0 <= 9 and i1 >= 0 and
+    i1 <= 9 }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 14
+  domain: '{ S_0[i, j] : i >= 0 and i <= 9 and j >= 0 and j <= 9 }'
+  schedule: '{ S_0[i, j] -> [0, i, j] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[i, j] -> s_f_a[s_f[s[] -> f[i]] -> a[j]] }'
+      index: '{ S_0[i, j] -> s_f_a[s_f[s[] -> f[(i)]] -> a[(j)]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: binary
+      operation: '*'
+      arguments:
+      - type: access
+        relation: '{ S_0[i, j] -> [i] }'
+        index: '{ S_0[i, j] -> [(i)] }'
+        reference: __pet_ref_1
+        read: 1
+        write: 0
+      - type: access
+        relation: '{ S_0[i, j] -> [j] }'
+        index: '{ S_0[i, j] -> [(j)] }'
+        reference: __pet_ref_2
+        read: 1
+        write: 0
diff --git a/tests/struct6.c b/tests/struct6.c
new file mode 100644 (file)
index 0000000..6f24833
--- /dev/null
@@ -0,0 +1,12 @@
+struct s {
+       int a;
+};
+
+void foo()
+{
+       struct s *s;
+
+#pragma scop
+       s->a = 5;
+#pragma endscop
+}
diff --git a/tests/struct6.scop b/tests/struct6.scop
new file mode 100644 (file)
index 0000000..b8a0cd5
--- /dev/null
@@ -0,0 +1,36 @@
+start: 51
+end: 91
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    int a;\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[i0] : i0 >= 0 }'
+  element_type: struct s
+  element_size: 4
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_a[s[i0] -> a[]] : i0 >= 0 }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 10
+  domain: '{ S_0[] }'
+  schedule: '{ S_0[] -> [0] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[] -> s_a[s[0] -> a[]] }'
+      index: '{ S_0[] -> s_a[s[(0)] -> a[]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: access
+      relation: '{ S_0[] -> [5] }'
+      index: '{ S_0[] -> [(5)] }'
+      reference: __pet_ref_1
+      read: 1
+      write: 0
diff --git a/tests/struct7.c b/tests/struct7.c
new file mode 100644 (file)
index 0000000..994d2e4
--- /dev/null
@@ -0,0 +1,18 @@
+struct scomplex {
+       float re;
+       float im;
+};
+
+struct pair {
+       struct scomplex a;
+       struct scomplex b;
+};
+
+void foo()
+{
+       struct pair p;
+
+#pragma scop
+       p.a.re = p.b.im;
+#pragma endscop
+}
diff --git a/tests/struct7.scop b/tests/struct7.scop
new file mode 100644 (file)
index 0000000..2ba4983
--- /dev/null
@@ -0,0 +1,60 @@
+start: 132
+end: 179
+context: '{  :  }'
+types:
+- name: scomplex
+  definition: "struct scomplex {\n    float re;\n    float im;\n}"
+- name: pair
+  definition: "struct pair {\n    struct scomplex a;\n    struct scomplex b;\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ p[] }'
+  element_type: struct pair
+  element_size: 16
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ p_a[p[] -> a[]] }'
+  element_type: struct scomplex
+  element_size: 8
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ p_a_re[p_a[p[] -> a[]] -> re[]] }'
+  element_type: float
+  element_size: 4
+- context: '{  :  }'
+  extent: '{ p_a_im[p_a[p[] -> a[]] -> im[]] }'
+  element_type: float
+  element_size: 4
+- context: '{  :  }'
+  extent: '{ p_b[p[] -> b[]] }'
+  element_type: struct scomplex
+  element_size: 8
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ p_b_re[p_b[p[] -> b[]] -> re[]] }'
+  element_type: float
+  element_size: 4
+- context: '{  :  }'
+  extent: '{ p_b_im[p_b[p[] -> b[]] -> im[]] }'
+  element_type: float
+  element_size: 4
+statements:
+- line: 16
+  domain: '{ S_0[] }'
+  schedule: '{ S_0[] -> [0] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[] -> p_a_re[p_a[p[] -> a[]] -> re[]] }'
+      index: '{ S_0[] -> p_a_re[p_a[p[] -> a[]] -> re[]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: access
+      relation: '{ S_0[] -> p_b_im[p_b[p[] -> b[]] -> im[]] }'
+      index: '{ S_0[] -> p_b_im[p_b[p[] -> b[]] -> im[]] }'
+      reference: __pet_ref_1
+      read: 1
+      write: 0
diff --git a/tests/struct8.c b/tests/struct8.c
new file mode 100644 (file)
index 0000000..0bc49c4
--- /dev/null
@@ -0,0 +1,20 @@
+struct s {
+       struct {
+               struct {
+                       int a[10];
+               } f[10];
+               int b;
+       };
+};
+
+void foo()
+{
+       struct s s;
+
+#pragma scop
+       for (int i = 0; i < 10; ++i)
+               for (int j = 0; j < 10; ++j)
+                       s.f[i].a[j] = i * j;
+       s.b = 1;
+#pragma endscop
+}
diff --git a/tests/struct8.scop b/tests/struct8.scop
new file mode 100644 (file)
index 0000000..b400a18
--- /dev/null
@@ -0,0 +1,75 @@
+start: 101
+end: 225
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    struct {\n        struct {\n            int a[10];\n
+    \       } f[10];\n        int b;\n    };\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[] }'
+  element_type: struct s
+  element_size: 404
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_f[s[] -> f[i0]] : i0 >= 0 and i0 <= 9 }'
+  element_type: <subfield>
+  element_size: 40
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_f_a[s_f[s[] -> f[i0]] -> a[i1]] : i0 >= 0 and i0 <= 9 and i1 >= 0 and
+    i1 <= 9 }'
+  element_type: int
+  element_size: 4
+- context: '{  :  }'
+  extent: '{ s_b[s[] -> b[]] }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 17
+  domain: '{ S_0[i, j] : i >= 0 and i <= 9 and j >= 0 and j <= 9 }'
+  schedule: '{ S_0[i, j] -> [0, i, j] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_0[i, j] -> s_f_a[s_f[s[] -> f[i]] -> a[j]] }'
+      index: '{ S_0[i, j] -> s_f_a[s_f[s[] -> f[(i)]] -> a[(j)]] }'
+      reference: __pet_ref_0
+      read: 0
+      write: 1
+    - type: binary
+      operation: '*'
+      arguments:
+      - type: access
+        relation: '{ S_0[i, j] -> [i] }'
+        index: '{ S_0[i, j] -> [(i)] }'
+        reference: __pet_ref_1
+        read: 1
+        write: 0
+      - type: access
+        relation: '{ S_0[i, j] -> [j] }'
+        index: '{ S_0[i, j] -> [(j)] }'
+        reference: __pet_ref_2
+        read: 1
+        write: 0
+- line: 18
+  domain: '{ S_1[] }'
+  schedule: '{ S_1[] -> [1] }'
+  body:
+    type: binary
+    operation: =
+    arguments:
+    - type: access
+      relation: '{ S_1[] -> s_b[s[] -> b[]] }'
+      index: '{ S_1[] -> s_b[s[] -> b[]] }'
+      reference: __pet_ref_3
+      read: 0
+      write: 1
+    - type: access
+      relation: '{ S_1[] -> [1] }'
+      index: '{ S_1[] -> [(1)] }'
+      reference: __pet_ref_4
+      read: 1
+      write: 0
diff --git a/tests/struct9.c b/tests/struct9.c
new file mode 100644 (file)
index 0000000..25e832c
--- /dev/null
@@ -0,0 +1,23 @@
+void f1(int a);
+void f2(int a[40]);
+void f3(int a[30][40]);
+
+struct s {
+       int a[30][40];
+};
+
+void foo()
+{
+       struct s s[10][20];
+
+#pragma scop
+       for (int i = 0; i < 10; ++i)
+               for (int j = 0; j < 20; ++j)
+                       for (int k = 0; k < 30; ++k)
+                               for (int l = 0; l < 40; ++l) {
+                                       f1(s[i][j].a[k][l]);
+                                       f2(s[i][j].a[k]);
+                                       f3(s[i][j].a);
+                               }
+#pragma endscop
+}
diff --git a/tests/struct9.scop b/tests/struct9.scop
new file mode 100644 (file)
index 0000000..939c687
--- /dev/null
@@ -0,0 +1,60 @@
+start: 127
+end: 359
+context: '{  :  }'
+types:
+- name: s
+  definition: "struct s {\n    int a[30][40];\n}"
+arrays:
+- context: '{  :  }'
+  extent: '{ s[i0, i1] : i0 >= 0 and i1 >= 0 and i0 <= 9 and i1 <= 19 }'
+  element_type: struct s
+  element_size: 4800
+  element_is_record: 1
+- context: '{  :  }'
+  extent: '{ s_a[s[i0, i1] -> a[i2, i3]] : i0 >= 0 and i1 >= 0 and i0 <= 9 and i1
+    <= 19 and i2 >= 0 and i3 >= 0 and i2 <= 29 and i3 <= 39 }'
+  element_type: int
+  element_size: 4
+statements:
+- line: 18
+  domain: '{ S_0[i, j, k, l] : i >= 0 and i <= 9 and j >= 0 and j <= 19 and k >= 0
+    and k <= 29 and l >= 0 and l <= 39 }'
+  schedule: '{ S_0[i, j, k, l] -> [0, i, j, k, l, 0] }'
+  body:
+    type: call
+    name: f1
+    arguments:
+    - type: access
+      relation: '{ S_0[i, j, k, l] -> s_a[s[i, j] -> a[k, l]] }'
+      index: '{ S_0[i, j, k, l] -> s_a[s[(i), (j)] -> a[(k), (l)]] }'
+      reference: __pet_ref_0
+      read: 1
+      write: 0
+- line: 19
+  domain: '{ S_1[i, j, k, l] : i >= 0 and i <= 9 and j >= 0 and j <= 19 and k >= 0
+    and k <= 29 and l >= 0 and l <= 39 }'
+  schedule: '{ S_1[i, j, k, l] -> [0, i, j, k, l, 1] }'
+  body:
+    type: call
+    name: f2
+    arguments:
+    - type: access
+      relation: '{ S_1[i, j, k, l] -> s_a[s[i, j] -> a[k, o3]] }'
+      index: '{ S_1[i, j, k, l] -> s_a[s[(i), (j)] -> a[(k)]] }'
+      reference: __pet_ref_1
+      read: 0
+      write: 1
+- line: 20
+  domain: '{ S_2[i, j, k, l] : i >= 0 and i <= 9 and j >= 0 and j <= 19 and k >= 0
+    and k <= 29 and l >= 0 and l <= 39 }'
+  schedule: '{ S_2[i, j, k, l] -> [0, i, j, k, l, 2] }'
+  body:
+    type: call
+    name: f3
+    arguments:
+    - type: access
+      relation: '{ S_2[i, j, k, l] -> s_a[s[i, j] -> a[o2, o3]] }'
+      index: '{ S_2[i, j, k, l] -> s_a[s[(i), (j)] -> a[]] }'
+      reference: __pet_ref_2
+      read: 0
+      write: 1