<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/136357>136357</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[flang][OpenMP] flaky firstprivate/lastprivate behavior due to misplaced barriers
</td>
</tr>
<tr>
<th>Labels</th>
<td>
flang
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
eugeneepshteyn
</td>
</tr>
</table>
<pre>
(Thanks goes to @ebaskakov for doing the actual investigation.)
The variables in firstprivate/lastprivate don't get set properly in some cases, resulting in flaky behavior.
Consider the following test:
```
implicit none
integer :: i, n
logical :: first
first = .true.
n = 42
!$omp parallel do firstprivate(n) firstprivate(first) lastprivate(n)
do i=1,10
if (first) then
if (n/=42) stop -1*n
first = .false.
end if
n = 100
end do
!$omp end parallel do
if (n/=100) stop -2*n
print *,'passed'
end
```
Using the following flang on x86_64:
```
$ flang --version
flang version 21.0.0git (https://github.com/eugeneepshteyn/llvm-project.git 31ddaef8d18d643ff4c343d03ddfe2edae7d22a2)
Target: x86_64-unknown-linux-gnu
Thread model: posix
Build config: +unoptimized, +assertions
```
... results in the following behavior:
```
$ ./a.out
Fortran STOP: code -100
Fortran STOP: code -100
Fortran STOP: code -100
$ ./a.out
Fortran STOP: code -100
$ ./a.out
Fortran STOP: code -100
$ ./a.out
Fortran STOP: code -100
Fortran STOP: code -100
$ ./a.out
passed
```
It seems that `n` is already set to 100, while it should still have the value of 42.
Looking at LLVM IR output of `flang -fopenmp -g -O0 -S -emit-llvm firstprivate.f90`:
Load `first` and `n` passed as the structure of two fields:
```
define internal void @_QQmain..omp_par(ptr noalias %tid.addr, ptr noalias %zero.addr, ptr %0) #1 !dbg !26 {
omp.par.entry:
%gep_ = getelementptr { ptr, ptr }, ptr %0, i32 0, i32 0
%loadgep_ = load ptr, ptr %gep_, align 8, !align !29
%gep_1 = getelementptr { ptr, ptr }, ptr %0, i32 0, i32 1
%loadgep_2 = load ptr, ptr %gep_1, align 8, !align !29
...
```
Bbarrier:
```
omp.par.region1: ; preds = %omp.par.region
%omp_global_thread_num2 = call i32 @__kmpc_global_thread_num(ptr @4)
call void @__kmpc_barrier(ptr @3, i32 %omp_global_thread_num2)
br label %omp.private.init, !dbg !30
omp.private.init: ; preds = %omp.par.region1
br label %omp.private.copy, !dbg !30
```
... but then the values for `first` and `n` are loaded via `loadgep_*` pointers:
```
omp.private.copy: ; preds = %omp.private.init
%2 = load i32, ptr %loadgep_, align 4, !dbg !31
store i32 %2, ptr %omp.private.alloc, align 4, !dbg !31
%3 = load i32, ptr %loadgep_2, align 4, !dbg !32
store i32 %3, ptr %omp.private.alloc4, align 4, !dbg !32
br label %omp.wsloop.region, !dbg !32
```
Since the load happens after the barrier, some threads could have already set the value of `n` to 100.
It seems that the loads of the values from the passed structure should happen before the barrier.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJy0V82O2zgMfhrlQsSw5Z8khxySDAIUaNF2O7vXQLFoRzuyZEhyptOnX0i2M07mD0WxRYGJKIr8SH0kZWatqBXimuRbkt_NWOdO2qyxq1Ehtvbk8EnNjpo_rQld3p-YerBQa7TgNJAsxiOzD-xBn6HSBrgWqgZ3QmCl65gEoc5onaiZE1pFhK5IvCHx5v6EcGZGsKNEC0JBJYx1rRFn5pDQvWSXFXCtCF04qNGBRQet0S0a-eSPWd0glMyiJXQHBm0nnUfgLUr28ARHPLGz0CaC3vFOKys4moCx0lLqx4AYrSOpVyBFPPyPNwCiaaUohQOlFXqJUA5rNOCV0w0I71YFValrUTI57oSAwkb4BSS9g8iZDqMgVEGQ0bAgNCE0000LLTNMSpTA9U1KlorQ1a2sd0JXMMnXoBoMg7cjSHqXELpL4kEGICqYnnYnVJe9cVcRuifpXUa9hnW6hXlC6GaqOImsYtIOofl_qDiI6rLso03iEYHf5vomdi-cxB-yPUXij1-g0AuU1gjlgNANoTtCFy2zFjmhCxJvUPGbGyXx5m87UvT5-ivJVA1awc9lcSiyl0wgNBuU5vMzGiu0d95LhjXQJIqjuBYezPLkXGu9HbondF8Ld-qOUakbQvfXpeXJLs_NvDX6Xyxd5M-nCecMqyVPlrzI0qrKyjRLeZxyXiFFznDBKWW0v-Z7Zmr07B3Qzzv1oPSjmkuhup_zWnWh4AwyDo3mKL1qq634SeLNthOSQ6lVJWovJ3TbKd060YhfPo07L_EpNb6A7U1aoigaii4U8XVSx9J7PZsRoXsW6c75wtxr4wxT8OP-6zePotQcYd7z5Y-3f9fb_63_u-ZgoPR1Dj_5ZoiNBXdiDkgRK1LEICww6W_6KbRKp0PR0R08noREEA7sSXeSg3VCSjixM4ZbOzPZIegKMhr1MD5r_eBvkTn4_PmfL_DpL9CdazvntUgRD9VQ6RZV08K8hvnXGOY_YI6NcHPP6atuFVWrgLwng7fPeLATmlARA1P8EkYfMTAbwFlnutJ1JgB0j74zouT2Ja84VkJh6NFGMQlnLbifUYfv3xsmVBTppj20zBC6bJ0BpZkUzAKhuRM8Ypwbn6qbrV9o9NUeoXloRISmiW9f_Fj7P7QAstiSeKObNmqZiVA589SD9G0ur7E9hD5Yo0OJDSoXzC223uzF-uLu2tEOREph8mMwJzXjF5N-cWWld-eXTIpawbIv5aRfebirKa7kz4Elt8Doe8iSj6BFUXRzu9sjM0bgK_1kzLjBWmiVhD6WbqE1yG0AQWh-reOx9sJDLfWRyYMLDfKguqbHXTIpQ1yeP4eHpi1fag48IlmcjRM3HLvwrj834r5op2PO3oQwmjsakOyI8hLBUExCCTekbaBfOrSPF1ofJyN511Wp26fXXN2MgWPnwjviuZ3Y8CJ8q8SZwcAN5HAWzItH3vhR7nuADnX8Spm_QPdmiNM8DOycsFKkdMLKZ_cjMbObsPs8WacNjrc3NTD1yKTU5UeWCM3Tj9DQt43Ql3DS9-BkH5m6ZcCjlVq3Y8W8PHFzLT-EKvtpEuI5sbZFZYFVbnhuX-pg17_be75bKMNECrPoanhN59JIm36iDTPqegaOnm0YExMWGt2E9TBVnsfJMAt7pHDEyqdygjSa8XXKV-mKzXCdLLI8jrO0SGen9SpLeV4ei8UyLousPCY5X2VZUS7ilJV5ls7EmsY0j7NkmaxoEadRktI4oXy5zGmWsIL7T6eGCRn5SRlpU8-EtR2uk7RI88UsXIQNH2WUhllLKPXfZ2YdnovHrrYki6Wwzj6bcMLJ8CXXn8jvSL792qL68o3kd8MX0TtfWuOLDXiHPtONsK1kJfIxIXbWGbl-523rkdy8aAndh8gsofshuPOa_hcAAP__qVlgbA">