Building on Week 5’s work with the TASK construct and fixes for shared/private variables, Week 6 focused on making shared variables work reliably in the TASK construct and adding the TASKWAIT construct. Last week, I planned to enhance TASK support and implement teams, but debugging TASK issues took priority. This week, I made PR #7905, and spent about 25 hours tackling these challenges through careful debugging and implementation.

Debugging and Fixing TASK Construct Issues

This week, I worked on ensuring shared variables function correctly in the TASK construct, a task that proved more complex than expected. I faced multiple segfaults and struggled to pinpoint the cause, eventually realizing it was a mix of two or three bugs. To tackle this, I took a step-by-step approach, starting from scratch by writing lowered Fortran code with GOMP calls for TASK. This revealed the first issue: the task data struct size sent to GOMP_TASK was incorrect, causing segfaults. The second problem was that shared variables in OMPRegion had garbage initial values. Debugging the LLVM IR showed that c_f_pointer was using the address of the struct member instead of its value for non-array shared variables, leading to junk data.

Implementation Details and Fixes in PR #7905

In PR #7905, I addressed these issues to support shared variables in the TASK construct and implemented the TASKWAIT construct, contributing to Issue #7332 and Issue #7365 while fixing Issue #7904. I corrected the task data struct size calculation for GOMP_TASK calls and fixed the c_f_pointer issue in asr_to_llvm.cpp by ensuring it references the correct memory address for non-array shared variables. This required debugging of the LLVM IR to identify all failure scenarios. Additionally, I added TASKWAIT to synchronize tasks, ensuring proper execution flow.

Examples: TASK and TASKWAIT Constructs

Below are the MREs from PR #7905 that demonstrate the improved TASK construct with shared variables and the new TASKWAIT construct.

View MRE for TASK with Pointers (bindc5.f90)
1module thread_data_module_tasks
2  use, intrinsic :: iso_c_binding
3  implicit none
4  type :: thread_data
5    type(c_ptr) :: i_ptr
6  end type thread_data
7end module thread_data_module_tasks
8
9program bindc5
10    use thread_data_module_tasks
11    use, intrinsic :: iso_c_binding
12    implicit none
13    integer, target :: i
14    integer, pointer :: ptr_i, ptr_i2
15    type(thread_data), pointer :: d,d1
16    type(thread_data), target :: threadData, taskData
17    type(c_ptr) :: threadPtr, taskPtr
18
19    i=0
20
21    threadData%i_ptr = c_loc(i)
22    threadPtr = c_loc(threadData)
23    call c_f_pointer(threadPtr, d)
24    call c_f_pointer(d%i_ptr, ptr_i)
25
26    ptr_i=2
27
28    taskData%i_ptr = d%i_ptr
29    taskPtr = c_loc(taskData)
30    call c_f_pointer(taskPtr, d1)
31    call c_f_pointer(d1%i_ptr, ptr_i2)
32
33    ptr_i2=3
34
35    print*, i,ptr_i2,ptr_i
36    if(i/=ptr_i2 .and. i/=ptr_i) error stop
37end program bindc5
View MRE for TASK with Shared Counter (openmp_55.f90)
1program openmp_55
2    use omp_lib
3    implicit none
4    integer :: i,n=10,counter
5    call omp_set_num_threads(8)
6counter=0
7  !$OMP PARALLEL 
8    !$OMP MASTER
9      do i = 1, n
10          !$OMP TASK shared(counter)
11                counter=counter+1
12              print *, "Task Done by TID:-",omp_get_thread_num()
13          !$OMP END TASK
14      end do
15    !$OMP END MASTER
16  !$OMP END PARALLEL
17      if(counter/=10) error stop
18end program openmp_55
View MRE for TASK with Shared Counter (openmp_56.f90)
1program openmp_56
2    use omp_lib
3    implicit none
4    integer :: counter
5    counter=0
6    call omp_set_num_threads(10)
7
8    !$omp parallel
9        !$omp task shared(counter)
10            counter=counter+1
11            print *, "Task done by TID:-",omp_get_thread_num()
12        !$omp end task
13    !$omp end parallel
14    if(counter/=10) error stop
15end program openmp_56
View MRE for TASK with TASKWAIT (openmp_57.f90)
1program openmp_57
2  use omp_lib
3  implicit none
4  integer, parameter :: N = 5
5  integer :: A(N)
6  integer :: i, index,total
7
8  A = 1
9  total=0
10  index=1
11
12  !$omp parallel
13  !$omp single
14  do i = 1, N
15    !$omp task shared(A)
16        total = total + A(index) * 2
17        index=index+1
18    !$omp end task
19  end do
20  !$omp end single
21  !$omp taskwait
22  !$omp end parallel
23
24  print *, "Total = ", total, index
25  if(total/=10) error stop
26end program openmp_57

Next Steps

For Week 7, I plan to:

  • Implement the teams construct using the OMPRegion node (Issue #7363).
  • Fix more bugs and implement other clauses if possible for TASKS

I am grateful to my mentors, Ondrej Certik, Pranav Goswami, and Gaurav Dhingra, for their expert guidance during this debugging process. I also thank the LFortran community for their support and encouragement.