[flang][OpenMP][CUDA] Place privatized device allocatable descriptors in managed memory (#187114)
When an OpenMP private clause privatizes a CUDA Fortran allocatable
device array, the Fortran descriptor for the private copy must be
accessible from both the host and the GPU. Without this change, the
descriptor lives on the host stack (via the OpenMP runtime's
CreateAlloca), which a CUF kernel running on the GPU cannot
dereference—resulting in cudaErrorIllegalAddress.
This patch modifies the omp.private init/dealloc region generation in
PrivateReductionUtils.cpp with three changes:
1. Allocate the descriptor in managed memory
2. Set allocator_idx = 2 on the null fir.embox
3. Free the managed descriptor
Source example:
```
real(8), device, allocatable :: adev(:)
!$omp parallel private(adev)
allocate(adev(10))
!$cuf kernel do <<<*,*>>>
do i = 1, 10
adev(i) = 1.0d0
end do
deallocate(adev)
!$omp end parallel
```
IR before this change:
```
omp.private {type = private} @... : !fir.box<!fir.heap<!fir.array<?xf64>>> init {
^bb0(%arg0: !fir.ref<!fir.box<...>>, %arg1: !fir.ref<!fir.box<...>>):
...
fir.if %3 {
%5 = fir.embox %1(%4) : (...) -> !fir.box<...> // no allocator_idx
fir.store %5 to %arg1 // host-stack alloca
}
omp.yield(%arg1 : ...) // yields host alloca
} dealloc {
...
fir.if %3 { fir.freemem %1 }
omp.yield // no cuf.free
}
```
IR after this change:
```
omp.private {type = private} @... : !fir.box<!fir.heap<!fir.array<?xf64>>> init {
^bb0(%arg0: !fir.ref<!fir.box<...>>, %arg1: !fir.ref<!fir.box<...>>):
%0 = cuf.alloc !fir.box<...> {data_attr = #cuf.cuda<device>} // managed memory
...
fir.if %4 {
%6 = fir.embox %2(%5) {allocator_idx = 2 : i32} // cudaMalloc
fir.store %6 to %0 // managed descriptor
}
omp.yield(%0 : ...) // yields managed ptr
} dealloc {
...
fir.if %3 { fir.freemem %1 }
cuf.free %arg0 : ... {data_attr = #cuf.cuda<device>} // free managed desc
omp.yield
}
```
---------
Co-authored-by: Valentin Clement (バレンタイン クレメン) <clementval@gmail.com>