Fortran/OpenMP: strict modifier on grainsize/num_tasks

This patch adds support for the 'strict' modifier on grainsize/num_tasks
clauses, an OpenMP 5.1 feature supported in C/C++ since commit
r12-3066-g3bc75533d1f87f0617be6c1af98804f9127ec637

gcc/fortran/ChangeLog:

	* dump-parse-tree.c (show_omp_clauses): Handle 'strict' modifier
	on grainsize/num_tasks
	* gfortran.h (gfc_omp_clauses): Add grainsize_strict
	and num_tasks_strict.
	* trans-openmp.c (gfc_trans_omp_clauses, gfc_split_omp_clauses):
	Handle 'strict' modifier on grainsize/num_tasks.
	* openmp.c (gfc_match_omp_clauses): Likewise.

libgomp/ChangeLog:

	* testsuite/libgomp.fortran/taskloop-4-a.f90: New test.
	* testsuite/libgomp.fortran/taskloop-4.f90: New test.
	* testsuite/libgomp.fortran/taskloop-5-a.f90: New test.
	* testsuite/libgomp.fortran/taskloop-5.f90: New test.
This commit is contained in:
Tobias Burnus 2021-08-23 15:13:30 +02:00
parent 12dc8ab983
commit d4de7e32ef
8 changed files with 326 additions and 5 deletions

View File

@ -1805,6 +1805,8 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
if (omp_clauses->grainsize)
{
fputs (" GRAINSIZE(", dumpfile);
if (omp_clauses->grainsize_strict)
fputs ("strict: ", dumpfile);
show_expr (omp_clauses->grainsize);
fputc (')', dumpfile);
}
@ -1823,6 +1825,8 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
if (omp_clauses->num_tasks)
{
fputs (" NUM_TASKS(", dumpfile);
if (omp_clauses->num_tasks_strict)
fputs ("strict: ", dumpfile);
show_expr (omp_clauses->num_tasks);
fputc (')', dumpfile);
}

View File

@ -1490,7 +1490,7 @@ typedef struct gfc_omp_clauses
unsigned inbranch:1, notinbranch:1, nogroup:1;
unsigned sched_simd:1, sched_monotonic:1, sched_nonmonotonic:1;
unsigned simd:1, threads:1, depend_source:1, destroy:1, order_concurrent:1;
unsigned capture:1;
unsigned capture:1, grainsize_strict:1, num_tasks_strict:1;
ENUM_BITFIELD (gfc_omp_sched_kind) sched_kind:3;
ENUM_BITFIELD (gfc_omp_device_type) device_type:2;
ENUM_BITFIELD (gfc_omp_memorder) memorder:3;

View File

@ -1839,8 +1839,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
}
if ((mask & OMP_CLAUSE_GRAINSIZE)
&& c->grainsize == NULL
&& gfc_match ("grainsize ( %e )", &c->grainsize) == MATCH_YES)
continue;
&& gfc_match ("grainsize ( ") == MATCH_YES)
{
if (gfc_match ("strict : ") == MATCH_YES)
c->grainsize_strict = true;
if (gfc_match (" %e )", &c->grainsize) != MATCH_YES)
goto error;
continue;
}
break;
case 'h':
if ((mask & OMP_CLAUSE_HINT)
@ -2148,8 +2154,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
continue;
if ((mask & OMP_CLAUSE_NUM_TASKS)
&& c->num_tasks == NULL
&& gfc_match ("num_tasks ( %e )", &c->num_tasks) == MATCH_YES)
continue;
&& gfc_match ("num_tasks ( ") == MATCH_YES)
{
if (gfc_match ("strict : ") == MATCH_YES)
c->num_tasks_strict = true;
if (gfc_match (" %e )", &c->num_tasks) != MATCH_YES)
goto error;
continue;
}
if ((mask & OMP_CLAUSE_NUM_TEAMS)
&& c->num_teams == NULL
&& gfc_match ("num_teams ( %e )", &c->num_teams) == MATCH_YES)

View File

