Skip to content

Commit f4fc2d7

Browse files
authored
[flang][OpenMP] Map ByRef if size/alignment exceed that of a pointer (#130832)
Improve the check for whether a type can be passed by copy. Currently, passing by copy is done via the OMP_MAP_LITERAL mapping, which can only transfer as much data as can be contained in a pointer representation.
1 parent c542991 commit f4fc2d7

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2192,6 +2192,21 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
21922192
/*useDelayedPrivatization=*/true, symTable);
21932193
dsp.processStep1(&clauseOps);
21942194

2195+
// Check if a value of type `type` can be passed to the kernel by value.
2196+
// All kernel parameters are of pointer type, so if the value can be
2197+
// represented inside of a pointer, then it can be passed by value.
2198+
auto isLiteralType = [&](mlir::Type type) {
2199+
const mlir::DataLayout &dl = firOpBuilder.getDataLayout();
2200+
mlir::Type ptrTy =
2201+
mlir::LLVM::LLVMPointerType::get(&converter.getMLIRContext());
2202+
uint64_t ptrSize = dl.getTypeSize(ptrTy);
2203+
uint64_t ptrAlign = dl.getTypePreferredAlignment(ptrTy);
2204+
2205+
auto [size, align] = fir::getTypeSizeAndAlignmentOrCrash(
2206+
loc, type, dl, converter.getKindMap());
2207+
return size <= ptrSize && align <= ptrAlign;
2208+
};
2209+
21952210
// 5.8.1 Implicit Data-Mapping Attribute Rules
21962211
// The following code follows the implicit data-mapping rules to map all the
21972212
// symbols used inside the region that do not have explicit data-environment
@@ -2269,7 +2284,14 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
22692284
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
22702285
}
22712286
} else if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
2272-
captureKind = mlir::omp::VariableCaptureKind::ByCopy;
2287+
// Scalars behave as if they were "firstprivate".
2288+
// TODO: Handle objects that are shared/lastprivate or were listed
2289+
// in an in_reduction clause.
2290+
if (isLiteralType(eleType)) {
2291+
captureKind = mlir::omp::VariableCaptureKind::ByCopy;
2292+
} else {
2293+
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
2294+
}
22732295
} else if (!fir::isa_builtin_cptr_type(eleType)) {
22742296
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
22752297
mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
2+
3+
! Check that the complex*4 is passed by value. but complex*8 is passed by
4+
! reference
5+
6+
!CHECK-LABEL: func.func @_QMmPbar()
7+
!CHECK: %[[V0:[0-9]+]]:2 = hlfir.declare {{.*}} (!fir.ref<complex<f64>>) -> (!fir.ref<complex<f64>>, !fir.ref<complex<f64>>)
8+
!CHECK: %[[V1:[0-9]+]]:2 = hlfir.declare {{.*}} (!fir.ref<complex<f32>>) -> (!fir.ref<complex<f32>>, !fir.ref<complex<f32>>)
9+
!CHECK: %[[V2:[0-9]+]] = omp.map.info var_ptr(%[[V1]]#1 : !fir.ref<complex<f32>>, complex<f32>) {{.*}} capture(ByCopy)
10+
!CHECK: %[[V3:[0-9]+]] = omp.map.info var_ptr(%[[V0]]#1 : !fir.ref<complex<f64>>, complex<f64>) {{.*}} capture(ByRef)
11+
!CHECK: omp.target map_entries(%[[V2]] -> {{.*}}, %[[V3]] -> {{.*}} : !fir.ref<complex<f32>>, !fir.ref<complex<f64>>)
12+
13+
module m
14+
implicit none
15+
complex(kind=4) :: cfval = (24, 25)
16+
complex(kind=8) :: cdval = (28, 29)
17+
interface
18+
subroutine foo(x, y)
19+
complex(kind=4) :: x
20+
complex(kind=8) :: y
21+
!$omp declare target
22+
end
23+
end interface
24+
25+
contains
26+
27+
subroutine bar()
28+
!$omp target
29+
call foo(cfval, cdval)
30+
!$omp end target
31+
end
32+
33+
end module
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
!REQUIRES: flang, amdgpu
2+
3+
!RUN: %libomptarget-compile-fortran-run-and-check-generic
4+
5+
program m
6+
complex(kind=8) :: x
7+
x = (1.0, 2.0)
8+
!$omp target
9+
x = (-1.0, -2.0)
10+
!$omp end target
11+
print *, "x=", x
12+
end program
13+
14+
! The host variable "x" should be passed to the kernel as "firstprivate",
15+
! hence the kernel should have its own copy of it. This is in contrast to
16+
! other cases where implicitly mapped variables have the TOFROM map-type.
17+
18+
! Make sure that the target region didn't overwrite the host variable.
19+
20+
!CHECK: x= (1.,2.)

0 commit comments

Comments
 (0)