From ab7a70089011bf3c834f9a16ae6a594956cbe45a Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Thu, 8 Aug 2013 14:50:08 +0200 Subject: [PATCH] add support for structs 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 --- clang.cc | 11 ++ clang.h | 1 + emit.c | 5 + include/pet.h | 10 ++ parse.c | 4 + scan.cc | 322 +++++++++++++++++++++++++++++++++++++++++++++++++++- scan.h | 22 +++- scop.c | 107 ++++++++++++++++- scop_plus.cc | 94 +++++++++++++-- scop_plus.h | 3 +- tests/struct1.c | 12 ++ tests/struct1.scop | 36 ++++++ tests/struct10.c | 10 ++ tests/struct10.scop | 47 ++++++++ tests/struct2.c | 14 +++ tests/struct2.scop | 37 ++++++ tests/struct3.c | 16 +++ tests/struct3.scop | 65 +++++++++++ tests/struct4.c | 16 +++ tests/struct4.scop | 51 +++++++++ tests/struct5.c | 16 +++ tests/struct5.scop | 52 +++++++++ tests/struct6.c | 12 ++ tests/struct6.scop | 36 ++++++ tests/struct7.c | 18 +++ tests/struct7.scop | 60 ++++++++++ tests/struct8.c | 20 ++++ tests/struct8.scop | 75 ++++++++++++ tests/struct9.c | 23 ++++ tests/struct9.scop | 60 ++++++++++ 30 files changed, 1235 insertions(+), 20 deletions(-) create mode 100644 tests/struct1.c create mode 100644 tests/struct1.scop create mode 100644 tests/struct10.c create mode 100644 tests/struct10.scop create mode 100644 tests/struct2.c create mode 100644 tests/struct2.scop create mode 100644 tests/struct3.c create mode 100644 tests/struct3.scop create mode 100644 tests/struct4.c create mode 100644 tests/struct4.scop create mode 100644 tests/struct5.c create mode 100644 tests/struct5.scop create mode 100644 tests/struct6.c create mode 100644 tests/struct6.scop create mode 100644 tests/struct7.c create mode 100644 tests/struct7.scop create mode 100644 tests/struct8.c create mode 100644 tests/struct8.scop create mode 100644 tests/struct9.c create mode 100644 tests/struct9.scop diff --git a/clang.cc b/clang.cc index fca093b..a04e111 100644 --- 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(type); + return record->getDecl(); +} diff --git a/clang.h b/clang.h index 8592ed8..f69bfb3 100644 --- a/clang.h +++ b/clang.h @@ -4,5 +4,6 @@ #include 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 --- 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; diff --git a/include/pet.h b/include/pet.h index bacf469..ed24e01 100644 --- a/include/pet.h +++ b/include/pet.h @@ -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 --- 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 --- 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(expr)); case Stmt::ArraySubscriptExprClass: return extract_affine(cast(expr)); + case Stmt::MemberExprClass: + return extract_affine(cast(expr)); case Stmt::ConditionalOperatorClass: return extract_affine(cast(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(expr)); case Stmt::IntegerLiteralClass: return extract_index(cast(expr)); + case Stmt::MemberExprClass: + return extract_index(cast(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(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(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(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(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 "". */ -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 = ""; + } + 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 decls, lex_recorddecl_set *types) +{ + struct pet_array *array; + vector::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 arrays; - set::iterator it; + set > arrays; + set >::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 --- 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 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 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 --- 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; } diff --git a/scop_plus.cc b/scop_plus.cc index 1a9563e..19f9202 100644 --- a/scop_plus.cc +++ b/scop_plus.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 @@ -32,37 +33,99 @@ */ #include +#include +#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 ancestors, + set > &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 &arrays) + set > &arrays) { isl_id *id; + isl_space *space; ValueDecl *decl; + vector 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 &arrays) +static void expr_collect_arrays(struct pet_expr *expr, + set > &arrays) { if (!expr) return; @@ -74,7 +137,8 @@ static void expr_collect_arrays(struct pet_expr *expr, set &arrays) access_collect_arrays(expr, arrays); } -static void stmt_collect_arrays(struct pet_stmt *stmt, set &arrays) +static void stmt_collect_arrays(struct pet_stmt *stmt, + set > &arrays) { if (!stmt) return; @@ -88,8 +152,16 @@ static void stmt_collect_arrays(struct pet_stmt *stmt, set &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 &arrays) +void pet_scop_collect_arrays(struct pet_scop *scop, + set > &arrays) { if (!scop) return; @@ -99,10 +171,14 @@ void pet_scop_collect_arrays(struct pet_scop *scop, set &arrays) for (int i = 0; i < scop->n_array; ++i) { ValueDecl *decl; + vector 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); } } diff --git a/scop_plus.h b/scop_plus.h index e788e1a..aaee707 100644 --- a/scop_plus.h +++ b/scop_plus.h @@ -2,11 +2,12 @@ #define PET_SCOP_PLUS_H #include +#include #include #include "scop.h" void pet_scop_collect_arrays(struct pet_scop *scop, - std::set &arrays); + std::set > &arrays); #endif diff --git a/tests/struct1.c b/tests/struct1.c new file mode 100644 index 0000000..ac23aec --- /dev/null +++ b/tests/struct1.c @@ -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 index 0000000..49e03ae --- /dev/null +++ b/tests/struct1.scop @@ -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 index 0000000..8b13c22 --- /dev/null +++ b/tests/struct10.c @@ -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 index 0000000..bde1b5b --- /dev/null +++ b/tests/struct10.scop @@ -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 index 0000000..2af9f93 --- /dev/null +++ b/tests/struct2.c @@ -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 index 0000000..f26ef15 --- /dev/null +++ b/tests/struct2.scop @@ -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 index 0000000..e2f0cf8 --- /dev/null +++ b/tests/struct3.c @@ -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 index 0000000..d4e6b1e --- /dev/null +++ b/tests/struct3.scop @@ -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 index 0000000..2a68673 --- /dev/null +++ b/tests/struct4.c @@ -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 index 0000000..cd8976a --- /dev/null +++ b/tests/struct4.scop @@ -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: + 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 index 0000000..e9a35c8 --- /dev/null +++ b/tests/struct5.c @@ -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 index 0000000..a5cff70 --- /dev/null +++ b/tests/struct5.scop @@ -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: + 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 index 0000000..6f24833 --- /dev/null +++ b/tests/struct6.c @@ -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 index 0000000..b8a0cd5 --- /dev/null +++ b/tests/struct6.scop @@ -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 index 0000000..994d2e4 --- /dev/null +++ b/tests/struct7.c @@ -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 index 0000000..2ba4983 --- /dev/null +++ b/tests/struct7.scop @@ -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 index 0000000..0bc49c4 --- /dev/null +++ b/tests/struct8.c @@ -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 index 0000000..b400a18 --- /dev/null +++ b/tests/struct8.scop @@ -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: + 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 index 0000000..25e832c --- /dev/null +++ b/tests/struct9.c @@ -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 index 0000000..939c687 --- /dev/null +++ b/tests/struct9.scop @@ -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 -- 2.11.4.GIT