<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">