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

Reply via email to