aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2016-06-08 14:43:40 +0000
committerJakub Jelinek <jakub@redhat.com>2016-06-08 14:43:40 +0000
commitad6a2d944931c4fa6fb18cc08a348a8ab9c36be9 (patch)
treea5bfaa04d6a4cfc4ab8a171610b5760eaabb9b15
parent0db3b02d444bf89d5bb9fdabbece13e98e324815 (diff)
* gfortran.h (symbol_attribute): Add omp_declare_target_link bitfield.
(struct gfc_omp_namelist): Add u.common field. (struct gfc_common_head): Change omp_declare_target into bitfield. Add omp_declare_target_link bitfield. (gfc_add_omp_declare_target_link): New prototype. * openmp.c (gfc_match_omp_to_link): New function. (gfc_match_omp_clauses): Use it for to and link clauses in declare target construct. (OMP_DECLARE_TARGET_CLAUSES): Define. (gfc_match_omp_declare_target): Rewritten for OpenMP 4.5. * symbol.c (check_conflict): Handle omp_declare_target_link. (gfc_add_omp_declare_target_link): New function. (gfc_copy_attr): Copy omp_declare_target_link. * module.c (enum ab_attribute): Add AB_OMP_DECLARE_TARGET_LINK. (attr_bits): Add AB_OMP_DECLARE_TARGET_LINK entry. (mio_symbol_attribute): Save and restore omp_declare_target_link bit. * f95-lang.c (gfc_attribute_table): Add "omp declare target link". * trans-decl.c (add_attributes_to_decl): Add "omp declare target link" instead of "omp declare target" for omp_declare_target_link. * trans-common.c (build_common_decl): Likewise. * openmp.c (gfc_match_omp_declare_simd): If not using the form with (proc-name), require space before first clause. testsuite/ * gfortran.dg/gomp/declare-target-1.f90: New test. * gfortran.dg/gomp/declare-target-2.f90: New test. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gomp-4_5-branch@237220 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/fortran/ChangeLog.gomp26
-rw-r--r--gcc/fortran/f95-lang.c2
-rw-r--r--gcc/fortran/gfortran.h8
-rw-r--r--gcc/fortran/module.c9
-rw-r--r--gcc/fortran/openmp.c267
-rw-r--r--gcc/fortran/symbol.c32
-rw-r--r--gcc/fortran/trans-common.c6
-rw-r--r--gcc/fortran/trans-decl.c5
-rw-r--r--gcc/testsuite/ChangeLog.gomp5
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/declare-target-1.f9027
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/declare-target-2.f9051
11 files changed, 375 insertions, 63 deletions
diff --git a/gcc/fortran/ChangeLog.gomp b/gcc/fortran/ChangeLog.gomp
index f79ad839a3f..d57189c174d 100644
--- a/gcc/fortran/ChangeLog.gomp
+++ b/gcc/fortran/ChangeLog.gomp
@@ -1,3 +1,29 @@
+2016-06-08 Jakub Jelinek <jakub@redhat.com>
+
+ * gfortran.h (symbol_attribute): Add omp_declare_target_link bitfield.
+ (struct gfc_omp_namelist): Add u.common field.
+ (struct gfc_common_head): Change omp_declare_target into bitfield.
+ Add omp_declare_target_link bitfield.
+ (gfc_add_omp_declare_target_link): New prototype.
+ * openmp.c (gfc_match_omp_to_link): New function.
+ (gfc_match_omp_clauses): Use it for to and link clauses in declare
+ target construct.
+ (OMP_DECLARE_TARGET_CLAUSES): Define.
+ (gfc_match_omp_declare_target): Rewritten for OpenMP 4.5.
+ * symbol.c (check_conflict): Handle omp_declare_target_link.
+ (gfc_add_omp_declare_target_link): New function.
+ (gfc_copy_attr): Copy omp_declare_target_link.
+ * module.c (enum ab_attribute): Add AB_OMP_DECLARE_TARGET_LINK.
+ (attr_bits): Add AB_OMP_DECLARE_TARGET_LINK entry.
+ (mio_symbol_attribute): Save and restore omp_declare_target_link bit.
+ * f95-lang.c (gfc_attribute_table): Add "omp declare target link".
+ * trans-decl.c (add_attributes_to_decl): Add "omp declare target link"
+ instead of "omp declare target" for omp_declare_target_link.
+ * trans-common.c (build_common_decl): Likewise.
+
+ * openmp.c (gfc_match_omp_declare_simd): If not using the form with
+ (proc-name), require space before first clause.
+
2016-05-31 Jakub Jelinek <jakub@redhat.com>
* trans-openmp.c (gfc_trans_omp_target_enter_data,
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 2320b69939e..8367746f08d 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -93,6 +93,8 @@ static const struct attribute_spec gfc_attribute_table[] =
affects_type_identity } */
{ "omp declare target", 0, 0, true, false, false,
gfc_handle_omp_declare_target_attribute, false },
+ { "omp declare target link", 0, 0, true, false, false,
+ gfc_handle_omp_declare_target_attribute, false },
{ "oacc function", 0, -1, true, false, false,
gfc_handle_omp_declare_target_attribute, false },
{ NULL, 0, 0, false, false, false, NULL, false }
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 7d57ffa19c9..a4c2e25394f 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -849,6 +849,7 @@ typedef struct
/* Mentioned in OMP DECLARE TARGET. */
unsigned omp_declare_target:1;
+ unsigned omp_declare_target_link:1;
/* Mentioned in OACC DECLARE. */
unsigned oacc_declare_create:1;
@@ -1157,6 +1158,7 @@ typedef struct gfc_omp_namelist
gfc_omp_depend_op depend_op;
gfc_omp_map_op map_op;
gfc_omp_linear_op linear_op;
+ struct gfc_common_head *common;
} u;
struct gfc_omp_namelist_udr *udr;
struct gfc_omp_namelist *next;
@@ -1561,7 +1563,9 @@ struct gfc_undo_change_set
typedef struct gfc_common_head
{
locus where;
- char use_assoc, saved, threadprivate, omp_declare_target;
+ char use_assoc, saved, threadprivate;
+ unsigned char omp_declare_target : 1;
+ unsigned char omp_declare_target_link : 1;
char name[GFC_MAX_SYMBOL_LEN + 1];
struct gfc_symbol *head;
const char* binding_label;
@@ -2840,6 +2844,8 @@ bool gfc_add_result (symbol_attribute *, const char *, locus *);
bool gfc_add_save (symbol_attribute *, save_state, const char *, locus *);
bool gfc_add_threadprivate (symbol_attribute *, const char *, locus *);
bool gfc_add_omp_declare_target (symbol_attribute *, const char *, locus *);
+bool gfc_add_omp_declare_target_link (symbol_attribute *, const char *,
+ locus *);
bool gfc_add_saved_common (symbol_attribute *, locus *);
bool gfc_add_target (symbol_attribute *, locus *);
bool gfc_add_dummy (symbol_attribute *, const char *, locus *);
diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c
index 32ee526aa22..e14e961d838 100644
--- a/gcc/fortran/module.c
+++ b/gcc/fortran/module.c
@@ -1988,7 +1988,8 @@ enum ab_attribute
AB_IMPLICIT_PURE, AB_ARTIFICIAL, AB_UNLIMITED_POLY, AB_OMP_DECLARE_TARGET,
AB_ARRAY_OUTER_DEPENDENCY, AB_MODULE_PROCEDURE, AB_OACC_DECLARE_CREATE,
AB_OACC_DECLARE_COPYIN, AB_OACC_DECLARE_DEVICEPTR,
- AB_OACC_DECLARE_DEVICE_RESIDENT, AB_OACC_DECLARE_LINK
+ AB_OACC_DECLARE_DEVICE_RESIDENT, AB_OACC_DECLARE_LINK,
+ AB_OMP_DECLARE_TARGET_LINK
};
static const mstring attr_bits[] =
@@ -2051,6 +2052,7 @@ static const mstring attr_bits[] =
minit ("OACC_DECLARE_DEVICEPTR", AB_OACC_DECLARE_DEVICEPTR),
minit ("OACC_DECLARE_DEVICE_RESIDENT", AB_OACC_DECLARE_DEVICE_RESIDENT),
minit ("OACC_DECLARE_LINK", AB_OACC_DECLARE_LINK),
+ minit ("OMP_DECLARE_TARGET_LINK", AB_OMP_DECLARE_TARGET_LINK),
minit (NULL, -1)
};
@@ -2250,6 +2252,8 @@ mio_symbol_attribute (symbol_attribute *attr)
MIO_NAME (ab_attribute) (AB_OACC_DECLARE_DEVICE_RESIDENT, attr_bits);
if (attr->oacc_declare_link)
MIO_NAME (ab_attribute) (AB_OACC_DECLARE_LINK, attr_bits);
+ if (attr->omp_declare_target_link)
+ MIO_NAME (ab_attribute) (AB_OMP_DECLARE_TARGET_LINK, attr_bits);
mio_rparen ();
@@ -2419,6 +2423,9 @@ mio_symbol_attribute (symbol_attribute *attr)
case AB_OMP_DECLARE_TARGET:
attr->omp_declare_target = 1;
break;
+ case AB_OMP_DECLARE_TARGET_LINK:
+ attr->omp_declare_target_link = 1;
+ break;
case AB_ARRAY_OUTER_DEPENDENCY:
attr->array_outer_dependency =1;
break;
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index 07278f99a59..4453bbd60c8 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -340,6 +340,96 @@ cleanup:
return MATCH_ERROR;
}
+/* Match a variable/procedure/common block list and construct a namelist
+ from it. */
+
+static match
+gfc_match_omp_to_link (const char *str, gfc_omp_namelist **list)
+{
+ gfc_omp_namelist *head, *tail, *p;
+ locus old_loc, cur_loc;
+ char n[GFC_MAX_SYMBOL_LEN+1];
+ gfc_symbol *sym;
+ match m;
+ gfc_symtree *st;
+
+ head = tail = NULL;
+
+ old_loc = gfc_current_locus;
+
+ m = gfc_match (str);
+ if (m != MATCH_YES)
+ return m;
+
+ for (;;)
+ {
+ cur_loc = gfc_current_locus;
+ m = gfc_match_symbol (&sym, 1);
+ switch (m)
+ {
+ case MATCH_YES:
+ p = gfc_get_omp_namelist ();
+ if (head == NULL)
+ head = tail = p;
+ else
+ {
+ tail->next = p;
+ tail = tail->next;
+ }
+ tail->sym = sym;
+ tail->where = cur_loc;
+ goto next_item;
+ case MATCH_NO:
+ break;
+ case MATCH_ERROR:
+ goto cleanup;
+ }
+
+ m = gfc_match (" / %n /", n);
+ if (m == MATCH_ERROR)
+ goto cleanup;
+ if (m == MATCH_NO)
+ goto syntax;
+
+ st = gfc_find_symtree (gfc_current_ns->common_root, n);
+ if (st == NULL)
+ {
+ gfc_error ("COMMON block /%s/ not found at %C", n);
+ goto cleanup;
+ }
+ p = gfc_get_omp_namelist ();
+ if (head == NULL)
+ head = tail = p;
+ else
+ {
+ tail->next = p;
+ tail = tail->next;
+ }
+ tail->u.common = st->n.common;
+ tail->where = cur_loc;
+
+ next_item:
+ if (gfc_match_char (')') == MATCH_YES)
+ break;
+ if (gfc_match_char (',') != MATCH_YES)
+ goto syntax;
+ }
+
+ while (*list)
+ list = &(*list)->next;
+
+ *list = head;
+ return MATCH_YES;
+
+syntax:
+ gfc_error ("Syntax error in OpenMP variable list at %C");
+
+cleanup:
+ gfc_free_omp_namelist (head);
+ gfc_current_locus = old_loc;
+ return MATCH_ERROR;
+}
+
/* Match depend(sink : ...) construct a namelist from it. */
static match
@@ -1249,6 +1339,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
&c->lists[OMP_LIST_LINK])
== MATCH_YES))
continue;
+ else if ((mask & OMP_CLAUSE_LINK)
+ && !openacc
+ && (gfc_match_omp_to_link ("link (",
+ &c->lists[OMP_LIST_LINK])
+ == MATCH_YES))
+ continue;
break;
case 'm':
if ((mask & OMP_CLAUSE_MAP)
@@ -1688,7 +1784,13 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
&& match_oacc_expr_list ("tile (", &c->tile_list,
true) == MATCH_YES)
continue;
- if ((mask & OMP_CLAUSE_TO)
+ if ((mask & OMP_CLAUSE_TO) && (mask & OMP_CLAUSE_LINK))
+ {
+ if (gfc_match_omp_to_link ("to (", &c->lists[OMP_LIST_TO])
+ == MATCH_YES)
+ continue;
+ }
+ else if ((mask & OMP_CLAUSE_TO)
&& gfc_match_omp_variable_list ("to (",
&c->lists[OMP_LIST_TO], false,
NULL, &head, true) == MATCH_YES)
@@ -2324,6 +2426,8 @@ cleanup:
(omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE)
#define OMP_ORDERED_CLAUSES \
(omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD)
+#define OMP_DECLARE_TARGET_CLAUSES \
+ (omp_mask (OMP_CLAUSE_TO) | OMP_CLAUSE_LINK)
static match
@@ -2457,16 +2561,17 @@ gfc_match_omp_declare_simd (void)
gfc_symbol *proc_name;
gfc_omp_clauses *c;
gfc_omp_declare_simd *ods;
+ bool needs_space = false;
switch (gfc_match (" ( %s ) ", &proc_name))
{
case MATCH_YES: break;
- case MATCH_NO: proc_name = NULL; break;
+ case MATCH_NO: proc_name = NULL; needs_space = true; break;
case MATCH_ERROR: return MATCH_ERROR;
}
if (gfc_match_omp_clauses (&c, OMP_DECLARE_SIMD_CLAUSES, true,
- false) != MATCH_YES)
+ needs_space) != MATCH_YES)
return MATCH_ERROR;
ods = gfc_get_omp_declare_simd ();
@@ -2874,26 +2979,15 @@ match
gfc_match_omp_declare_target (void)
{
locus old_loc;
- char n[GFC_MAX_SYMBOL_LEN+1];
- gfc_symbol *sym;
match m;
- gfc_symtree *st;
+ gfc_omp_clauses *c = NULL;
+ int list;
+ gfc_omp_namelist *n;
+ gfc_symbol *s;
old_loc = gfc_current_locus;
- m = gfc_match (" (");
-
if (gfc_current_ns->proc_name
- && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY
- && m == MATCH_YES)
- {
- gfc_error ("Only the !$OMP DECLARE TARGET form without "
- "list is allowed in interface block at %C");
- goto cleanup;
- }
-
- if (m == MATCH_NO
- && gfc_current_ns->proc_name
&& gfc_match_omp_eos () == MATCH_YES)
{
if (!gfc_add_omp_declare_target (&gfc_current_ns->proc_name->attr,
@@ -2903,58 +2997,111 @@ gfc_match_omp_declare_target (void)
return MATCH_YES;
}
- if (m != MATCH_YES)
- return m;
+ if (gfc_current_ns->proc_name
+ && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY)
+ {
+ gfc_error ("Only the !$OMP DECLARE TARGET form without "
+ "clauses is allowed in interface block at %C");
+ goto cleanup;
+ }
- for (;;)
+ m = gfc_match (" (");
+ if (m == MATCH_YES)
{
- m = gfc_match_symbol (&sym, 0);
- switch (m)
+ c = gfc_get_omp_clauses ();
+ gfc_current_locus = old_loc;
+ m = gfc_match_omp_to_link (" (", &c->lists[OMP_LIST_TO]);
+ if (m != MATCH_YES)
+ goto syntax;
+ if (gfc_match_omp_eos () != MATCH_YES)
{
- case MATCH_YES:
- if (sym->attr.in_common)
- gfc_error_now ("OMP DECLARE TARGET on a variable at %C is an "
- "element of a COMMON block");
- else if (!gfc_add_omp_declare_target (&sym->attr, sym->name,
- &sym->declared_at))
- goto cleanup;
- goto next_item;
- case MATCH_NO:
- break;
- case MATCH_ERROR:
+ gfc_error ("Unexpected junk after !$OMP DECLARE TARGET at %C");
goto cleanup;
}
+ }
+ else if (gfc_match_omp_clauses (&c, OMP_DECLARE_TARGET_CLAUSES) != MATCH_YES)
+ return MATCH_ERROR;
- m = gfc_match (" / %n /", n);
- if (m == MATCH_ERROR)
- goto cleanup;
- if (m == MATCH_NO || n[0] == '\0')
- goto syntax;
+ gfc_buffer_error (false);
- st = gfc_find_symtree (gfc_current_ns->common_root, n);
- if (st == NULL)
+ for (list = OMP_LIST_TO; list != OMP_LIST_NUM;
+ list = (list == OMP_LIST_TO ? OMP_LIST_LINK : OMP_LIST_NUM))
+ for (n = c->lists[list]; n; n = n->next)
+ if (n->sym)
+ n->sym->mark = 0;
+ else if (n->u.common->head)
+ n->u.common->head->mark = 0;
+
+ for (list = OMP_LIST_TO; list != OMP_LIST_NUM;
+ list = (list == OMP_LIST_TO ? OMP_LIST_LINK : OMP_LIST_NUM))
+ for (n = c->lists[list]; n; n = n->next)
+ if (n->sym)
{
- gfc_error ("COMMON block /%s/ not found at %C", n);
- goto cleanup;
+ if (n->sym->attr.in_common)
+ gfc_error_now ("OMP DECLARE TARGET variable at %L is an "
+ "element of a COMMON block", &n->where);
+ else if (n->sym->attr.omp_declare_target
+ && n->sym->attr.omp_declare_target_link
+ && list != OMP_LIST_LINK)
+ gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
+ "mentioned in LINK clause and later in TO clause",
+ &n->where);
+ else if (n->sym->attr.omp_declare_target
+ && !n->sym->attr.omp_declare_target_link
+ && list == OMP_LIST_LINK)
+ gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
+ "mentioned in TO clause and later in LINK clause",
+ &n->where);
+ else if (n->sym->mark)
+ gfc_error_now ("Variable at %L mentioned multiple times in "
+ "clauses of the same OMP DECLARE TARGET directive",
+ &n->where);
+ else if (gfc_add_omp_declare_target (&n->sym->attr, n->sym->name,
+ &n->sym->declared_at))
+ {
+ if (list == OMP_LIST_LINK)
+ gfc_add_omp_declare_target_link (&n->sym->attr, n->sym->name,
+ &n->sym->declared_at);
+ }
+ n->sym->mark = 1;
+ }
+ else if (n->u.common->omp_declare_target
+ && n->u.common->omp_declare_target_link
+ && list != OMP_LIST_LINK)
+ gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
+ "mentioned in LINK clause and later in TO clause",
+ &n->where);
+ else if (n->u.common->omp_declare_target
+ && !n->u.common->omp_declare_target_link
+ && list == OMP_LIST_LINK)
+ gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
+ "mentioned in TO clause and later in LINK clause",
+ &n->where);
+ else if (n->u.common->head && n->u.common->head->mark)
+ gfc_error_now ("COMMON at %L mentioned multiple times in "
+ "clauses of the same OMP DECLARE TARGET directive",
+ &n->where);
+ else
+ {
+ n->u.common->omp_declare_target = 1;
+ n->u.common->omp_declare_target_link = (list == OMP_LIST_LINK);
+ for (s = n->u.common->head; s; s = s->common_next)
+ {
+ s->mark = 1;
+ if (gfc_add_omp_declare_target (&s->attr, s->name,
+ &s->declared_at))
+ {
+ if (list == OMP_LIST_LINK)
+ gfc_add_omp_declare_target_link (&s->attr, s->name,
+ &s->declared_at);
+ }
+ }
}
- st->n.common->omp_declare_target = 1;
- for (sym = st->n.common->head; sym; sym = sym->common_next)
- if (!gfc_add_omp_declare_target (&sym->attr, sym->name,
- &sym->declared_at))
- goto cleanup;
- next_item:
- if (gfc_match_char (')') == MATCH_YES)
- break;
- if (gfc_match_char (',') != MATCH_YES)
- goto syntax;
- }
+ gfc_buffer_error (true);
- if (gfc_match_omp_eos () != MATCH_YES)
- {
- gfc_error ("Unexpected junk after !$OMP DECLARE TARGET at %C");
- goto cleanup;
- }
+ if (c)
+ gfc_free_omp_clauses (c);
return MATCH_YES;
syntax:
@@ -2962,6 +3109,8 @@ syntax:
cleanup:
gfc_current_locus = old_loc;
+ if (c)
+ gfc_free_omp_clauses (c);
return MATCH_ERROR;
}
diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c
index 8efd12ca68b..e6b44868742 100644
--- a/gcc/fortran/symbol.c
+++ b/gcc/fortran/symbol.c
@@ -375,6 +375,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
*contiguous = "CONTIGUOUS", *generic = "GENERIC";
static const char *threadprivate = "THREADPRIVATE";
static const char *omp_declare_target = "OMP DECLARE TARGET";
+ static const char *omp_declare_target_link = "OMP DECLARE TARGET LINK";
static const char *oacc_declare_copyin = "OACC DECLARE COPYIN";
static const char *oacc_declare_create = "OACC DECLARE CREATE";
static const char *oacc_declare_deviceptr = "OACC DECLARE DEVICEPTR";
@@ -472,6 +473,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (dummy, intrinsic);
conf (dummy, threadprivate);
conf (dummy, omp_declare_target);
+ conf (dummy, omp_declare_target_link);
conf (pointer, target);
conf (pointer, intrinsic);
conf (pointer, elemental);
@@ -516,6 +518,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (in_equivalence, allocatable);
conf (in_equivalence, threadprivate);
conf (in_equivalence, omp_declare_target);
+ conf (in_equivalence, omp_declare_target_link);
conf (in_equivalence, oacc_declare_create);
conf (in_equivalence, oacc_declare_copyin);
conf (in_equivalence, oacc_declare_deviceptr);
@@ -524,6 +527,8 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (dummy, result);
conf (entry, result);
conf (generic, result);
+ conf (generic, omp_declare_target);
+ conf (generic, omp_declare_target_link);
conf (function, subroutine);
@@ -569,6 +574,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (cray_pointee, in_equivalence);
conf (cray_pointee, threadprivate);
conf (cray_pointee, omp_declare_target);
+ conf (cray_pointee, omp_declare_target_link);
conf (cray_pointee, oacc_declare_create);
conf (cray_pointee, oacc_declare_copyin);
conf (cray_pointee, oacc_declare_deviceptr);
@@ -625,8 +631,11 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (procedure, entry)
conf (proc_pointer, abstract)
+ conf (proc_pointer, omp_declare_target)
+ conf (proc_pointer, omp_declare_target_link)
conf (entry, omp_declare_target)
+ conf (entry, omp_declare_target_link)
conf (entry, oacc_declare_create)
conf (entry, oacc_declare_copyin)
conf (entry, oacc_declare_deviceptr)
@@ -668,6 +677,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf2 (subroutine);
conf2 (threadprivate);
conf2 (omp_declare_target);
+ conf2 (omp_declare_target_link);
conf2 (oacc_declare_create);
conf2 (oacc_declare_copyin);
conf2 (oacc_declare_deviceptr);
@@ -718,6 +728,8 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
if (!attr->proc_pointer)
conf2 (in_common);
+ conf2 (omp_declare_target_link);
+
switch (attr->proc)
{
case PROC_ST_FUNCTION:
@@ -754,6 +766,7 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf2 (threadprivate);
conf2 (result);
conf2 (omp_declare_target);
+ conf2 (omp_declare_target_link);
conf2 (oacc_declare_create);
conf2 (oacc_declare_copyin);
conf2 (oacc_declare_deviceptr);
@@ -1269,6 +1282,22 @@ gfc_add_omp_declare_target (symbol_attribute *attr, const char *name,
bool
+gfc_add_omp_declare_target_link (symbol_attribute *attr, const char *name,
+ locus *where)
+{
+
+ if (check_used (attr, name, where))
+ return false;
+
+ if (attr->omp_declare_target_link)
+ return true;
+
+ attr->omp_declare_target_link = 1;
+ return check_conflict (attr, name, where);
+}
+
+
+bool
gfc_add_oacc_declare_create (symbol_attribute *attr, const char *name,
locus *where)
{
@@ -1905,6 +1934,9 @@ gfc_copy_attr (symbol_attribute *dest, symbol_attribute *src, locus *where)
if (src->omp_declare_target
&& !gfc_add_omp_declare_target (dest, NULL, where))
goto fail;
+ if (src->omp_declare_target_link
+ && !gfc_add_omp_declare_target_link (dest, NULL, where))
+ goto fail;
if (src->oacc_declare_create
&& !gfc_add_oacc_declare_create (dest, NULL, where))
goto fail;
diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c
index 4fdccc90747..6189ec0715f 100644
--- a/gcc/fortran/trans-common.c
+++ b/gcc/fortran/trans-common.c
@@ -457,7 +457,11 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init)
if (com->threadprivate)
set_decl_tls_model (decl, decl_default_tls_model (decl));
- if (com->omp_declare_target)
+ if (com->omp_declare_target_link)
+ DECL_ATTRIBUTES (decl)
+ = tree_cons (get_identifier ("omp declare target link"),
+ NULL_TREE, DECL_ATTRIBUTES (decl));
+ else if (com->omp_declare_target)
DECL_ATTRIBUTES (decl)
= tree_cons (get_identifier ("omp declare target"),
NULL_TREE, DECL_ATTRIBUTES (decl));
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 309baf1c69e..1b5884bd8a6 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -1306,7 +1306,10 @@ add_attributes_to_decl (symbol_attribute sym_attr, tree list)
list = chainon (list, attr);
}
- if (sym_attr.omp_declare_target)
+ if (sym_attr.omp_declare_target_link)
+ list = tree_cons (get_identifier ("omp declare target link"),
+ NULL_TREE, list);
+ else if (sym_attr.omp_declare_target)
list = tree_cons (get_identifier ("omp declare target"),
NULL_TREE, list);
diff --git a/gcc/testsuite/ChangeLog.gomp b/gcc/testsuite/ChangeLog.gomp
index fc67b9ebccc..b3bd85a785e 100644
--- a/gcc/testsuite/ChangeLog.gomp
+++ b/gcc/testsuite/ChangeLog.gomp
@@ -1,3 +1,8 @@
+2016-06-08 Jakub Jelinek <jakub@redhat.com>
+
+ * gfortran.dg/gomp/declare-target-1.f90: New test.
+ * gfortran.dg/gomp/declare-target-2.f90: New test.
+
2016-05-31 Jakub Jelinek <jakub@redhat.com>
* gfortran.dg/gomp/declare-simd-2.f90 (f2): New function.
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-1.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-1.f90
new file mode 100644
index 00000000000..bf64e72d082
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-1.f90
@@ -0,0 +1,27 @@
+! { dg-do compile }
+
+module declare_target_1
+ !$omp declare target to (var_1, var_4) link (var_2, var_3) &
+ !$omp & link (var_5) to (var_6)
+ integer :: var_1, var_2, var_3, var_4, var_5, var_6
+ interface
+ subroutine foo
+ !$omp declare target
+ end subroutine
+ end interface
+end
+subroutine bar
+ !$omp declare target
+ integer, save :: var_9
+ !$omp declare target link (var_8) to (baz, var_7) link (var_9) to (var_10)
+ integer, save :: var_7, var_8, var_10
+ integer :: var_11, var_12, var_13, var_14
+ common /c1/ var_11, var_12
+ common /c2/ var_13
+ common /c3/ var_14
+ !$omp declare target (baz, var_7, var_10, /c1/)
+ !$omp declare target to (/c2/)
+ !$omp declare target link (/c3/)
+ !$omp declare target (bar)
+ call baz
+end subroutine
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90
new file mode 100644
index 00000000000..2217eab07e5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-target-2.f90
@@ -0,0 +1,51 @@
+! { dg-do compile }
+
+module declare_target_2
+ !$omp declare target to (a) link (a) ! { dg-error "TO clause and later in LINK" }
+ !$omp declare target (b)
+ !$omp declare target link (b) ! { dg-error "TO clause and later in LINK" }
+ !$omp declare target link (f)
+ !$omp declare target to (f) ! { dg-error "LINK clause and later in TO" }
+ !$omp declare target(c, c) ! { dg-error "mentioned multiple times in clauses of the same" }
+ !$omp declare target to (d) to (d) ! { dg-error "mentioned multiple times in clauses of the same" }
+ !$omp declare target link (e, e) ! { dg-error "mentioned multiple times in clauses of the same" }
+ integer, save :: a, b, c, d, e, f
+ interface
+ integer function f1 (a)
+ !$omp declare target (f1) ! { dg-error "form without clauses is allowed in interface block" }
+ integer :: a
+ end function
+ end interface
+ interface
+ integer function f2 (a)
+ !$omp declare target to (f2) ! { dg-error "form without clauses is allowed in interface block" }
+ integer :: a
+ end function
+ end interface
+end
+subroutine bar
+ !$omp declare target link (baz) ! { dg-error "isn.t SAVEd" }
+ call baz ! { dg-error "attribute conflicts" }
+end subroutine
+subroutine foo ! { dg-error "attribute conflicts" }
+ integer :: g, h, i, j, k, l, m, n, o, p, q
+ common /c1/ g, h
+ common /c2/ i, j
+ common /c3/ k, l
+ common /c4/ m, n
+ common /c5/ o, p, q
+ !$omp declare target to (g) ! { dg-error "is an element of a COMMON block" }
+ !$omp declare target link (foo)
+ !$omp declare target to (/c2/)
+ !$omp declare target (/c2/)
+ !$omp declare target to(/c2/)
+ !$omp declare target link(/c2/) ! { dg-error "TO clause and later in LINK" }
+ !$omp declare target link(/c3/)
+ !$omp declare target (/c3/) ! { dg-error "LINK clause and later in TO" }
+ !$omp declare target (/c4/, /c4/) ! { dg-error "mentioned multiple times in clauses of the same" }
+ !$omp declare target to (/c4/) to(/c4/) ! { dg-error "mentioned multiple times in clauses of the same" }
+ !$omp declare target link (/c5/)
+ !$omp declare target link (/c5/)
+ !$omp declare target link(/c5/)link(/c5/) ! { dg-error "mentioned multiple times in clauses of the same" }
+ !$omp declare target link(/c5/,/c5/) ! { dg-error "mentioned multiple times in clauses of the same" }
+end subroutine