case OMP_LIST_USE_DEVICE_PTR: type = "USE_DEVICE_PTR"; break;
case OMP_LIST_USE_DEVICE_ADDR: type = "USE_DEVICE_ADDR"; break;
case OMP_LIST_NONTEMPORAL: type = "NONTEMPORAL"; break;
+ case OMP_LIST_SCAN_IN: type = "INCLUSIVE"; break;
+ case OMP_LIST_SCAN_EX: type = "EXCLUSIVE"; break;
default:
gcc_unreachable ();
}
case EXEC_OMP_PARALLEL_DO_SIMD: name = "PARALLEL DO SIMD"; break;
case EXEC_OMP_PARALLEL_SECTIONS: name = "PARALLEL SECTIONS"; break;
case EXEC_OMP_PARALLEL_WORKSHARE: name = "PARALLEL WORKSHARE"; break;
+ case EXEC_OMP_SCAN: name = "SCAN"; break;
case EXEC_OMP_SECTIONS: name = "SECTIONS"; break;
case EXEC_OMP_SIMD: name = "SIMD"; break;
case EXEC_OMP_SINGLE: name = "SINGLE"; break;
case EXEC_OMP_PARALLEL_DO_SIMD:
case EXEC_OMP_PARALLEL_SECTIONS:
case EXEC_OMP_PARALLEL_WORKSHARE:
+ case EXEC_OMP_SCAN:
case EXEC_OMP_SECTIONS:
case EXEC_OMP_SIMD:
case EXEC_OMP_SINGLE:
if (c->op == EXEC_OACC_CACHE || c->op == EXEC_OACC_UPDATE
|| c->op == EXEC_OACC_ENTER_DATA || c->op == EXEC_OACC_EXIT_DATA
|| c->op == EXEC_OMP_TARGET_UPDATE || c->op == EXEC_OMP_TARGET_ENTER_DATA
- || c->op == EXEC_OMP_TARGET_EXIT_DATA
+ || c->op == EXEC_OMP_TARGET_EXIT_DATA || c->op == EXEC_OMP_SCAN
|| (c->op == EXEC_OMP_ORDERED && c->block == NULL))
return;
if (c->op == EXEC_OMP_SECTIONS || c->op == EXEC_OMP_PARALLEL_SECTIONS)
case EXEC_OMP_PARALLEL_DO_SIMD:
case EXEC_OMP_PARALLEL_SECTIONS:
case EXEC_OMP_PARALLEL_WORKSHARE:
+ case EXEC_OMP_SCAN:
case EXEC_OMP_SECTIONS:
case EXEC_OMP_SIMD:
case EXEC_OMP_SINGLE:
ST_OMP_TARGET_PARALLEL_DO_SIMD, ST_OMP_END_TARGET_PARALLEL_DO_SIMD,
ST_OMP_TARGET_ENTER_DATA, ST_OMP_TARGET_EXIT_DATA,
ST_OMP_TARGET_SIMD, ST_OMP_END_TARGET_SIMD,
- ST_OMP_TASKLOOP, ST_OMP_END_TASKLOOP,
+ ST_OMP_TASKLOOP, ST_OMP_END_TASKLOOP, ST_OMP_SCAN,
ST_OMP_TASKLOOP_SIMD, ST_OMP_END_TASKLOOP_SIMD, ST_OMP_ORDERED_DEPEND,
ST_OMP_REQUIRES, ST_PROCEDURE, ST_GENERIC, ST_CRITICAL, ST_END_CRITICAL,
ST_GET_FCN_CHARACTERISTICS, ST_LOCK, ST_UNLOCK, ST_EVENT_POST,
OMP_LIST_MAP,
OMP_LIST_TO,
OMP_LIST_FROM,
+ OMP_LIST_SCAN_IN,
+ OMP_LIST_SCAN_EX,
OMP_LIST_REDUCTION,
OMP_LIST_REDUCTION_INSCAN,
OMP_LIST_REDUCTION_TASK,
EXEC_OMP_TARGET_ENTER_DATA, EXEC_OMP_TARGET_EXIT_DATA,
EXEC_OMP_TARGET_PARALLEL, EXEC_OMP_TARGET_PARALLEL_DO,
EXEC_OMP_TARGET_PARALLEL_DO_SIMD, EXEC_OMP_TARGET_SIMD,
- EXEC_OMP_TASKLOOP, EXEC_OMP_TASKLOOP_SIMD
+ EXEC_OMP_TASKLOOP, EXEC_OMP_TASKLOOP_SIMD, EXEC_OMP_SCAN
};
typedef struct gfc_code
match gfc_match_omp_parallel_sections (void);
match gfc_match_omp_parallel_workshare (void);
match gfc_match_omp_requires (void);
+match gfc_match_omp_scan (void);
match gfc_match_omp_sections (void);
match gfc_match_omp_simd (void);
match gfc_match_omp_single (void);
}
+match
+gfc_match_omp_scan (void)
+{
+ bool incl;
+ gfc_omp_clauses *c = gfc_get_omp_clauses ();
+ gfc_gobble_whitespace ();
+ if ((incl = (gfc_match ("inclusive") == MATCH_YES))
+ || gfc_match ("exclusive") == MATCH_YES)
+ {
+ if (gfc_match_omp_variable_list (" (", &c->lists[incl ? OMP_LIST_SCAN_IN
+ : OMP_LIST_SCAN_EX],
+ false) != MATCH_YES)
+ {
+ gfc_free_omp_clauses (c);
+ return MATCH_ERROR;
+ }
+ }
+ else
+ {
+ gfc_error ("Expected INCLUSIVE or EXCLUSIVE clause at %C");
+ gfc_free_omp_clauses (c);
+ return MATCH_ERROR;
+ }
+ if (gfc_match_omp_eos () != MATCH_YES)
+ {
+ gfc_error ("Unexpected junk after !$OMP SCAN at %C");
+ gfc_free_omp_clauses (c);
+ return MATCH_ERROR;
+ }
+
+ new_st.op = EXEC_OMP_SCAN;
+ new_st.ext.omp_clauses = c;
+ return MATCH_YES;
+}
+
+
match
gfc_match_omp_sections (void)
{
match
gfc_match_omp_taskgroup (void)
{
- gfc_omp_clauses *c;
- if (gfc_match_omp_clauses (&c, OMP_CLAUSE_TASK_REDUCTION, true, true)
- != MATCH_YES)
- return MATCH_ERROR;
- new_st.op = EXEC_OMP_TASKGROUP;
- new_st.ext.omp_clauses = c;
- return MATCH_YES;
+ return match_omp (EXEC_OMP_TASKGROUP, OMP_CLAUSE_TASK_REDUCTION);
}
static const char *clause_names[]
= { "PRIVATE", "FIRSTPRIVATE", "LASTPRIVATE", "COPYPRIVATE", "SHARED",
"COPYIN", "UNIFORM", "ALIGNED", "LINEAR", "DEPEND", "MAP",
- "TO", "FROM", "REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
+ "TO", "FROM", "INCLUSIVE", "EXCLUSIVE",
+ "REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
"IN_REDUCTION", "TASK_REDUCTION",
"DEVICE_RESIDENT", "LINK", "USE_DEVICE",
"CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
gfc_error ("Object %qs is not a variable at %L", n->sym->name,
&n->where);
}
+ if (omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]
+ && code->op != EXEC_OMP_DO
+ && code->op != EXEC_OMP_SIMD
+ && code->op != EXEC_OMP_DO_SIMD
+ && code->op != EXEC_OMP_PARALLEL_DO
+ && code->op != EXEC_OMP_PARALLEL_DO_SIMD)
+ gfc_error ("%<inscan%> REDUCTION clause on construct other than DO, SIMD, "
+ "DO SIMD, PARALLEL DO, PARALLEL DO SIMD at %L",
+ &omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]->where);
for (list = 0; list < OMP_LIST_NUM; list++)
if (list != OMP_LIST_FIRSTPRIVATE
n->sym->mark = 1;
}
+ bool has_inscan = false, has_notinscan = false;
for (list = 0; list < OMP_LIST_NUM; list++)
if ((n = omp_clauses->lists[list]) != NULL)
{
|| list == OMP_LIST_REDUCTION_TASK
|| list == OMP_LIST_IN_REDUCTION
|| list == OMP_LIST_TASK_REDUCTION);
+ if (list == OMP_LIST_REDUCTION_INSCAN)
+ has_inscan = true;
+ else if (is_reduction)
+ has_notinscan = true;
+ if (has_inscan && has_notinscan && is_reduction)
+ {
+ gfc_error ("%<inscan%> and non-%<inscan%> %<reduction%> "
+ "clauses on the same construct %L",
+ &n->where);
+ break;
+ }
if (n->sym->attr.threadprivate)
gfc_error ("THREADPRIVATE object %qs in %s clause at %L",
n->sym->name, name, &n->where);
}
if (i < omp_current_do_collapse || omp_current_do_collapse <= 0)
omp_current_do_collapse = 1;
+ if (code->ext.omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN])
+ {
+ locus *loc
+ = &code->ext.omp_clauses->lists[OMP_LIST_REDUCTION_INSCAN]->where;
+ if (code->ext.omp_clauses->ordered)
+ gfc_error ("ORDERED clause specified together with %<inscan%> "
+ "REDUCTION clause at %L", loc);
+ if (code->ext.omp_clauses->sched_kind != OMP_SCHED_NONE)
+ gfc_error ("SCHEDULE clause specified together with %<inscan%> "
+ "REDUCTION clause at %L", loc);
+ if (!c->block
+ || !c->block->next
+ || !c->block->next->next
+ || c->block->next->next->op != EXEC_OMP_SCAN
+ || !c->block->next->next->next
+ || c->block->next->next->next->next)
+ gfc_error ("With INSCAN at %L, expected loop body with !$OMP SCAN "
+ "between two structured-block-sequences", loc);
+ else
+ /* Mark as checked; flag will be unset later. */
+ c->block->next->next->ext.omp_clauses->if_present = true;
+ }
}
gfc_resolve_blocks (code->block, ns);
omp_current_do_collapse = 0;
return ST_OMP_DISTRIBUTE_SIMD;
case EXEC_OMP_DO_SIMD:
return ST_OMP_DO_SIMD;
+ case EXEC_OMP_SCAN:
+ return ST_OMP_SCAN;
case EXEC_OMP_SIMD:
return ST_OMP_SIMD;
case EXEC_OMP_TARGET:
of each directive. */
void
-gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns ATTRIBUTE_UNUSED)
+gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns)
{
resolve_omp_directive_inside_oacc_region (code);
gfc_error ("OMP CRITICAL at %L with HINT clause requires a NAME, "
"except when omp_sync_hint_none is used", &code->loc);
break;
+ case EXEC_OMP_SCAN:
+ /* Flag is only used to checking, hence, it is unset afterwards. */
+ if (!code->ext.omp_clauses->if_present)
+ gfc_error ("Unexpected !$OMP SCAN at %L outside loop construct with "
+ "%<inscan%> REDUCTION clause", &code->loc);
+ code->ext.omp_clauses->if_present = false;
+ resolve_omp_clauses (code, code->ext.omp_clauses, ns);
+ break;
default:
break;
}
matcho ("requires", gfc_match_omp_requires, ST_OMP_REQUIRES);
break;
case 's':
+ matcho ("scan", gfc_match_omp_scan, ST_OMP_SCAN);
matcho ("sections", gfc_match_omp_sections, ST_OMP_SECTIONS);
matcho ("section", gfc_match_omp_eos_error, ST_OMP_SECTION);
matcho ("single", gfc_match_omp_single, ST_OMP_SINGLE);
case ST_OMP_CANCEL: case ST_OMP_CANCELLATION_POINT: \
case ST_OMP_TARGET_UPDATE: case ST_OMP_TARGET_ENTER_DATA: \
case ST_OMP_TARGET_EXIT_DATA: case ST_OMP_ORDERED_DEPEND: \
- case ST_ERROR_STOP: case ST_SYNC_ALL: \
+ case ST_ERROR_STOP: case ST_OMP_SCAN: case ST_SYNC_ALL: \
case ST_SYNC_IMAGES: case ST_SYNC_MEMORY: case ST_LOCK: case ST_UNLOCK: \
case ST_FORM_TEAM: case ST_CHANGE_TEAM: \
case ST_END_TEAM: case ST_SYNC_TEAM: \
case ST_OMP_REQUIRES:
p = "!$OMP REQUIRES";
break;
+ case ST_OMP_SCAN:
+ p = "!$OMP SCAN";
+ break;
case ST_OMP_SECTIONS:
p = "!$OMP SECTIONS";
break;
case EXEC_OMP_DO_SIMD:
case EXEC_OMP_MASTER:
case EXEC_OMP_ORDERED:
+ case EXEC_OMP_SCAN:
case EXEC_OMP_SECTIONS:
case EXEC_OMP_SIMD:
case EXEC_OMP_SINGLE:
case EXEC_OMP_PARALLEL_DO_SIMD:
case EXEC_OMP_PARALLEL_SECTIONS:
case EXEC_OMP_PARALLEL_WORKSHARE:
+ case EXEC_OMP_SCAN:
case EXEC_OMP_SECTIONS:
case EXEC_OMP_SIMD:
case EXEC_OMP_SINGLE:
case OMP_LIST_NONTEMPORAL:
clause_code = OMP_CLAUSE_NONTEMPORAL;
goto add_clause;
+ case OMP_LIST_SCAN_IN:
+ clause_code = OMP_CLAUSE_INCLUSIVE;
+ goto add_clause;
+ case OMP_LIST_SCAN_EX:
+ clause_code = OMP_CLAUSE_EXCLUSIVE;
+ goto add_clause;
add_clause:
omp_clauses
code->exit_label = NULL_TREE;
/* Main loop body. */
- tmp = gfc_trans_omp_code (code->block->next, true);
+ if (clauses->lists[OMP_LIST_REDUCTION_INSCAN])
+ {
+ gcc_assert (code->block->next->next->op == EXEC_OMP_SCAN);
+ gcc_assert (code->block->next->next->next->next == NULL);
+ locus *cloc = &code->block->next->next->loc;
+ location_t loc = gfc_get_location (cloc);
+
+ gfc_code code2 = *code->block->next;
+ code2.next = NULL;
+ tmp = gfc_trans_code (&code2);
+ tmp = build2 (OMP_SCAN, void_type_node, tmp, NULL_TREE);
+ SET_EXPR_LOCATION (tmp, loc);
+ gfc_add_expr_to_block (&body, tmp);
+ input_location = loc;
+ tree c = gfc_trans_omp_clauses (&body,
+ code->block->next->next->ext.omp_clauses,
+ *cloc);
+ code2 = *code->block->next->next->next;
+ code2.next = NULL;
+ tmp = gfc_trans_code (&code2);
+ tmp = build2 (OMP_SCAN, void_type_node, tmp, c);
+ SET_EXPR_LOCATION (tmp, loc);
+ }
+ else
+ tmp = gfc_trans_omp_code (code->block->next, true);
gfc_add_expr_to_block (&body, tmp);
/* Label for cycle statements (if needed). */
= code->ext.omp_clauses->lists[OMP_LIST_LASTPRIVATE];
/* Reduction is allowed on simd, do, parallel and teams.
Duplicate it on all of them, but omit on do if
- parallel is present. */
+ parallel is present; additionally, inscan applies to do/simd only. */
for (int i = OMP_LIST_REDUCTION; i <= OMP_LIST_REDUCTION_TASK; i++)
{
- if (mask & GFC_OMP_MASK_TEAMS)
+ if (mask & GFC_OMP_MASK_TEAMS
+ && i != OMP_LIST_REDUCTION_INSCAN)
clausesa[GFC_OMP_SPLIT_TEAMS].lists[i]
= code->ext.omp_clauses->lists[i];
- if (mask & GFC_OMP_MASK_PARALLEL)
+ if (mask & GFC_OMP_MASK_PARALLEL
+ && i != OMP_LIST_REDUCTION_INSCAN)
clausesa[GFC_OMP_SPLIT_PARALLEL].lists[i]
= code->ext.omp_clauses->lists[i];
else if (mask & GFC_OMP_MASK_DO)
end do
!$omp end parallel
-!$omp parallel reduction(inscan,+:a) ! { dg-error "'inscan' 'reduction' clause on 'parallel' construct" }
+!$omp parallel reduction(inscan,+:a) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" }
do i=1,10
a = a + 1
end do
a = a + 1
end do
-!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" }
-do i=1,10
- a = a + 1
-end do
-
-!$omp simd reduction(inscan,+:a) ! { dg-error "'inscan' 'reduction' clause but not in 'scan' directive clause" }
-do i=1,10
- a = a + 1
-end do
-
! ------------ do ------------
!$omp parallel
!$omp do reduction(+:a)
end do
!$omp end parallel
-!$omp parallel
-!$omp do reduction(inscan,+:a) ! { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" }
-do i=1,10
- a = a + 1
-end do
-!$omp end parallel
-
! ------------ section ------------
!$omp parallel
!$omp sections reduction(+:a)
!$omp end parallel
!$omp parallel
-!$omp sections reduction(inscan,+:a) ! { dg-error "'inscan' 'reduction' clause on 'sections' construct" }
+!$omp sections reduction(inscan,+:a) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" }
!$omp section
a = a + 1
!$omp end sections
end
! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(\\\+:a\\)" 2 "original" } }
-! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(inscan,\\\+:a\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(task,\\\+:a\\)" 1 "original" } }
-! { dg-final { scan-tree-dump-times "#pragma omp parallel\[\n\r\]" 8 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp parallel\[\n\r\]" 7 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(\\\+:a\\)" 2 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(task,\\\+:a\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(inscan,\\\+:a\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(task,\\\+:a\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(\\\+:a\\)" 2 "original" } }
-! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(task,\\\+:a\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp target in_reduction\\(\\\+:b\\)" 1 "original" } }
! { dg-final { scan-tree-dump-times "#pragma omp task in_reduction\\(\\\+:a\\)" 1 "original" } }
a = a + 1
!$omp end task ! { dg-error "Unexpected !.OMP END TASK statement" }
-!$omp taskloop reduction(inscan,+:a) in_reduction(+:b) ! { dg-error "34: Only DEFAULT permitted as reduction-modifier in REDUCTION clause" }
+!$omp taskloop reduction(inscan,+:a) in_reduction(+:b) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" }
+ ! { dg-error "34: With INSCAN at .1., expected loop body with ..OMP SCAN between two structured-block-sequences" "" { target *-*-* } .-1 }
+ ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" "" { target *-*-* } .-2 }
+ ! { dg-error "'inscan' and non-'inscan' 'reduction' clauses on the same construct" "" { target *-*-* } .-3 }
do i=1,10
a = a + 1
end do
a = a + 1
end do
-!$omp teams reduction(inscan,+:b) ! { dg-error "31: Only DEFAULT permitted as reduction-modifier in REDUCTION clause" }
+!$omp teams reduction(inscan,+:b) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" }
+ ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" "" { target *-*-* } .-1 }
a = a + 1
!$omp end teams
--- /dev/null
+! { dg-do compile }
+
+implicit none
+integer :: a, b, i
+a = 0
+
+!$omp simd reduction(inscan,+:a) ! { dg-error "30: With INSCAN at .1., expected loop body with ..OMP SCAN between two structured-block-sequences" }
+do i=1,10
+ a = a + 1
+end do
+
+!$omp parallel
+!$omp do reduction(inscan,+:a) ! { dg-error "28: With INSCAN at .1., expected loop body with ..OMP SCAN between two structured-block-sequences" }
+do i=1,10
+ a = a + 1
+end do
+!$omp end parallel
+end
--- /dev/null
+implicit none
+integer :: a, b, i
+a = 0
+
+!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" }
+do i=1,10
+ a = a + 1
+end do
+end
--- /dev/null
+module m
+ integer a, b
+end module m
+
+subroutine f1
+ use m
+ !$omp scan inclusive (a) ! { dg-error "Unexpected ..OMP SCAN at .1. outside loop construct with 'inscan' REDUCTION clause" }
+ !$omp scan exclusive (b) ! { dg-error "Unexpected ..OMP SCAN at .1. outside loop construct with 'inscan' REDUCTION clause" }
+end
+
+subroutine f2 (c, d, e, f)
+ use m
+ implicit none
+ integer i, l, c(*), d(*), e(64), f(64)
+ l = 1
+
+ !$omp do reduction (inscan, +: a) reduction (+: b) ! { dg-error "'inscan' and non-'inscan' 'reduction' clauses on the same construct" }
+ do i = 1, 64
+ block
+ b = b + 1
+ a = a + c(i)
+ end block
+ !$omp scan inclusive (a)
+ d(i) = a
+ end do
+
+ !$omp do reduction (+: a) reduction (inscan, +: b) ! { dg-error "'inscan' and non-'inscan' 'reduction' clauses on the same construct" }
+ do i = 1, 64
+ block
+ a = a + 1
+ b = b + c(i)
+ end block
+ !$omp scan inclusive (b)
+ d(i) = b
+ end do
+
+ !$omp do reduction (inscan, +: e)
+ do i = 1, 64
+ block
+ e(1) = e(1) + c(i)
+ e(2) = e(2) + c(i)
+ end block
+ !$omp scan inclusive (a, e)
+ block
+ d(1) = e(1)
+ f(2) = e(2)
+ end block
+ end do
+
+ !$omp do reduction (inscan, +: e(:2)) ! { dg-error "Syntax error in OpenMP variable list" }
+ do i = 1, 64
+ block
+ e(1) = e(1) + c(i)
+ e(2) = e(2) + c(i)
+ end block
+ !$omp scan inclusive (a, e) ! { dg-error "outside loop construct with 'inscan' REDUCTION clause" }
+ block
+ d(1) = e(1)
+ f(2) = e(2)
+ end block
+ end do
+
+ !$omp do reduction (inscan, +: a) ordered ! { dg-error "ORDERED clause specified together with 'inscan' REDUCTION clause" }
+ do i = 1, 64
+ a = a + c(i)
+ !$omp scan inclusive (a)
+ d(i) = a
+ end do
+
+ !$omp do reduction (inscan, +: a) ordered(1) ! { dg-error "ORDERED clause specified together with 'inscan' REDUCTION clause" }
+ do i = 1, 64
+ a = a + c(i)
+ !$omp scan inclusive (a)
+ d(i) = a
+ end do
+
+ !$omp do reduction (inscan, +: a) schedule(static) ! { dg-error "SCHEDULE clause specified together with 'inscan' REDUCTION clause" }
+ do i = 1, 64
+ a = a + c(i)
+ !$omp scan inclusive (a)
+ d(i) = a
+ end do
+
+ !$omp do reduction (inscan, +: a) schedule(static, 2) ! { dg-error "SCHEDULE clause specified together with 'inscan' REDUCTION clause" }
+ do i = 1, 64
+ a = a + c(i)
+ !$omp scan inclusive (a)
+ d(i) = a
+ end do
+
+ !$omp do reduction (inscan, +: a) schedule(nonmonotonic: dynamic, 2) ! { dg-error "SCHEDULE clause specified together with 'inscan' REDUCTION clause" }
+ do i = 1, 64
+ a = a + c(i)
+ !$omp scan inclusive (a)
+ d(i) = a
+ end do
+end
+
+subroutine f3 (c, d)
+ use m
+ implicit none
+ integer i, c(64), d(64)
+ !$omp teams reduction (inscan, +: a) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause at" }
+ ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 }
+ ! ...
+ !$omp end teams
+
+ !$omp target parallel do reduction (inscan, +: a) map (c, d)
+ ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 }
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a)
+ a = a + c(i)
+ end do
+ !$omp teams
+ !$omp distribute parallel do reduction (inscan, +: a)
+ ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 }
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a)
+ a = a + c(i)
+ end do
+ !$omp end teams
+
+ !$omp distribute parallel do simd reduction (inscan, +: a)
+ ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 }
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a)
+ a = a + c(i)
+ end do
+end
+
+subroutine f4 (c, d)
+ use m
+ implicit none
+ integer i, c(64), d(64)
+ !$omp taskloop reduction (inscan, +: a) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" }
+ ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 }
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a)
+ a = a + c(i)
+ end do
+end
+
+subroutine f7
+ use m
+ implicit none
+ integer i
+ !$omp simd reduction (inscan, +: a)
+ do i = 1, 64
+ if (i == 23) then ! { dg-error "invalid exit from OpenMP structured block" "" { target c++ } .+1 }
+ cycle ! { dg-error "invalid branch to/from OpenMP structured block" "" { target c } }
+ elseif (i == 27) then
+ goto 123 ! Diagnostic by ME, see scan-7.f90
+ ! { dg-warning "is not in the same block as the GOTO statement" "" { target *-*-* } .-1 }
+ endif
+ !$omp scan exclusive (a)
+ block
+123 a = 0 ! { dg-error "jump to label 'l1'" "" { target c++ } }
+ ! { dg-warning "is not in the same block as the GOTO statement" "" { target *-*-* } .-1 }
+ if (i == 33) then ! { dg-error "invalid exit from OpenMP structured block" "" { target c++ } .+1 }
+ cycle ! { dg-error "invalid branch to/from OpenMP structured block" "" { target c } }
+ end if
+ end block
+ end do
+end
+
+subroutine f8 (c, d, e, f)
+ use m
+ implicit none
+ integer i, c(64), d(64), e(64), f(64)
+ !$omp do reduction (inscan, +: a, b) ! { dg-error "With INSCAN at .1., expected loop body with ..OMP SCAN between two structured-block-sequences" }
+ do i = 1, 64
+ block
+ a = a + c(i)
+ b = b + d(i)
+ end block
+ !$omp scan inclusive (a) inclusive (b) ! { dg-error "Unexpected junk after ..OMP SCAN" }
+ block
+ e(i) = a
+ f(i) = b
+ end block
+ end do
+
+ !$omp do reduction (inscan, +: a, b) ! { dg-error "With INSCAN at .1., expected loop body with ..OMP SCAN between two structured-block-sequences" }
+ do i = 1, 64
+ block
+ a = a + c(i)
+ b = b + d(i)
+ end block
+ !$omp scan ! { dg-error "Expected INCLUSIVE or EXCLUSIVE clause" }
+ block
+ e(i) = a
+ f(i) = b
+ end block
+ end do
+end
+
+subroutine f9
+ use m
+ implicit none
+ integer i
+! The first error (exit) causes two follow-up errors:
+ !$omp simd reduction (inscan, +: a) ! { dg-error "With INSCAN at .1., expected loop body with ..OMP SCAN between two structured-block-sequences" }
+ do i = 1, 64
+ if (i == 23) &
+ exit ! { dg-error "EXIT statement at .1. terminating ..OMP DO loop" } */
+ !$omp scan exclusive (a) ! { dg-error "Unexpected ..OMP SCAN at .1. outside loop construct with 'inscan' REDUCTION clause" }
+ a = a + 1
+ end do
+end
--- /dev/null
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+
+module m
+ integer :: a, b
+end module m
+
+subroutine f1 (c, d)
+ use m
+ implicit none
+ integer i, c(*), d(*)
+ !$omp simd reduction (inscan, +: a)
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a)
+ a = a + c(i)
+ end do
+end
+
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp scan exclusive\\(a\\)" 1 "original" } }
--- /dev/null
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+
+module m
+ integer :: a, b
+end module m
+
+subroutine f1 (c, d)
+ use m
+ implicit none
+ integer i, c(*), d(*)
+ !$omp do reduction (inscan, +: a)
+ do i = 1, 64
+ d(i) = a
+ !$omp scan inclusive (a)
+ a = a + c(i)
+ end do
+end
+
+! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp scan inclusive\\(a\\)" 1 "original" } }
--- /dev/null
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+
+module m
+ integer a, b
+end module m
+
+subroutine f1 (c, d)
+ use m
+ implicit none
+ integer c(*), d(*), i
+ !$omp do simd reduction (inscan, +: a)
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a)
+ a = a + c(i)
+ end do
+end
+
+! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp scan exclusive\\(a\\)" 1 "original" } }
--- /dev/null
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+
+integer function foo(a,b, n) result(r)
+ implicit none
+ integer :: a(n), b(n), n, i
+ r = 0
+ !$omp parallel do reduction (inscan, +:r) default(none) firstprivate (a, b)
+ do i = 1, n
+ r = r + a(i)
+ !$omp scan inclusive (r)
+ b(i) = r
+ end do
+end
+
+! { dg-final { scan-tree-dump-times "#pragma omp parallel firstprivate\\(a\\) firstprivate\\(b\\) default\\(none\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(inscan,\\\+:r\\) nowait" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp scan inclusive\\(r\\)" 1 "original" } }
--- /dev/null
+module m
+ integer a, b
+end module m
+
+subroutine f3 (c, d)
+ use m
+ implicit none
+ integer i, c(64), d(64)
+ !$omp parallel reduction (inscan, +: a) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" }
+ ! ...
+ !$omp end parallel
+ !$omp sections reduction (inscan, +: a) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" }
+ !$omp section
+ ! ...
+ !$omp end sections
+end
--- /dev/null
+module m
+ integer a, b
+end module m
+
+subroutine f2 (c, d, e, f)
+ use m
+ implicit none
+ integer i, l, c(*), d(*), e(64), f(64)
+ l = 1
+
+ !$omp do reduction (inscan, +: a) linear (l) ! { dg-error "'inscan' 'reduction' clause used together with 'linear' clause for a variable other than loop iterator" }
+ do i = 1, 64
+ block
+ a = a + c(i)
+ l = l + 1
+ end block
+ !$omp scan inclusive (a)
+ d(i) = a
+ end do
+end
+
+subroutine f5 (c, d)
+ use m
+ implicit none
+ integer i, c(64), d(64)
+ !$omp simd reduction (inscan, +: a)
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a, b) ! { dg-error "'b' specified in 'exclusive' clause but not in 'inscan' 'reduction' clause on the containing construct" }
+ a = a + c(i)
+ end do
+end
+
+subroutine f6 (c, d)
+ use m
+ implicit none
+ integer i, c(64), d(64)
+ !$omp simd reduction (inscan, +: a, b) ! { dg-error "'b' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" }
+ do i = 1, 64
+ d(i) = a
+ !$omp scan exclusive (a)
+ a = a + c(i)
+ end do
+end
+
+subroutine f7
+ use m
+ implicit none
+ integer i
+ !$omp simd reduction (inscan, +: a)
+ do i = 1, 64
+ if (i == 27) goto 123 ! { dg-error "invalid branch to/from OpenMP structured block" }
+ ! { dg-warning "is not in the same block as the GOTO statement" "" { target *-*-* } .-1 }
+ !$omp scan exclusive (a)
+ block
+123 a = 0 ! { dg-error "jump to label 'l1'" "" { target c++ } }
+ ! { dg-warning "is not in the same block as the GOTO statement" "" { target *-*-* } .-1 }
+ end block
+ end do
+end
--- /dev/null
+! { dg-require-effective-target size32plus }
+
+module m
+ implicit none
+ integer r, a(1024), b(1024)
+contains
+subroutine foo (a, b)
+ integer, contiguous :: a(:), b(:)
+ integer :: i
+ !$omp do reduction (inscan, +:r)
+ do i = 1, 1024
+ r = r + a(i)
+ !$omp scan inclusive(r)
+ b(i) = r
+ end do
+end
+
+integer function bar ()
+ integer s, i
+ s = 0
+ !$omp parallel
+ !$omp do reduction (inscan, +:s)
+ do i = 1, 1024
+ s = s + 2 * a(i)
+ !$omp scan inclusive(s)
+ b(i) = s
+ end do
+ !$omp end parallel
+ bar = s
+end
+
+subroutine baz (a, b)
+ integer, contiguous :: a(:), b(:)
+ integer :: i
+ !$omp parallel do reduction (inscan, +:r)
+ do i = 1, 1024
+ r = r + a(i)
+ !$omp scan inclusive(r)
+ b(i) = r
+ end do
+end
+
+integer function qux ()
+ integer s, i
+ s = 0
+ !$omp parallel do reduction (inscan, +:s)
+ do i = 1, 1024
+ s = s + 2 * a(i)
+ !$omp scan inclusive(s)
+ b(i) = s
+ end do
+ qux = s
+end
+end module m
+
+program main
+ use m
+ implicit none
+
+ integer s, i
+ s = 0
+ do i = 1, 1024
+ a(i) = i-1
+ b(i) = -1
+ end do
+
+ !$omp parallel
+ call foo (a, b)
+ !$omp end parallel
+ if (r /= 1024 * 1023 / 2) &
+ stop 1
+ do i = 1, 1024
+ s = s + i-1
+ if (b(i) /= s) then
+ stop 2
+ else
+ b(i) = 25
+ endif
+ end do
+
+ if (bar () /= 1024 * 1023) &
+ stop 3
+ s = 0
+ do i = 1, 1024
+ s = s + 2 * (i-1)
+ if (b(i) /= s) then
+ stop 4
+ else
+ b(i) = -1
+ end if
+ end do
+
+ r = 0
+ call baz (a, b)
+ if (r /= 1024 * 1023 / 2) &
+ stop 5
+ s = 0
+ do i = 1, 1024
+ s = s + i-1
+ if (b(i) /= s) then
+ stop 6
+ else
+ b(i) = -25
+ endif
+ end do
+
+ if (qux () /= 1024 * 1023) &
+ stop 6
+ s = 0
+ do i = 1, 1024
+ s = s + 2 * (i-1)
+ if (b(i) /= s) &
+ stop 7
+ end do
+end program