https://github.com/bhandarkar-pranav updated https://github.com/llvm/llvm-project/pull/141715
>From 2d411fc5d24c7e3e933447307fc958b7e544490b Mon Sep 17 00:00:00 2001 From: Pranav Bhandarkar <pranav.bhandar...@amd.com> Date: Fri, 23 May 2025 10:26:14 -0500 Subject: [PATCH 1/5] Fix boxchar with firstprivate --- .../Optimizer/Builder/DirectivesCommon.h | 85 +++++++++++++----- flang/lib/Optimizer/Dialect/FIRType.cpp | 3 + .../Optimizer/OpenMP/MapInfoFinalization.cpp | 88 ++++++++++++++++++- .../OpenMP/MapsForPrivatizedSymbols.cpp | 67 ++++++++------ .../Fir/convert-to-llvm-openmp-and-fir.fir | 27 ++++++ flang/test/Lower/OpenMP/map-character.f90 | 23 +++-- .../Lower/OpenMP/optional-argument-map-2.f90 | 63 +++++++++++-- 7 files changed, 297 insertions(+), 59 deletions(-) diff --git a/flang/include/flang/Optimizer/Builder/DirectivesCommon.h b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h index 3f30c761acb4e..be11b9b5ede7c 100644 --- a/flang/include/flang/Optimizer/Builder/DirectivesCommon.h +++ b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h @@ -91,6 +91,16 @@ inline AddrAndBoundsInfo getDataOperandBaseAddr(fir::FirOpBuilder &builder, return AddrAndBoundsInfo(symAddr, rawInput, isPresent, boxTy); } + // For boxchar references, do the same as what is done above for box + // references - Load the boxchar so that it is easier to retrieve the length + // of the underlying character and the data pointer. + if (auto boxCharType = mlir::dyn_cast<fir::BoxCharType>( + fir::unwrapRefType((symAddr.getType())))) { + if (!isOptional && mlir::isa<fir::ReferenceType>(symAddr.getType())) { + mlir::Value boxChar = builder.create<fir::LoadOp>(loc, symAddr); + return AddrAndBoundsInfo(boxChar, rawInput, isPresent); + } + } return AddrAndBoundsInfo(symAddr, rawInput, isPresent); } @@ -137,26 +147,61 @@ template <typename BoundsOp, typename BoundsType> mlir::Value genBoundsOpFromBoxChar(fir::FirOpBuilder &builder, mlir::Location loc, fir::ExtendedValue dataExv, AddrAndBoundsInfo &info) { - // TODO: Handle info.isPresent. - if (auto boxCharType = - mlir::dyn_cast<fir::BoxCharType>(info.addr.getType())) { - mlir::Type idxTy = builder.getIndexType(); - mlir::Type lenType = builder.getCharacterLengthType(); + + if (!mlir::isa<fir::BoxCharType>(fir::unwrapRefType(info.addr.getType()))) + return mlir::Value{}; + + mlir::Type idxTy = builder.getIndexType(); + mlir::Type lenType = builder.getCharacterLengthType(); + mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); + mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); + using ExtentAndStride = std::tuple<mlir::Value, mlir::Value>; + auto [extent, stride] = [&]() -> ExtentAndStride { + if (info.isPresent) { + llvm::SmallVector<mlir::Type> resTypes = {idxTy, idxTy}; + mlir::Operation::result_range ifRes = + builder.genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true) + .genThen([&]() { + mlir::Value boxChar = + fir::isa_ref_type(info.addr.getType()) + ? builder.create<fir::LoadOp>(loc, info.addr) + : info.addr; + fir::BoxCharType boxCharType = + mlir::cast<fir::BoxCharType>(boxChar.getType()); + mlir::Type refType = builder.getRefType(boxCharType.getEleTy()); + auto unboxed = builder.create<fir::UnboxCharOp>( + loc, refType, lenType, boxChar); + mlir::SmallVector<mlir::Value> results = {unboxed.getResult(1), one }; + builder.create<fir::ResultOp>(loc, results); + }) + .genElse([&]() { + mlir::SmallVector<mlir::Value> results = {zero, zero }; + builder.create<fir::ResultOp>(loc, results); }) + .getResults(); + return {ifRes[0], ifRes[1]}; + } + // We have already established that info.addr.getType() is a boxchar + // or a boxchar address. If an address, load the boxchar. + mlir::Value boxChar = fir::isa_ref_type(info.addr.getType()) + ? builder.create<fir::LoadOp>(loc, info.addr) + : info.addr; + fir::BoxCharType boxCharType = + mlir::cast<fir::BoxCharType>(boxChar.getType()); mlir::Type refType = builder.getRefType(boxCharType.getEleTy()); auto unboxed = - builder.create<fir::UnboxCharOp>(loc, refType, lenType, info.addr); - mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); - mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); - mlir::Value extent = unboxed.getResult(1); - mlir::Value stride = one; - mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one); - mlir::Type boundTy = builder.getType<mlir::omp::MapBoundsType>(); - return builder.create<mlir::omp::MapBoundsOp>( - loc, boundTy, /*lower_bound=*/zero, - /*upper_bound=*/ub, /*extent=*/extent, /*stride=*/stride, - /*stride_in_bytes=*/true, /*start_idx=*/zero); - } - return mlir::Value{}; + builder.create<fir::UnboxCharOp>(loc, refType, lenType, boxChar); + return {unboxed.getResult(1), one}; + }(); + + mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one); + mlir::Type boundTy = builder.getType<BoundsType>(); + return builder.create<BoundsOp>(loc, boundTy, + /*lower_bound=*/zero, + /*upper_bound=*/ub, + /*extent=*/extent, + /*stride=*/stride, + /*stride_in_bytes=*/true, + /*start_idx=*/zero); } /// Generate the bounds operation from the descriptor information. @@ -296,11 +341,11 @@ genImplicitBoundsOps(fir::FirOpBuilder &builder, AddrAndBoundsInfo &info, bounds = genBaseBoundsOps<BoundsOp, BoundsType>(builder, loc, dataExv, dataExvIsAssumedSize); } - if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType()))) { + if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType())) || + mlir::isa<fir::BoxCharType>(fir::unwrapRefType(info.addr.getType()))) { bounds = {genBoundsOpFromBoxChar<BoundsOp, BoundsType>(builder, loc, dataExv, info)}; } - return bounds; } diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp index da7aa17445404..f521c9b3058fd 100644 --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -285,6 +285,9 @@ bool hasDynamicSize(mlir::Type t) { return true; if (auto rec = mlir::dyn_cast<fir::RecordType>(t)) return hasDynamicSize(rec); + if (auto boxChar = mlir::dyn_cast<fir::BoxCharType>(t)) { + return characterWithDynamicLen(boxChar.getEleTy()); + } return false; } diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp index 86095d708f7e5..51237840f060e 100644 --- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp +++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp @@ -48,7 +48,7 @@ #include <numeric> #define DEBUG_TYPE "omp-map-info-finalization" -#define PDBGS() (llvm::dbgs() << "[" << DEBUG_TYPE << "]: ") + namespace flangomp { #define GEN_PASS_DEF_MAPINFOFINALIZATIONPASS #include "flang/Optimizer/OpenMP/Passes.h.inc" @@ -285,6 +285,60 @@ class MapInfoFinalizationPass return false; } + mlir::omp::MapInfoOp genBoxcharMemberMap(mlir::omp::MapInfoOp op, + fir::FirOpBuilder &builder) { + if (!op.getMembers().empty()) + return op; + mlir::Location loc = op.getVarPtr().getLoc(); + mlir::Value boxChar = op.getVarPtr(); + + if (mlir::isa<fir::ReferenceType>(op.getVarPtr().getType())) + boxChar = builder.create<fir::LoadOp>(loc, op.getVarPtr()); + + fir::BoxCharType boxCharType = mlir::dyn_cast<fir::BoxCharType>(boxChar.getType()); + mlir::Value boxAddr = builder.create<fir::BoxOffsetOp>(loc, op.getVarPtr(), fir::BoxFieldAttr::base_addr); + + uint64_t mapTypeToImplicit = static_cast< + std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>( + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT); + + mlir::ArrayAttr newMembersAttr; + llvm::SmallVector<llvm::SmallVector<int64_t>> memberIdx = {{0}}; + newMembersAttr = builder.create2DI64ArrayAttr(memberIdx); + + mlir::Value varPtr = op.getVarPtr(); + mlir::omp::MapInfoOp memberMapInfoOp = builder.create<mlir::omp::MapInfoOp>( + op.getLoc(), varPtr.getType(), varPtr, + mlir::TypeAttr::get(boxCharType.getEleTy()), + builder.getIntegerAttr(builder.getIntegerType(64, /*isSigned=*/false), + mapTypeToImplicit), + builder.getAttr<mlir::omp::VariableCaptureKindAttr>( + mlir::omp::VariableCaptureKind::ByRef), + /*varPtrPtr=*/boxAddr, + /*members=*/llvm::SmallVector<mlir::Value>{}, + /*member_index=*/mlir::ArrayAttr{}, + /*bounds=*/op.getBounds(), + /*mapperId=*/mlir::FlatSymbolRefAttr(), /*name=*/op.getNameAttr(), + builder.getBoolAttr(false)); + + mlir::omp::MapInfoOp newMapInfoOp = builder.create<mlir::omp::MapInfoOp>( + op.getLoc(), op.getResult().getType(), varPtr, + mlir::TypeAttr::get(llvm::cast<mlir::omp::PointerLikeType>(varPtr.getType()) + .getElementType()), + op.getMapTypeAttr(), + op.getMapCaptureTypeAttr(), + /*varPtrPtr=*/mlir::Value{}, + /*members=*/llvm::SmallVector<mlir::Value>{memberMapInfoOp}, + /*member_index=*/newMembersAttr, + /*bounds=*/llvm::SmallVector<mlir::Value>{}, + /*mapperId=*/mlir::FlatSymbolRefAttr(), op.getNameAttr(), + /*partial_map=*/builder.getBoolAttr(false)); + op.replaceAllUsesWith(newMapInfoOp.getResult()); + op->erase(); + return newMapInfoOp; + } + mlir::omp::MapInfoOp genDescriptorMemberMaps(mlir::omp::MapInfoOp op, fir::FirOpBuilder &builder, mlir::Operation *target) { @@ -575,6 +629,7 @@ class MapInfoFinalizationPass fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr( builder, varPtr, /*isOptional=*/false, varPtr.getLoc()); + fir::ExtendedValue extendedValue = hlfir::translateToExtendedValue(varPtr.getLoc(), builder, hlfir::Entity{info.addr}, @@ -743,6 +798,37 @@ class MapInfoFinalizationPass return mlir::WalkResult::advance(); }); + func->walk([&](mlir::omp::MapInfoOp op) { + if (!op.getMembers().empty()) + return; + + if (!mlir::isa<fir::BoxCharType>(fir::unwrapRefType(op.getVarType()))) + return; + + // POSSIBLE_HACK_ALERT: If the boxchar has been implicitly mapped then + // it is likely that the underlying pointer to the data + // (!fir.ref<fir.char<k,?>>) has already been mapped. So, skip such + // boxchars. We are primarily interested in boxchars that were mapped + // by passes such as MapsForPrivatizedSymbols that map boxchars that + // are privatized. At present, such boxchar maps are not marked + // implicit. Should they be? I don't know. If they should be then + // we need to change this check for early return OR live with + // over-mapping. + bool hasImplicitMap = + (llvm::omp::OpenMPOffloadMappingFlags(op.getMapType()) & + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT) == + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT; + if (hasImplicitMap) + return; + + assert(llvm::hasSingleElement(op->getUsers()) && + "OMPMapInfoFinalization currently only supports single users " + "of a MapInfoOp"); + + builder.setInsertionPoint(op); + genBoxcharMemberMap(op, builder); + }); + func->walk([&](mlir::omp::MapInfoOp op) { // TODO: Currently only supports a single user for the MapInfoOp. This // is fine for the moment, as the Fortran frontend will generate a diff --git a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp index dedff59d66aa0..70f051789acb7 100644 --- a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp +++ b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp @@ -22,7 +22,9 @@ // 2. Generalize this for more than just omp.target ops. //===----------------------------------------------------------------------===// +#include "flang/Optimizer/Builder/DirectivesCommon.h" #include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Dialect/FIRType.h" #include "flang/Optimizer/Dialect/Support/KindMapping.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" @@ -188,32 +190,45 @@ class MapsForPrivatizedSymbolsPass // in a subsequent PR. void genBoundsOps(fir::FirOpBuilder &builder, mlir::Value var, llvm::SmallVector<mlir::Value> &boundsOps) { - if (!fir::isBoxAddress(var.getType())) - return; - - unsigned int rank = 0; - rank = fir::getBoxRank(fir::unwrapRefType(var.getType())); - mlir::Location loc = var.getLoc(); - mlir::Type idxTy = builder.getIndexType(); - mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); - mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); - mlir::Type boundTy = builder.getType<omp::MapBoundsType>(); - mlir::Value box = builder.create<fir::LoadOp>(loc, var); - for (unsigned int i = 0; i < rank; ++i) { - mlir::Value dimNo = builder.createIntegerConstant(loc, idxTy, i); - auto dimInfo = - builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dimNo); - mlir::Value lb = dimInfo.getLowerBound(); - mlir::Value extent = dimInfo.getExtent(); - mlir::Value byteStride = dimInfo.getByteStride(); - mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one); - - mlir::Value boundsOp = builder.create<omp::MapBoundsOp>( - loc, boundTy, /*lower_bound=*/zero, - /*upper_bound=*/ub, /*extent=*/extent, /*stride=*/byteStride, - /*stride_in_bytes = */ true, /*start_idx=*/lb); - LLVM_DEBUG(PDBGS() << "Created BoundsOp " << boundsOp << "\n"); - boundsOps.push_back(boundsOp); + if (fir::isBoxAddress(var.getType())) { + unsigned int rank = 0; + rank = fir::getBoxRank(fir::unwrapRefType(var.getType())); + mlir::Location loc = var.getLoc(); + mlir::Type idxTy = builder.getIndexType(); + mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); + mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); + mlir::Type boundTy = builder.getType<omp::MapBoundsType>(); + mlir::Value box = builder.create<fir::LoadOp>(loc, var); + for (unsigned int i = 0; i < rank; ++i) { + mlir::Value dimNo = builder.createIntegerConstant(loc, idxTy, i); + auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, + box, dimNo); + mlir::Value lb = dimInfo.getLowerBound(); + mlir::Value extent = dimInfo.getExtent(); + mlir::Value byteStride = dimInfo.getByteStride(); + mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one); + + mlir::Value boundsOp = builder.create<omp::MapBoundsOp>( + loc, boundTy, /*lower_bound=*/zero, + /*upper_bound=*/ub, /*extent=*/extent, /*stride=*/byteStride, + /*stride_in_bytes = */ true, /*start_idx=*/lb); + LLVM_DEBUG(PDBGS() << "Created BoundsOp " << boundsOp << "\n"); + boundsOps.push_back(boundsOp); + } + } else { + mlir::Location loc = var.getLoc(); + fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr(builder, var, /*isOptional=*/false, loc); + fir::ExtendedValue extendedValue = + hlfir::translateToExtendedValue(loc, builder, + hlfir::Entity{info.addr}, + /*continguousHint=*/true).first; + llvm::SmallVector<mlir::Value> boundsOpsVec = + fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp, + mlir::omp::MapBoundsType>( + builder, info, extendedValue, + /*dataExvIsAssumedSize=*/false, loc); + for (auto bounds : boundsOpsVec) + boundsOps.push_back(bounds); } } }; diff --git a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir index b13921f822b4d..24e5cad84b709 100644 --- a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir +++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir @@ -1288,3 +1288,30 @@ omp.declare_mapper @my_mapper : !fir.type<_QFdeclare_mapperTmy_type{data:i32}> { omp.declare_mapper.info map_entries(%4, %3 : !fir.ref<!fir.type<_QFdeclare_mapperTmy_type{data:i32}>>, !fir.ref<i32>) // CHECK: } } + +// ----- +omp.private {type = firstprivate} @boxchar_privatizer : !fir.boxchar<1> copy { + ^bb0(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>): + omp.yield(%arg1 : !fir.boxchar<1>) +} + +func.func @map_privatized_boxchar(%arg0 : !fir.boxchar<1>) { + %0 = fir.alloca !fir.boxchar<1> + fir.store %arg0 to %0 : !fir.ref<!fir.boxchar<1>> + %7 = fir.box_offset %0 base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>> + %8 = omp.map.info var_ptr(%0 : !fir.ref<!fir.boxchar<1>>, !fir.char<1,?>) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%7 : !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>) -> !fir.ref<!fir.boxchar<1>> + %9 = omp.map.info var_ptr(%0 : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) members(%8 : [0] : !fir.ref<!fir.boxchar<1>>) -> !fir.ref<!fir.boxchar<1>> + omp.target map_entries(%9 -> %arg1, %8 -> %arg2 : !fir.ref<!fir.boxchar<1>>, !fir.ref<!fir.boxchar<1>>) private(@boxchar_privatizer %arg0 -> %arg3 [map_idx=0] : !fir.boxchar<1>) { + omp.terminator + } + return +} + +// CHECK-LABEL: llvm.func @map_privatized_boxchar( +// CHECK-SAME: %[[ARG0:.*]]: !llvm.struct<(ptr, i64)>) { +// CHECK: %[[BOXCHAR_ALLOCA:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64)> : (i64) -> !llvm.ptr +// CHECK: llvm.store %[[ARG0]], %[[BOXCHAR_ALLOCA]] : !llvm.struct<(ptr, i64)>, !llvm.ptr +// CHECK: %[[BASE_ADDR:.*]] = llvm.getelementptr %[[BOXCHAR_ALLOCA]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64)> +// CHECK: %[[MAP_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[BOXCHAR_ALLOCA]] : !llvm.ptr, i8) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR]] : !llvm.ptr) -> !llvm.ptr +// CHECK: %[[MAP_BOXCHAR:.*]] = omp.map.info var_ptr(%[[BOXCHAR_ALLOCA]] : !llvm.ptr, !llvm.struct<(ptr, i64)>) map_clauses(to) capture(ByRef) members(%[[MAP_BASE_ADDR]] : [0] : !llvm.ptr) -> !llvm.ptr +// CHECK: omp.target map_entries(%[[MAP_BOXCHAR]] -> %arg1, %[[MAP_BASE_ADDR]] -> %arg2 : !llvm.ptr, !llvm.ptr) private(@boxchar_privatizer %[[ARG0]] -> %arg3 [map_idx=0] : !llvm.struct<(ptr, i64)>) { diff --git a/flang/test/Lower/OpenMP/map-character.f90 b/flang/test/Lower/OpenMP/map-character.f90 index 232c0a6361cb6..cefd3ac0e54f9 100644 --- a/flang/test/Lower/OpenMP/map-character.f90 +++ b/flang/test/Lower/OpenMP/map-character.f90 @@ -18,25 +18,38 @@ end subroutine TestOfCharacter !CHECK: %[[A0_DECL:.*]]:2 = hlfir.declare %[[UNBOXED_ARG0]]#0 typeparams %[[UNBOXED_ARG0]]#1 dummy_scope {{.*}} -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) !CHECK: %[[UNBOXED_ARG1:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) !CHECK: %[[A1_DECL:.*]]:2 = hlfir.declare %[[UNBOXED_ARG1]]#0 typeparams %[[UNBOXED_ARG1]]#1 dummy_scope {{.*}} -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) -!CHECK: %[[UNBOXED_A0_DECL:.*]]:2 = fir.unboxchar %[[A0_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) !CHECK: %[[A0_LB:.*]] = arith.constant 0 : index !CHECK: %[[A0_STRIDE:.*]] = arith.constant 1 : index +!CHECK: %[[UNBOXED_A0_DECL:.*]]:2 = fir.unboxchar %[[A0_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) !CHECK: %[[A0_UB:.*]] = arith.subi %[[UNBOXED_A0_DECL]]#1, %[[A0_STRIDE]] : index !CHECK: %[[A0_BOUNDS:.*]] = omp.map.bounds lower_bound(%[[A0_LB]] : index) upper_bound(%[[A0_UB]] : index) extent(%[[UNBOXED_A0_DECL]]#1 : index) !CHECK-SAME: stride(%[[A0_STRIDE]] : index) start_idx(%[[A0_LB]] : index) {stride_in_bytes = true} !CHECK: %[[A0_MAP:.*]] = omp.map.info var_ptr(%[[A0_DECL]]#1 : !fir.ref<!fir.char<1,?>>, !fir.char<1,?>) map_clauses(to) capture(ByRef) bounds(%[[A0_BOUNDS]]) -> !fir.ref<!fir.char<1,?>> {name = "a0"} -!CHECK: %[[UNBOXED_A1_DECL:.*]]:2 = fir.unboxchar %[[A1_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) !CHECK: %[[A1_LB:.*]] = arith.constant 0 : index !CHECK: %[[A1_STRIDE:.*]] = arith.constant 1 : index +!CHECK: %[[UNBOXED_A1_DECL:.*]]:2 = fir.unboxchar %[[A1_DECL]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) !CHECK: %[[A1_UB:.*]] = arith.subi %[[UNBOXED_A1_DECL]]#1, %[[A1_STRIDE]] : index !CHECK: %[[A1_BOUNDS:.*]] = omp.map.bounds lower_bound(%[[A1_LB]] : index) upper_bound(%[[A1_UB]] : index) extent(%[[UNBOXED_A1_DECL]]#1 : index) !CHECKL-SAME: stride(%[[A1_STRIDE]] : index) start_idx(%[[A1_LB]] : index) {stride_in_bytes = true} !CHECK: %[[A1_MAP:.*]] = omp.map.info var_ptr(%[[A1_DECL]]#1 : !fir.ref<!fir.char<1,?>>, !fir.char<1,?>) map_clauses(from) capture(ByRef) bounds(%[[A1_BOUNDS]]) -> !fir.ref<!fir.char<1,?>> {name = "a1"} !CHECK: fir.store %[[ARG1]] to %[[A1_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>> -!CHECK: %[[A1_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A1_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) -> !fir.ref<!fir.boxchar<1>> {name = ""} +!CHECK: %[[CONST_ZERO:.*]] = arith.constant 0 : index +!CHECK: %[[CONST_ONE:.*]] = arith.constant 1 : index +!CHECK: %[[UNBOXED_ARG1:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +!CHECK: %[[A1_UB:.*]] = arith.subi %[[UNBOXED_ARG1]]#1, %[[CONST_ONE]] : index +!CHECK: %[[BOUNDS_A1_BOXCHAR:.*]] = omp.map.bounds lower_bound(%[[CONST_ZERO]] : index) upper_bound(%[[A1_UB]] : index) extent(%[[UNBOXED_ARG1]]#1 : index) +!CHECK-SAME: stride(%[[CONST_ONE]] : index) start_idx(%[[CONST_ZERO]] : index) {stride_in_bytes = true} +!CHECK: %[[A1_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A1_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) +!CHECK-SAME: capture(ByRef) bounds(%[[BOUNDS_A1_BOXCHAR]]) -> !fir.ref<!fir.boxchar<1>> {name = ""} !CHECK: fir.store %[[ARG0]] to %[[A0_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>> -!CHECK: %[[A0_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) -> !fir.ref<!fir.boxchar<1>> {name = ""} - +!CHECK: %[[CONST_ZERO:.*]] = arith.constant 0 : index +!CHECK: %[[CONST_ONE:.*]] = arith.constant 1 : index +!CHECK: %[[UNBOXED_ARG0:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +!CHECK: %[[A0_UB:.*]] = arith.subi %[[UNBOXED_ARG0]]#1, %[[CONST_ONE]] : index +!CHECK: %[[BOUNDS_A0_BOXCHAR:.*]] = omp.map.bounds lower_bound(%[[CONST_ZERO]] : index) upper_bound(%[[A0_UB]] : index) extent(%[[UNBOXED_ARG0]]#1 : index) +!CHECK-SAME: stride(%[[CONST_ONE]] : index) start_idx(%[[CONST_ZERO]] : index) {stride_in_bytes = true} +!CHECK: %[[A0_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) +!CHECK-SAME: capture(ByRef) bounds(%[[BOUNDS_A0_BOXCHAR]]) -> !fir.ref<!fir.boxchar<1>> {name = ""} !CHECK: omp.target map_entries(%[[A0_MAP]] -> %[[TGT_A0:.*]], %[[A1_MAP]] -> %[[TGT_A1:.*]], %[[A1_BOXCHAR_MAP]] -> %[[TGT_A1_BOXCHAR:.*]], %[[A0_BOXCHAR_MAP]] -> %[[TGT_A0_BOXCHAR:.*]] : !fir.ref<!fir.char<1,?>>, !fir.ref<!fir.char<1,?>>, !fir.ref<!fir.boxchar<1>>, !fir.ref<!fir.boxchar<1>>) { !CHECK: %[[TGT_A0_BC_LD:.*]] = fir.load %[[TGT_A0_BOXCHAR]] : !fir.ref<!fir.boxchar<1>> !CHECK: %[[TGT_A1_BC_LD:.*]] = fir.load %[[TGT_A1_BOXCHAR]] : !fir.ref<!fir.boxchar<1>> diff --git a/flang/test/Lower/OpenMP/optional-argument-map-2.f90 b/flang/test/Lower/OpenMP/optional-argument-map-2.f90 index 3b629cfc06d3a..e713d71cfbec9 100644 --- a/flang/test/Lower/OpenMP/optional-argument-map-2.f90 +++ b/flang/test/Lower/OpenMP/optional-argument-map-2.f90 @@ -3,24 +3,31 @@ module mod implicit none contains - subroutine routine(a) + subroutine routine_box(a) implicit none real(4), allocatable, optional, intent(inout) :: a(:) integer(4) :: i !$omp target teams distribute parallel do shared(a) - do i=1,10 - a(i) = i + a(i) - end do + do i=1,10 + a(i) = i + a(i) + end do - end subroutine routine + end subroutine routine_box + subroutine routine_boxchar(a) + character(len=*), optional, intent(in) :: a + character(len=4) :: b + !$omp target map(from: b) + b = a + !$omp end target + end subroutine routine_boxchar end module mod -! CHECK-LABEL: func.func @_QMmodProutine( +! CHECK-LABEL: func.func @_QMmodProutine_box( ! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> {fir.bindc_name = "a", fir.optional}) { ! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xf32>>> ! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope -! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<allocatable, intent_inout, optional>, uniq_name = "_QMmodFroutineEa"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<allocatable, intent_inout, optional>, uniq_name = "_QMmodFroutine_boxEa"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) ! CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_2]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> i1 ! CHECK: %[[VAL_9:.*]]:5 = fir.if %[[VAL_8]] -> (index, index, index, index, index) { ! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> @@ -44,3 +51,45 @@ end module mod ! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> ! CHECK: fir.store %[[VAL_24]] to %[[VAL_0]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>> ! CHECK: } + + +! CHECK-LABEL: func.func @_QMmodProutine_boxchar( +! CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1> {fir.bindc_name = "a", fir.optional}) { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.boxchar<1> +! CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_2:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]#0 typeparams %[[VAL_2]]#1 dummy_scope %[[VAL_1]] {fortran_attrs = #fir.var_attrs<intent_in, optional>, uniq_name = "_QMmodFroutine_boxcharEa"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) +! CHECK: %[[VAL_4:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_5:.*]] = fir.alloca !fir.char<1,4> {bindc_name = "b", uniq_name = "_QMmodFroutine_boxcharEb"} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] typeparams %[[VAL_4]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>) +! CHECK: %[[VAL_7:.*]] = omp.map.info var_ptr(%[[VAL_6]]#1 : !fir.ref<!fir.char<1,4>>, !fir.char<1,4>) map_clauses(from) capture(ByRef) -> !fir.ref<!fir.char<1,4>> {name = "b"} +! CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_3]]#1 : (!fir.ref<!fir.char<1,?>>) -> i1 +! CHECK: %[[VAL_9:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_11:.*]]:2 = fir.if %[[VAL_8]] -> (index, index) { +! CHECK: %[[VAL_12:.*]]:2 = fir.unboxchar %[[VAL_3]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +! CHECK: fir.result %[[VAL_12]]#1, %[[VAL_10]] : index, index +! CHECK: } else { +! CHECK: fir.result %[[VAL_9]], %[[VAL_9]] : index, index +! CHECK: } +! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_14:.*]]#0, %[[VAL_10]] : index +! CHECK: %[[VAL_15:.*]] = omp.map.bounds lower_bound(%[[VAL_9]] : index) upper_bound(%[[VAL_13]] : index) extent(%[[VAL_14]]#0 : index) stride(%[[VAL_14]]#1 : index) start_idx(%[[VAL_9]] : index) {stride_in_bytes = true} +! CHECK: %[[VAL_16:.*]] = omp.map.info var_ptr(%[[VAL_3]]#1 : !fir.ref<!fir.char<1,?>>, !fir.char<1,?>) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) bounds(%[[VAL_15]]) -> !fir.ref<!fir.char<1,?>> {name = "a"} +! CHECK: fir.store %[[ARG0]] to %[[VAL_0]] : !fir.ref<!fir.boxchar<1>> +! CHECK: %[[VAL_17:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_18:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_19:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +! CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_19]]#1, %[[VAL_18]] : index +! CHECK: %[[VAL_21:.*]] = omp.map.bounds lower_bound(%[[VAL_17]] : index) upper_bound(%[[VAL_20]] : index) extent(%[[VAL_19]]#1 : index) stride(%[[VAL_18]] : index) start_idx(%[[VAL_17]] : index) {stride_in_bytes = true} +! CHECK: %[[VAL_22:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) bounds(%[[VAL_21]]) -> !fir.ref<!fir.boxchar<1>> {name = ""} +! CHECK: omp.target map_entries(%[[VAL_7]] -> %[[VAL_23:.*]], %[[VAL_16]] -> %[[VAL_24:.*]], %[[VAL_22]] -> %[[VAL_25:.*]] : !fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,?>>, !fir.ref<!fir.boxchar<1>>) { +! CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_25]] : !fir.ref<!fir.boxchar<1>> +! CHECK: %[[VAL_27:.*]]:2 = fir.unboxchar %[[VAL_26]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +! CHECK: %[[VAL_28:.*]] = arith.constant 4 : index +! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_23]] typeparams %[[VAL_28]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref<!fir.char<1,4>>, index) -> (!fir.ref<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>) +! CHECK: %[[VAL_30:.*]]:2 = hlfir.declare %[[VAL_24]] typeparams %[[VAL_27]]#1 {fortran_attrs = #fir.var_attrs<intent_in, optional>, uniq_name = "_QMmodFroutine_boxcharEa"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) +! CHECK: hlfir.assign %[[VAL_30]]#0 to %[[VAL_29]]#0 : !fir.boxchar<1>, !fir.ref<!fir.char<1,4>> +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } >From e166c85218ce493e03134d12c05d5072c3ef0aca Mon Sep 17 00:00:00 2001 From: Pranav Bhandarkar <pranav.bhandar...@amd.com> Date: Tue, 27 May 2025 15:22:30 -0500 Subject: [PATCH 2/5] Add testcase for firstprivate boxchar fix --- .../Transforms/omp-map-info-finalization.fir | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/flang/test/Transforms/omp-map-info-finalization.fir b/flang/test/Transforms/omp-map-info-finalization.fir index 586605700880f..ed814cdcfc728 100644 --- a/flang/test/Transforms/omp-map-info-finalization.fir +++ b/flang/test/Transforms/omp-map-info-finalization.fir @@ -333,3 +333,62 @@ func.func @_QPreuse_alloca(%arg0: !fir.box<!fir.array<?xf64>> {fir.bindc_name = // CHECK: } // CHECK: return + + +omp.private {type = firstprivate} @boxchar.privatizer : !fir.boxchar<1> copy { + ^bb0(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>): + omp.yield(%arg0 : !fir.boxchar<1>) + } +func.func @_QPrealtest(%arg0: !fir.boxchar<1>) { + %0 = fir.alloca !fir.boxchar<1> + %1 = fir.dummy_scope : !fir.dscope + %2:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) + %3:2 = hlfir.declare %2#0 typeparams %2#1 dummy_scope %1 {uniq_name = "a0"}: (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) + fir.store %3#0 to %0 : !fir.ref<!fir.boxchar<1>> + %4 = fir.load %0 : !fir.ref<!fir.boxchar<1>> + %5:2 = fir.unboxchar %4 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) + %c0 = arith.constant 0 : index + %c1 = arith.constant 1 : index + %6:2 = fir.unboxchar %4 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) + %7 = arith.subi %6#1, %c1 : index + %8 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%7 : index) extent(%6#1 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true} + %9 = omp.map.info var_ptr(%0 : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) bounds(%8) -> !fir.ref<!fir.boxchar<1>> + omp.target map_entries(%9 -> %arg1 : !fir.ref<!fir.boxchar<1>>) private(@boxchar.privatizer %3#0 -> %arg2 [map_idx=0] : !fir.boxchar<1>) { + %10:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) + %11:2 = hlfir.declare %10#0 typeparams %10#1 {uniq_name = "tgt_a0"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) + omp.terminator + } + return +} + + +// CHECK-LABEL: omp.private {type = firstprivate} @boxchar.privatizer : !fir.boxchar<1> copy { +// CHECK: ^bb0(%[[VAL_0:.*]]: !fir.boxchar<1>, %[[VAL_1:.*]]: !fir.boxchar<1>): +// CHECK: omp.yield(%[[VAL_0]] : !fir.boxchar<1>) +// CHECK: } + +// CHECK-LABEL: func.func @_QPrealtest( +// CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1>) { +// CHECK: %[[VAL_0:.*]] = fir.alloca !fir.boxchar<1> +// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_2:.*]]:2 = fir.unboxchar %[[ARG0]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]]#0 typeparams %[[VAL_2]]#1 dummy_scope %[[VAL_1]] {uniq_name = "a0"} : (!fir.ref<!fir.char<1,?>>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) +// CHECK: fir.store %[[VAL_3]]#0 to %[[VAL_0]] : !fir.ref<!fir.boxchar<1>> +// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.boxchar<1>> +// CHECK: %[[VAL_5:.*]]:2 = fir.unboxchar %[[VAL_4]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +// CHECK: %[[VAL_6:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_7:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_8:.*]]:2 = fir.unboxchar %[[VAL_4]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +// CHECK: %[[VAL_9:.*]] = arith.subi %[[VAL_8]]#1, %[[VAL_7]] : index +// CHECK: %[[VAL_10:.*]] = omp.map.bounds lower_bound(%[[VAL_6]] : index) upper_bound(%[[VAL_9]] : index) extent(%[[VAL_8]]#1 : index) stride(%[[VAL_7]] : index) start_idx(%[[VAL_6]] : index) {stride_in_bytes = true} +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_0]] : !fir.ref<!fir.boxchar<1>> +// CHECK: %[[VAL_12:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>> +// CHECK: %[[VAL_13:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref<!fir.boxchar<1>>, !fir.char<1,?>) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%[[VAL_12]] : !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>) bounds(%[[VAL_10]]) -> !fir.ref<!fir.boxchar<1>> +// CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref<!fir.boxchar<1>>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) members(%[[VAL_13]] : [0] : !fir.ref<!fir.boxchar<1>>) -> !fir.ref<!fir.boxchar<1>> +// CHECK: omp.target map_entries(%[[VAL_14]] -> %[[VAL_15:.*]], %[[VAL_13]] -> %[[VAL_16:.*]] : !fir.ref<!fir.boxchar<1>>, !fir.ref<!fir.boxchar<1>>) private(@boxchar.privatizer %[[VAL_3]]#0 -> %[[VAL_17:.*]] [map_idx=0] : !fir.boxchar<1>) { +// CHECK: %[[VAL_18:.*]]:2 = fir.unboxchar %[[VAL_17]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index) +// CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]]#0 typeparams %[[VAL_18]]#1 {uniq_name = "tgt_a0"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>) +// CHECK: omp.terminator +// CHECK: } +// CHECK: return +// CHECK: } >From 93f3c522e88d85cf618a25472f42866933750739 Mon Sep 17 00:00:00 2001 From: Pranav Bhandarkar <pranav.bhandar...@amd.com> Date: Wed, 28 May 2025 10:32:51 -0500 Subject: [PATCH 3/5] Fix clang format issues --- .../flang/Optimizer/Builder/DirectivesCommon.h | 15 +++++++++------ .../lib/Optimizer/OpenMP/MapInfoFinalization.cpp | 16 +++++++++------- .../OpenMP/MapsForPrivatizedSymbols.cpp | 11 +++++++---- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/flang/include/flang/Optimizer/Builder/DirectivesCommon.h b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h index be11b9b5ede7c..ce960ea19e84a 100644 --- a/flang/include/flang/Optimizer/Builder/DirectivesCommon.h +++ b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h @@ -160,7 +160,8 @@ genBoundsOpFromBoxChar(fir::FirOpBuilder &builder, mlir::Location loc, if (info.isPresent) { llvm::SmallVector<mlir::Type> resTypes = {idxTy, idxTy}; mlir::Operation::result_range ifRes = - builder.genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true) + builder + .genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true) .genThen([&]() { mlir::Value boxChar = fir::isa_ref_type(info.addr.getType()) @@ -171,13 +172,15 @@ genBoundsOpFromBoxChar(fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type refType = builder.getRefType(boxCharType.getEleTy()); auto unboxed = builder.create<fir::UnboxCharOp>( loc, refType, lenType, boxChar); - mlir::SmallVector<mlir::Value> results = {unboxed.getResult(1), one }; + mlir::SmallVector<mlir::Value> results = {unboxed.getResult(1), + one}; builder.create<fir::ResultOp>(loc, results); }) - .genElse([&]() { - mlir::SmallVector<mlir::Value> results = {zero, zero }; - builder.create<fir::ResultOp>(loc, results); }) - .getResults(); + .genElse([&]() { + mlir::SmallVector<mlir::Value> results = {zero, zero}; + builder.create<fir::ResultOp>(loc, results); + }) + .getResults(); return {ifRes[0], ifRes[1]}; } // We have already established that info.addr.getType() is a boxchar diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp index 51237840f060e..f052cf8d22d1e 100644 --- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp +++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp @@ -295,15 +295,17 @@ class MapInfoFinalizationPass if (mlir::isa<fir::ReferenceType>(op.getVarPtr().getType())) boxChar = builder.create<fir::LoadOp>(loc, op.getVarPtr()); - fir::BoxCharType boxCharType = mlir::dyn_cast<fir::BoxCharType>(boxChar.getType()); - mlir::Value boxAddr = builder.create<fir::BoxOffsetOp>(loc, op.getVarPtr(), fir::BoxFieldAttr::base_addr); + fir::BoxCharType boxCharType = + mlir::dyn_cast<fir::BoxCharType>(boxChar.getType()); + mlir::Value boxAddr = builder.create<fir::BoxOffsetOp>( + loc, op.getVarPtr(), fir::BoxFieldAttr::base_addr); uint64_t mapTypeToImplicit = static_cast< std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>( llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT); - mlir::ArrayAttr newMembersAttr; + mlir::ArrayAttr newMembersAttr; llvm::SmallVector<llvm::SmallVector<int64_t>> memberIdx = {{0}}; newMembersAttr = builder.create2DI64ArrayAttr(memberIdx); @@ -324,10 +326,10 @@ class MapInfoFinalizationPass mlir::omp::MapInfoOp newMapInfoOp = builder.create<mlir::omp::MapInfoOp>( op.getLoc(), op.getResult().getType(), varPtr, - mlir::TypeAttr::get(llvm::cast<mlir::omp::PointerLikeType>(varPtr.getType()) - .getElementType()), - op.getMapTypeAttr(), - op.getMapCaptureTypeAttr(), + mlir::TypeAttr::get( + llvm::cast<mlir::omp::PointerLikeType>(varPtr.getType()) + .getElementType()), + op.getMapTypeAttr(), op.getMapCaptureTypeAttr(), /*varPtrPtr=*/mlir::Value{}, /*members=*/llvm::SmallVector<mlir::Value>{memberMapInfoOp}, /*member_index=*/newMembersAttr, diff --git a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp index 70f051789acb7..b6caeca70d5ed 100644 --- a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp +++ b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp @@ -217,16 +217,19 @@ class MapsForPrivatizedSymbolsPass } } else { mlir::Location loc = var.getLoc(); - fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr(builder, var, /*isOptional=*/false, loc); + fir::factory::AddrAndBoundsInfo info = + fir::factory::getDataOperandBaseAddr(builder, var, + /*isOptional=*/false, loc); fir::ExtendedValue extendedValue = hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr}, - /*continguousHint=*/true).first; + /*continguousHint=*/true) + .first; llvm::SmallVector<mlir::Value> boundsOpsVec = fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp, mlir::omp::MapBoundsType>( - builder, info, extendedValue, - /*dataExvIsAssumedSize=*/false, loc); + builder, info, extendedValue, + /*dataExvIsAssumedSize=*/false, loc); for (auto bounds : boundsOpsVec) boundsOps.push_back(bounds); } >From 9dc13d26a1db54821a3795871694c24699aa12d9 Mon Sep 17 00:00:00 2001 From: Pranav Bhandarkar <pranav.bhandar...@amd.com> Date: Thu, 29 May 2025 12:35:38 -0500 Subject: [PATCH 4/5] Only use fir::factory::genImplicitBoundsOps to generate bounds in MapsForPrivatizedSymbols.cpp --- .../OpenMP/MapsForPrivatizedSymbols.cpp | 60 +++++-------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp index b6caeca70d5ed..19566af11db04 100644 --- a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp +++ b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp @@ -186,53 +186,23 @@ class MapsForPrivatizedSymbolsPass return fir::hasDynamicSize(t); } - // TODO: Remove this in favor of fir::factory::genImplicitBoundsOps - // in a subsequent PR. void genBoundsOps(fir::FirOpBuilder &builder, mlir::Value var, llvm::SmallVector<mlir::Value> &boundsOps) { - if (fir::isBoxAddress(var.getType())) { - unsigned int rank = 0; - rank = fir::getBoxRank(fir::unwrapRefType(var.getType())); - mlir::Location loc = var.getLoc(); - mlir::Type idxTy = builder.getIndexType(); - mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); - mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); - mlir::Type boundTy = builder.getType<omp::MapBoundsType>(); - mlir::Value box = builder.create<fir::LoadOp>(loc, var); - for (unsigned int i = 0; i < rank; ++i) { - mlir::Value dimNo = builder.createIntegerConstant(loc, idxTy, i); - auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, - box, dimNo); - mlir::Value lb = dimInfo.getLowerBound(); - mlir::Value extent = dimInfo.getExtent(); - mlir::Value byteStride = dimInfo.getByteStride(); - mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one); - - mlir::Value boundsOp = builder.create<omp::MapBoundsOp>( - loc, boundTy, /*lower_bound=*/zero, - /*upper_bound=*/ub, /*extent=*/extent, /*stride=*/byteStride, - /*stride_in_bytes = */ true, /*start_idx=*/lb); - LLVM_DEBUG(PDBGS() << "Created BoundsOp " << boundsOp << "\n"); - boundsOps.push_back(boundsOp); - } - } else { - mlir::Location loc = var.getLoc(); - fir::factory::AddrAndBoundsInfo info = - fir::factory::getDataOperandBaseAddr(builder, var, - /*isOptional=*/false, loc); - fir::ExtendedValue extendedValue = - hlfir::translateToExtendedValue(loc, builder, - hlfir::Entity{info.addr}, - /*continguousHint=*/true) - .first; - llvm::SmallVector<mlir::Value> boundsOpsVec = - fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp, - mlir::omp::MapBoundsType>( - builder, info, extendedValue, - /*dataExvIsAssumedSize=*/false, loc); - for (auto bounds : boundsOpsVec) - boundsOps.push_back(bounds); - } + mlir::Location loc = var.getLoc(); + fir::factory::AddrAndBoundsInfo info = + fir::factory::getDataOperandBaseAddr(builder, var, + /*isOptional=*/false, loc); + fir::ExtendedValue extendedValue = + hlfir::translateToExtendedValue(loc, builder, hlfir::Entity{info.addr}, + /*continguousHint=*/true) + .first; + llvm::SmallVector<mlir::Value> boundsOpsVec = + fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp, + mlir::omp::MapBoundsType>( + builder, info, extendedValue, + /*dataExvIsAssumedSize=*/false, loc); + for (auto bounds : boundsOpsVec) + boundsOps.push_back(bounds); } }; } // namespace >From d438e215f868830aacccc805038f48f24ed81ee0 Mon Sep 17 00:00:00 2001 From: Pranav Bhandarkar <pranav.bhandar...@amd.com> Date: Tue, 3 Jun 2025 13:46:07 -0500 Subject: [PATCH 5/5] Do not handle BoxCharType in hasDynamicSize because hasDynamicSize helper is supposed to return false for pointer-like types which boxchar is. Clients should use a "preprocessing" helper such as dyn_cast_ptrOrBoxEleTy before calling hasDynamicSize as shown below bool HasDynamicSize = fir::hasDynamicSize(fir::dyn_cast_ptrOrBoxEleTy(boxCharType)); --- flang/lib/Optimizer/Dialect/FIRType.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp index f521c9b3058fd..da7aa17445404 100644 --- a/flang/lib/Optimizer/Dialect/FIRType.cpp +++ b/flang/lib/Optimizer/Dialect/FIRType.cpp @@ -285,9 +285,6 @@ bool hasDynamicSize(mlir::Type t) { return true; if (auto rec = mlir::dyn_cast<fir::RecordType>(t)) return hasDynamicSize(rec); - if (auto boxChar = mlir::dyn_cast<fir::BoxCharType>(t)) { - return characterWithDynamicLen(boxChar.getEleTy()); - } return false; } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits