Skip to content

Commit b2c9a58

Browse files
authored
[Flang][OpenMP][MLIR] Check for presence of Box type before emitting store in MapInfoFinalization pass (#135477)
Currently we don't check for the presence of descriptor/BoxTypes before emitting stores which lower to memcpys, the issue with this is that users can have optional arguments, where they don't provide an input, making the argument effectively null. This can still be mapped and this causes issues at the moment as we'll emit a memcpy for function arguments to store to a local variable for certain edge cases, when we perform this memcpy on a null input, we cause a segfault at runtime. The fix to this is to simply create a branch around the store that checks if the data we're copying from is actually present. If it is, we proceed with the store, if it isn't we skip it.
1 parent 092b6e7 commit b2c9a58

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,15 @@ class MapInfoFinalizationPass
153153
builder.setInsertionPointToStart(allocaBlock);
154154
auto alloca = builder.create<fir::AllocaOp>(loc, descriptor.getType());
155155
builder.restoreInsertionPoint(insPt);
156-
builder.create<fir::StoreOp>(loc, descriptor, alloca);
156+
// We should only emit a store if the passed in data is present, it is
157+
// possible a user passes in no argument to an optional parameter, in which
158+
// case we cannot store or we'll segfault on the emitted memcpy.
159+
auto isPresent =
160+
builder.create<fir::IsPresentOp>(loc, builder.getI1Type(), descriptor);
161+
builder.genIfOp(loc, {}, isPresent, false)
162+
.genThen(
163+
[&]() { builder.create<fir::StoreOp>(loc, descriptor, alloca); })
164+
.end();
157165
return slot = alloca;
158166
}
159167

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
2+
3+
module foo
4+
implicit none
5+
contains
6+
subroutine test(I,A)
7+
implicit none
8+
real(4), optional, intent(inout) :: A(:)
9+
integer(kind=4), intent(in) :: I
10+
11+
!$omp target data map(to: A) if (I>0)
12+
!$omp end target data
13+
14+
end subroutine test
15+
end module foo
16+
17+
! CHECK-LABEL: func.func @_QMfooPtest(
18+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "i"},
19+
! CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "a", fir.optional}) {
20+
! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.array<?xf32>>
21+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %{{.*}} {fortran_attrs = #fir.var_attrs<intent_inout, optional>, uniq_name = "_QMfooFtestEa"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
22+
! CHECK: %{{.*}} = fir.is_present %{{.*}}#1 : (!fir.box<!fir.array<?xf32>>) -> i1
23+
! CHECK: %{{.*}}:5 = fir.if %{{.*}}
24+
! CHECK: %[[VAL_4:.*]] = fir.is_present %[[VAL_3]]#1 : (!fir.box<!fir.array<?xf32>>) -> i1
25+
! CHECK: fir.if %[[VAL_4]] {
26+
! CHECK: fir.store %[[VAL_3]]#1 to %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<?xf32>>>
27+
! CHECK: }
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
! OpenMP offloading test that checks we do not cause a segfault when mapping
2+
! optional function arguments (present or otherwise). No results requiring
3+
! checking other than that the program compiles and runs to completion with no
4+
! error.
5+
! REQUIRES: flang, amdgpu
6+
7+
! RUN: %libomptarget-compile-fortran-run-and-check-generic
8+
module foo
9+
implicit none
10+
contains
11+
subroutine test(I,A)
12+
implicit none
13+
real(4), optional, intent(inout) :: A(:)
14+
integer(kind=4), intent(in) :: I
15+
16+
!$omp target data map(to: A) if (I>0)
17+
!$omp end target data
18+
19+
!$omp target enter data map(to:A) if (I>0)
20+
21+
!$omp target exit data map(from:A) if (I>0)
22+
end subroutine test
23+
end module foo
24+
25+
program main
26+
use foo
27+
implicit none
28+
real :: array(10)
29+
call test(0)
30+
call test(1)
31+
call test(0, array)
32+
call test(1, array)
33+
print *, "PASSED"
34+
end program main
35+
36+
! CHECK: PASSED

0 commit comments

Comments
 (0)