@ -3998,6 +3998,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_GRAINSIZE);
OMP_CLAUSE_GRAINSIZE_EXPR (c) = grainsize;
if (clauses->grainsize_strict)
OMP_CLAUSE_GRAINSIZE_STRICT (c) = 1;
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
}
@ -4013,6 +4015,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_NUM_TASKS);
OMP_CLAUSE_NUM_TASKS_EXPR (c) = num_tasks;
if (clauses->num_tasks_strict)
OMP_CLAUSE_NUM_TASKS_STRICT (c) = 1;
omp_clauses = gfc_trans_add_clause (c, omp_clauses);
}
@ -5964,8 +5968,12 @@ gfc_split_omp_clauses (gfc_code *code,
= code->ext.omp_clauses->nogroup;
clausesa[GFC_OMP_SPLIT_TASKLOOP].grainsize
= code->ext.omp_clauses->grainsize;
clausesa[GFC_OMP_SPLIT_TASKLOOP].grainsize_strict
= code->ext.omp_clauses->grainsize_strict;
clausesa[GFC_OMP_SPLIT_TASKLOOP].num_tasks
= code->ext.omp_clauses->num_tasks;
clausesa[GFC_OMP_SPLIT_TASKLOOP].num_tasks_strict
= code->ext.omp_clauses->num_tasks_strict;
clausesa[GFC_OMP_SPLIT_TASKLOOP].priority
= code->ext.omp_clauses->priority;
clausesa[GFC_OMP_SPLIT_TASKLOOP].final_expr

View File

@ -0,0 +1,86 @@
! { dg-do compile { target skip-all-targets } }
! Only used by taskloop-4.f90
! To avoid inlining
module m2
use m_taskloop4
implicit none (external, type)
contains
subroutine grainsize (a, b, c, d)
integer, value :: a, b, c, d
integer :: i, j, k
j = 0
k = 0
!$omp taskloop firstprivate (j, k) grainsize(d)
do i = a, b - 1, c
if (j == 0) then
!$omp atomic capture
k = v
v = v + 1
!$omp end atomic
if (k >= 64) &
stop 1
end if
j = j + 1
u(k) = j
end do
end
subroutine num_tasks (a, b, c, d)
integer, value :: a, b, c, d
integer :: i, j, k
j = 0
k = 0
!$omp taskloop firstprivate (j, k) num_tasks(d)
do i = a, b - 1, c
if (j == 0) then
!$omp atomic capture
k = v
v = v + 1
!$omp end atomic
if (k >= 64) &
stop 2
end if
j = j + 1
u(k) = j
end do
end
end module
program main
use m2
implicit none (external, type)
!$omp parallel
!$omp single
block
integer :: min_iters, max_iters, ntasks
! If grainsize is present, # of task loop iters is >= grainsize && < 2 * grainsize,
! unless # of loop iterations is smaller than grainsize.
if (test (0, 79, 1, 17, grainsize, ntasks, min_iters, max_iters) /= 79) &
stop 3
if (min_iters < 17 .or. max_iters >= 17 * 2) &
stop 4
if (test (-49, 2541, 7, 28, grainsize, ntasks, min_iters, max_iters) /= 370) &
stop 5
if (min_iters < 28 .or. max_iters >= 28 * 2) &
stop 6
if (test (7, 21, 2, 15, grainsize, ntasks, min_iters, max_iters) /= 7) &
stop 7
if (ntasks /= 1 .or. min_iters /= 7 .or. max_iters /= 7) &
stop 8
! If num_tasks is present, # of tasks is min (# of loop iters, num_tasks)
! and each task has at least one iteration.
if (test (-51, 2500, 48, 9, num_tasks, ntasks, min_iters, max_iters) /= 54) &
stop 9
if (ntasks /= 9) &
stop 10
if (test (0, 25, 2, 17, num_tasks, ntasks, min_iters, max_iters) /= 13) &
stop 11
if (ntasks /= 13) &
stop 12
end block
!$omp end single
!$omp end parallel
end program

View File

@ -0,0 +1,41 @@
! { dg-do run }
! { dg-options "-O2" }
! { dg-additional-sources taskloop-4-a.f90 }
module m_taskloop4
implicit none (type, external)
integer :: v, u(0:63)
contains
integer function test (a, b, c, d, fn, num_tasks, min_iters, max_iters)
integer, value :: a, b, c, d
interface
subroutine fn (n1, n2, n3, n4)
integer, value :: n1, n2, n3, n4
end
end interface
integer :: num_tasks, min_iters, max_iters
integer :: i, t
t = 0
u = 0
v = 0
call fn (a, b, c, d)
min_iters = 0
max_iters = 0
num_tasks = v
if (v /= 0) then
min_iters = u(0)
max_iters = u(0)
t = u(0)
do i = 1, v - 1
if (min_iters > u(i)) &
min_iters = u(i)
if (max_iters < u(i)) &
max_iters = u(i)
t = t + u(i)
end do
end if
test = t
end
end module

View File

@ -0,0 +1,95 @@
! { dg-do compile { target skip-all-targets } }
! Only used by taskloop-5-a.f90
! To avoid inlining
module m2
use m_taskloop5
implicit none (external, type)
contains
subroutine grainsize (a, b, c, d)
integer, value :: a, b, c, d
integer :: i, j, k
j = 0
k = 0
!$omp taskloop firstprivate (j, k) grainsize(strict:d)
do i = a, b - 1, c
if (j == 0) then
!$omp atomic capture
k = v
v = v + 1
!$omp end atomic
if (k >= 64) &
stop 3
w(k) = i
end if
j = j + 1
u(k) = j
end do
end
subroutine num_tasks (a, b, c, d)
integer, value :: a, b, c, d
integer :: i, j, k
j = 0
k = 0
!$omp taskloop firstprivate (j, k) num_tasks(strict:d)
do i = a, b - 1, c
if (j == 0) then
!$omp atomic capture
k = v
v = v + 1
!$omp end atomic
if (k >= 64) &
stop 4
w(k) = i
end if
j = j + 1
u(k) = j
end do
end
end module
program main
use m2
implicit none (external, type)
!$omp parallel
!$omp single
block
integer :: min_iters, max_iters, ntasks, sep
! If grainsize is present and has strict modifier, # of task loop iters is == grainsize,
! except that it can be smaller on the last task.
if (test (0, 79, 1, 17, grainsize, ntasks, min_iters, max_iters, sep) /= 79) &
stop 5
if (ntasks /= 5 .or. min_iters /= 11 .or. max_iters /= 17 .or. sep /= 4) &
stop
if (test (-49, 2541, 7, 28, grainsize, ntasks, min_iters, max_iters, sep) /= 370) &
stop 6
if (ntasks /= 14 .or. min_iters /= 6 .or. max_iters /= 28 .or. sep /= 13) &
stop
if (test (7, 21, 2, 15, grainsize, ntasks, min_iters, max_iters, sep) /= 7) &
stop 7
if (ntasks /= 1 .or. min_iters /= 7 .or. max_iters /= 7 .or. sep /= 1) &
stop 8
! If num_tasks is present, # of tasks is min (# of loop iters, num_tasks)
! and each task has at least one iteration. If strict modifier is present,
! first set of tasks has ceil (# of loop iters / num_tasks) iterations,
! followed by possibly empty set of tasks with floor (# of loop iters / num_tasks)
! iterations.
if (test (-51, 2500, 48, 9, num_tasks, ntasks, min_iters, max_iters, sep) /= 54) &
stop 9
if (ntasks /= 9 .or. min_iters /= 6 .or. max_iters /= 6 .or. sep /= 9) &
stop 10
if (test (0, 57, 1, 9, num_tasks, ntasks, min_iters, max_iters, sep) /= 57) &
stop 11
if (ntasks /= 9 .or. min_iters /= 6 .or. max_iters /= 7 .or. sep /= 3) &
stop 12
if (test (0, 25, 2, 17, num_tasks, ntasks, min_iters, max_iters, sep) /= 13) &
stop 13
if (ntasks /= 13 .or. min_iters /= 1 .or. max_iters /= 1 .or. sep /= 13) &
stop 14
end block
!$omp end single
!$omp end parallel
end program

View File

@ -0,0 +1,75 @@
! { dg-do run }
! { dg-options "-O2" }
! { dg-additional-sources taskloop-5-a.f90 }
module m_taskloop5
implicit none (type, external)
integer :: u(0:63), v, w(0:63)
contains
integer function test (a, b, c, d, fn, num_tasks, min_iters, max_iters, sep)
integer, value :: a, b, c, d
interface
subroutine fn (n1, n2, n3, n4)
integer, value :: n1, n2, n3, n4
end
end interface
integer :: num_tasks, min_iters, max_iters, sep
integer :: i, j, t
t = 0
u = 0
v = 0
call fn (a, b, c, d)
min_iters = 0
max_iters = 0
num_tasks = v
sep = v
if (v /= 0) then
min_iters = u(0)
max_iters = u(0)
t = u(0)
do i = 1, v - 1
if (min_iters > u(i)) &
min_iters = u(i)
if (max_iters < u(i)) &
max_iters = u(i)
t = t + u(i)
end do
if (min_iters /= max_iters) then
do i = 0, v - 2
block
integer :: min_idx
min_idx = i
do j = i + 1, v - 1
if (w(min_idx) > w(j)) &
min_idx = j
end do
if (min_idx /= i) then
block
integer tem
tem = u(i)
u(i) = u(min_idx)
u(min_idx) = tem
tem = w(i)
w(i) = w(min_idx)
w(min_idx) = tem
end block
end if
end block
end do
if (u(0) /= max_iters) &
stop 1
do i = 1, v - 1
if (u(i) /= u(i - 1)) then
if (sep /= v .or. u(i) /= min_iters) &
stop 2
sep = i;
end if
end do
end if
end if
test = t
end
end module