Skip to content

[flang][OpenMP] Support using copyprivate with fir.boxchar arguments #144092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -727,12 +727,15 @@ class TypeInfo {
// Is the type inside a box?
bool isBox() const { return inBox; }

bool isBoxChar() const { return inBoxChar; }

private:
void typeScan(mlir::Type type);

std::optional<fir::CharacterType::LenType> charLen;
llvm::SmallVector<int64_t> shape;
bool inBox = false;
bool inBoxChar = false;
};

void TypeInfo::typeScan(mlir::Type ty) {
Expand All @@ -748,6 +751,9 @@ void TypeInfo::typeScan(mlir::Type ty) {
typeScan(cty.getEleTy());
} else if (auto cty = mlir::dyn_cast<fir::CharacterType>(ty)) {
charLen = cty.getLen();
} else if (auto cty = mlir::dyn_cast<fir::BoxCharType>(ty)) {
inBoxChar = true;
typeScan(cty.getEleTy());
} else if (auto hty = mlir::dyn_cast<fir::HeapType>(ty)) {
typeScan(hty.getEleTy());
} else if (auto pty = mlir::dyn_cast<fir::PointerType>(ty)) {
Expand Down Expand Up @@ -791,12 +797,6 @@ createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter,
fir::FortranVariableFlagsAttr attrs;
if (varAttrs != fir::FortranVariableFlagsEnum::None)
attrs = fir::FortranVariableFlagsAttr::get(builder.getContext(), varAttrs);
llvm::SmallVector<mlir::Value> typeparams;
if (typeInfo.getCharLength().has_value()) {
mlir::Value charLen = builder.createIntegerConstant(
loc, builder.getCharacterLengthType(), *typeInfo.getCharLength());
typeparams.push_back(charLen);
}
mlir::Value shape;
if (!typeInfo.isBox() && !typeInfo.getShape().empty()) {
llvm::SmallVector<mlir::Value> extents;
Expand All @@ -805,11 +805,34 @@ createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter,
builder.createIntegerConstant(loc, builder.getIndexType(), extent));
shape = builder.create<fir::ShapeOp>(loc, extents);
}
mlir::Value dst = funcOp.getArgument(0);
mlir::Value src = funcOp.getArgument(1);
llvm::SmallVector<mlir::Value> typeparams;
if (typeInfo.isBoxChar()) {
// fir.boxchar will be passed here as fir.ref<fir.boxchar>
auto loadDst = builder.create<fir::LoadOp>(loc, dst);
auto loadSrc = builder.create<fir::LoadOp>(loc, src);
// get the actual fir.ref<fir.char> type
mlir::Type refType =
fir::ReferenceType::get(mlir::cast<fir::BoxCharType>(eleTy).getEleTy());
auto unboxedDst = builder.create<fir::UnboxCharOp>(
loc, refType, builder.getIndexType(), loadDst);
auto unboxedSrc = builder.create<fir::UnboxCharOp>(
loc, refType, builder.getIndexType(), loadSrc);
// Add length to type parameters
typeparams.push_back(unboxedDst.getResult(1));
dst = unboxedDst.getResult(0);
src = unboxedSrc.getResult(0);
} else if (typeInfo.getCharLength().has_value()) {
mlir::Value charLen = builder.createIntegerConstant(
loc, builder.getCharacterLengthType(), *typeInfo.getCharLength());
typeparams.push_back(charLen);
}
auto declDst = builder.create<hlfir::DeclareOp>(
loc, funcOp.getArgument(0), copyFuncName + "_dst", shape, typeparams,
loc, dst, copyFuncName + "_dst", shape, typeparams,
/*dummy_scope=*/nullptr, attrs);
auto declSrc = builder.create<hlfir::DeclareOp>(
loc, funcOp.getArgument(1), copyFuncName + "_src", shape, typeparams,
loc, src, copyFuncName + "_src", shape, typeparams,
/*dummy_scope=*/nullptr, attrs);
converter.copyVar(loc, declDst.getBase(), declSrc.getBase(), varAttrs);
builder.create<mlir::func::ReturnOp>(loc);
Expand All @@ -835,10 +858,13 @@ bool ClauseProcessor::processCopyprivate(

// CopyPrivate variables must be passed by reference. However, in the case
// of assumed shapes/vla the type is not a !fir.ref, but a !fir.box.
// In these cases to retrieve the appropriate !fir.ref<!fir.box<...>> to
// access the data we need we must perform an alloca and then store to it
// and retrieve the data from the new alloca.
if (mlir::isa<fir::BaseBoxType>(symType)) {
// In the case of character types, the passed in type can also be
// !fir.boxchar. In these cases to retrieve the appropriate
// !fir.ref<!fir.box<...>> or !fir.ref<!fir.boxchar<..>> to access the data
// we need we must perform an alloca and then store to it and retrieve the
// data from the new alloca.
if (mlir::isa<fir::BaseBoxType>(symType) ||
mlir::isa<fir::BoxCharType>(symType)) {
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
auto alloca = builder.create<fir::AllocaOp>(currentLocation, symType);
builder.create<fir::StoreOp>(currentLocation, symVal, alloca);
Expand Down
36 changes: 36 additions & 0 deletions flang/test/Lower/OpenMP/copyprivate5.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
! Test lowering of COPYPRIVATE with character arguments
! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s

! Testcase from: https://github.com/llvm/llvm-project/issues/142123

! CHECK-LABEL: func.func private @_copy_boxchar_c8xU(
! CHECK-SAME: %arg0: [[TYPE:!fir.ref<!fir.boxchar<1>>]],
! CHECK-SAME: %arg1: [[TYPE]]) attributes {llvm.linkage = #llvm.linkage<internal>} {
! CHECK: %[[RDST:.*]] = fir.load %arg0 : [[TYPE]]
! CHECK: %[[RSRC:.*]] = fir.load %arg1 : [[TYPE]]
! CHECK: %[[UDST:.*]]:2 = fir.unboxchar %[[RDST:.*]] : ([[UTYPE:!fir.boxchar<1>]]) -> ([[RTYPE:!fir.ref<!fir.char<1,\?>>]], [[ITYPE:index]])
! CHECK: %[[USRC:.*]]:2 = fir.unboxchar %[[RSRC:.*]] : ([[UTYPE]]) -> ([[RTYPE]], [[ITYPE]])
! CHECK: %[[DST:.*]]:2 = hlfir.declare %[[UDST:.*]]#0 typeparams %[[UDST:.*]]#1 {uniq_name = "[[NAME1:.*]]"} : ([[RTYPE]], [[ITYPE]]) -> ([[UTYPE]], [[RTYPE]])
! CHECK: %[[SRC:.*]]:2 = hlfir.declare %[[USRC:.*]]#0 typeparams %[[UDST:.*]]#1 {uniq_name = "[[NAME2:.*]]"} : ([[RTYPE]], [[ITYPE]]) -> ([[UTYPE]], [[RTYPE]])
! CHECK: hlfir.assign %[[SRC:.*]]#0 to %[[DST:.*]]#0 : [[UTYPE]], [[UTYPE]]
! CHECK: return
! CHECK: }

! CHECK-LABEL: func.func @_QPs(%arg0: !fir.boxchar<1> {fir.bindc_name = "c"}) {
! CHECK: %[[ALLOC:.*]] = fir.alloca !fir.boxchar<1>
! CHECK: fir.store %[[SRC:.*]] to %[[ALLOC:.*]] : !fir.ref<!fir.boxchar<1>>
! CHECK: omp.single copyprivate([[ALLOC:.*]] -> @_copy_boxchar_c8xU : !fir.ref<!fir.boxchar<1>>) {
! CHECK: hlfir.assign %[[NEW_VAL:.*]] to %[[SRC:.*]] : !fir.ref<!fir.char<1,3>>, !fir.boxchar<1>
! CHECK: omp.terminator
! CHECK: }

subroutine s(c)
character(*) :: c
!$omp single copyprivate(c)
c = "bar"
!$omp end single
end subroutine

character(len=3) :: c
call s(c)
end
Loading