Skip to content

Commit 61cfbc7

Browse files
Fix boxchar with firstprivate
1 parent 271272f commit 61cfbc7

File tree

7 files changed

+297
-59
lines changed

7 files changed

+297
-59
lines changed

flang/include/flang/Optimizer/Builder/DirectivesCommon.h

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ inline AddrAndBoundsInfo getDataOperandBaseAddr(fir::FirOpBuilder &builder,
9191

9292
return AddrAndBoundsInfo(symAddr, rawInput, isPresent, boxTy);
9393
}
94+
// For boxchar references, do the same as what is done above for box
95+
// references - Load the boxchar so that it is easier to retrieve the length
96+
// of the underlying character and the data pointer.
97+
if (auto boxCharType = mlir::dyn_cast<fir::BoxCharType>(
98+
fir::unwrapRefType((symAddr.getType())))) {
99+
if (!isOptional && mlir::isa<fir::ReferenceType>(symAddr.getType())) {
100+
mlir::Value boxChar = builder.create<fir::LoadOp>(loc, symAddr);
101+
return AddrAndBoundsInfo(boxChar, rawInput, isPresent);
102+
}
103+
}
94104
return AddrAndBoundsInfo(symAddr, rawInput, isPresent);
95105
}
96106

@@ -137,26 +147,61 @@ template <typename BoundsOp, typename BoundsType>
137147
mlir::Value
138148
genBoundsOpFromBoxChar(fir::FirOpBuilder &builder, mlir::Location loc,
139149
fir::ExtendedValue dataExv, AddrAndBoundsInfo &info) {
140-
// TODO: Handle info.isPresent.
141-
if (auto boxCharType =
142-
mlir::dyn_cast<fir::BoxCharType>(info.addr.getType())) {
143-
mlir::Type idxTy = builder.getIndexType();
144-
mlir::Type lenType = builder.getCharacterLengthType();
150+
151+
if (!mlir::isa<fir::BoxCharType>(fir::unwrapRefType(info.addr.getType())))
152+
return mlir::Value{};
153+
154+
mlir::Type idxTy = builder.getIndexType();
155+
mlir::Type lenType = builder.getCharacterLengthType();
156+
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
157+
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
158+
using ExtentAndStride = std::tuple<mlir::Value, mlir::Value>;
159+
auto [extent, stride] = [&]() -> ExtentAndStride {
160+
if (info.isPresent) {
161+
llvm::SmallVector<mlir::Type> resTypes = {idxTy, idxTy};
162+
mlir::Operation::result_range ifRes =
163+
builder.genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true)
164+
.genThen([&]() {
165+
mlir::Value boxChar =
166+
fir::isa_ref_type(info.addr.getType())
167+
? builder.create<fir::LoadOp>(loc, info.addr)
168+
: info.addr;
169+
fir::BoxCharType boxCharType =
170+
mlir::cast<fir::BoxCharType>(boxChar.getType());
171+
mlir::Type refType = builder.getRefType(boxCharType.getEleTy());
172+
auto unboxed = builder.create<fir::UnboxCharOp>(
173+
loc, refType, lenType, boxChar);
174+
mlir::SmallVector<mlir::Value> results = {unboxed.getResult(1), one };
175+
builder.create<fir::ResultOp>(loc, results);
176+
})
177+
.genElse([&]() {
178+
mlir::SmallVector<mlir::Value> results = {zero, zero };
179+
builder.create<fir::ResultOp>(loc, results); })
180+
.getResults();
181+
return {ifRes[0], ifRes[1]};
182+
}
183+
// We have already established that info.addr.getType() is a boxchar
184+
// or a boxchar address. If an address, load the boxchar.
185+
mlir::Value boxChar = fir::isa_ref_type(info.addr.getType())
186+
? builder.create<fir::LoadOp>(loc, info.addr)
187+
: info.addr;
188+
fir::BoxCharType boxCharType =
189+
mlir::cast<fir::BoxCharType>(boxChar.getType());
145190
mlir::Type refType = builder.getRefType(boxCharType.getEleTy());
146191
auto unboxed =
147-
builder.create<fir::UnboxCharOp>(loc, refType, lenType, info.addr);
148-
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
149-
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
150-
mlir::Value extent = unboxed.getResult(1);
151-
mlir::Value stride = one;
152-
mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one);
153-
mlir::Type boundTy = builder.getType<mlir::omp::MapBoundsType>();
154-
return builder.create<mlir::omp::MapBoundsOp>(
155-
loc, boundTy, /*lower_bound=*/zero,
156-
/*upper_bound=*/ub, /*extent=*/extent, /*stride=*/stride,
157-
/*stride_in_bytes=*/true, /*start_idx=*/zero);
158-
}
159-
return mlir::Value{};
192+
builder.create<fir::UnboxCharOp>(loc, refType, lenType, boxChar);
193+
return {unboxed.getResult(1), one};
194+
}();
195+
196+
mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one);
197+
mlir::Type boundTy = builder.getType<BoundsType>();
198+
return builder.create<BoundsOp>(loc, boundTy,
199+
/*lower_bound=*/zero,
200+
/*upper_bound=*/ub,
201+
/*extent=*/extent,
202+
/*stride=*/stride,
203+
/*stride_in_bytes=*/true,
204+
/*start_idx=*/zero);
160205
}
161206

162207
/// Generate the bounds operation from the descriptor information.
@@ -296,11 +341,11 @@ genImplicitBoundsOps(fir::FirOpBuilder &builder, AddrAndBoundsInfo &info,
296341
bounds = genBaseBoundsOps<BoundsOp, BoundsType>(builder, loc, dataExv,
297342
dataExvIsAssumedSize);
298343
}
299-
if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType()))) {
344+
if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType())) ||
345+
mlir::isa<fir::BoxCharType>(fir::unwrapRefType(info.addr.getType()))) {
300346
bounds = {genBoundsOpFromBoxChar<BoundsOp, BoundsType>(builder, loc,
301347
dataExv, info)};
302348
}
303-
304349
return bounds;
305350
}
306351

flang/lib/Optimizer/Dialect/FIRType.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ bool hasDynamicSize(mlir::Type t) {
285285
return true;
286286
if (auto rec = mlir::dyn_cast<fir::RecordType>(t))
287287
return hasDynamicSize(rec);
288+
if (auto boxChar = mlir::dyn_cast<fir::BoxCharType>(t)) {
289+
return characterWithDynamicLen(boxChar.getEleTy());
290+
}
288291
return false;
289292
}
290293

flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
#include <numeric>
4949

5050
#define DEBUG_TYPE "omp-map-info-finalization"
51-
#define PDBGS() (llvm::dbgs() << "[" << DEBUG_TYPE << "]: ")
51+
5252
namespace flangomp {
5353
#define GEN_PASS_DEF_MAPINFOFINALIZATIONPASS
5454
#include "flang/Optimizer/OpenMP/Passes.h.inc"
@@ -285,6 +285,60 @@ class MapInfoFinalizationPass
285285
return false;
286286
}
287287

288+
mlir::omp::MapInfoOp genBoxcharMemberMap(mlir::omp::MapInfoOp op,
289+
fir::FirOpBuilder &builder) {
290+
if (!op.getMembers().empty())
291+
return op;
292+
mlir::Location loc = op.getVarPtr().getLoc();
293+
mlir::Value boxChar = op.getVarPtr();
294+
295+
if (mlir::isa<fir::ReferenceType>(op.getVarPtr().getType()))
296+
boxChar = builder.create<fir::LoadOp>(loc, op.getVarPtr());
297+
298+
fir::BoxCharType boxCharType = mlir::dyn_cast<fir::BoxCharType>(boxChar.getType());
299+
mlir::Value boxAddr = builder.create<fir::BoxOffsetOp>(loc, op.getVarPtr(), fir::BoxFieldAttr::base_addr);
300+
301+
uint64_t mapTypeToImplicit = static_cast<
302+
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
303+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
304+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT);
305+
306+
mlir::ArrayAttr newMembersAttr;
307+
llvm::SmallVector<llvm::SmallVector<int64_t>> memberIdx = {{0}};
308+
newMembersAttr = builder.create2DI64ArrayAttr(memberIdx);
309+
310+
mlir::Value varPtr = op.getVarPtr();
311+
mlir::omp::MapInfoOp memberMapInfoOp = builder.create<mlir::omp::MapInfoOp>(
312+
op.getLoc(), varPtr.getType(), varPtr,
313+
mlir::TypeAttr::get(boxCharType.getEleTy()),
314+
builder.getIntegerAttr(builder.getIntegerType(64, /*isSigned=*/false),
315+
mapTypeToImplicit),
316+
builder.getAttr<mlir::omp::VariableCaptureKindAttr>(
317+
mlir::omp::VariableCaptureKind::ByRef),
318+
/*varPtrPtr=*/boxAddr,
319+
/*members=*/llvm::SmallVector<mlir::Value>{},
320+
/*member_index=*/mlir::ArrayAttr{},
321+
/*bounds=*/op.getBounds(),
322+
/*mapperId=*/mlir::FlatSymbolRefAttr(), /*name=*/op.getNameAttr(),
323+
builder.getBoolAttr(false));
324+
325+
mlir::omp::MapInfoOp newMapInfoOp = builder.create<mlir::omp::MapInfoOp>(
326+
op.getLoc(), op.getResult().getType(), varPtr,
327+
mlir::TypeAttr::get(llvm::cast<mlir::omp::PointerLikeType>(varPtr.getType())
328+
.getElementType()),
329+
op.getMapTypeAttr(),
330+
op.getMapCaptureTypeAttr(),
331+
/*varPtrPtr=*/mlir::Value{},
332+
/*members=*/llvm::SmallVector<mlir::Value>{memberMapInfoOp},
333+
/*member_index=*/newMembersAttr,
334+
/*bounds=*/llvm::SmallVector<mlir::Value>{},
335+
/*mapperId=*/mlir::FlatSymbolRefAttr(), op.getNameAttr(),
336+
/*partial_map=*/builder.getBoolAttr(false));
337+
op.replaceAllUsesWith(newMapInfoOp.getResult());
338+
op->erase();
339+
return newMapInfoOp;
340+
}
341+
288342
mlir::omp::MapInfoOp genDescriptorMemberMaps(mlir::omp::MapInfoOp op,
289343
fir::FirOpBuilder &builder,
290344
mlir::Operation *target) {
@@ -575,6 +629,7 @@ class MapInfoFinalizationPass
575629
fir::factory::AddrAndBoundsInfo info =
576630
fir::factory::getDataOperandBaseAddr(
577631
builder, varPtr, /*isOptional=*/false, varPtr.getLoc());
632+
578633
fir::ExtendedValue extendedValue =
579634
hlfir::translateToExtendedValue(varPtr.getLoc(), builder,
580635
hlfir::Entity{info.addr},
@@ -743,6 +798,37 @@ class MapInfoFinalizationPass
743798
return mlir::WalkResult::advance();
744799
});
745800

801+
func->walk([&](mlir::omp::MapInfoOp op) {
802+
if (!op.getMembers().empty())
803+
return;
804+
805+
if (!mlir::isa<fir::BoxCharType>(fir::unwrapRefType(op.getVarType())))
806+
return;
807+
808+
// POSSIBLE_HACK_ALERT: If the boxchar has been implicitly mapped then
809+
// it is likely that the underlying pointer to the data
810+
// (!fir.ref<fir.char<k,?>>) has already been mapped. So, skip such
811+
// boxchars. We are primarily interested in boxchars that were mapped
812+
// by passes such as MapsForPrivatizedSymbols that map boxchars that
813+
// are privatized. At present, such boxchar maps are not marked
814+
// implicit. Should they be? I don't know. If they should be then
815+
// we need to change this check for early return OR live with
816+
// over-mapping.
817+
bool hasImplicitMap =
818+
(llvm::omp::OpenMPOffloadMappingFlags(op.getMapType()) &
819+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT) ==
820+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
821+
if (hasImplicitMap)
822+
return;
823+
824+
assert(llvm::hasSingleElement(op->getUsers()) &&
825+
"OMPMapInfoFinalization currently only supports single users "
826+
"of a MapInfoOp");
827+
828+
builder.setInsertionPoint(op);
829+
genBoxcharMemberMap(op, builder);
830+
});
831+
746832
func->walk([&](mlir::omp::MapInfoOp op) {
747833
// TODO: Currently only supports a single user for the MapInfoOp. This
748834
// is fine for the moment, as the Fortran frontend will generate a

flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
// 2. Generalize this for more than just omp.target ops.
2323
//===----------------------------------------------------------------------===//
2424

25+
#include "flang/Optimizer/Builder/DirectivesCommon.h"
2526
#include "flang/Optimizer/Builder/FIRBuilder.h"
27+
#include "flang/Optimizer/Builder/HLFIRTools.h"
2628
#include "flang/Optimizer/Dialect/FIRType.h"
2729
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
2830
#include "flang/Optimizer/HLFIR/HLFIROps.h"
@@ -188,32 +190,45 @@ class MapsForPrivatizedSymbolsPass
188190
// in a subsequent PR.
189191
void genBoundsOps(fir::FirOpBuilder &builder, mlir::Value var,
190192
llvm::SmallVector<mlir::Value> &boundsOps) {
191-
if (!fir::isBoxAddress(var.getType()))
192-
return;
193-
194-
unsigned int rank = 0;
195-
rank = fir::getBoxRank(fir::unwrapRefType(var.getType()));
196-
mlir::Location loc = var.getLoc();
197-
mlir::Type idxTy = builder.getIndexType();
198-
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
199-
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
200-
mlir::Type boundTy = builder.getType<omp::MapBoundsType>();
201-
mlir::Value box = builder.create<fir::LoadOp>(loc, var);
202-
for (unsigned int i = 0; i < rank; ++i) {
203-
mlir::Value dimNo = builder.createIntegerConstant(loc, idxTy, i);
204-
auto dimInfo =
205-
builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy, box, dimNo);
206-
mlir::Value lb = dimInfo.getLowerBound();
207-
mlir::Value extent = dimInfo.getExtent();
208-
mlir::Value byteStride = dimInfo.getByteStride();
209-
mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one);
210-
211-
mlir::Value boundsOp = builder.create<omp::MapBoundsOp>(
212-
loc, boundTy, /*lower_bound=*/zero,
213-
/*upper_bound=*/ub, /*extent=*/extent, /*stride=*/byteStride,
214-
/*stride_in_bytes = */ true, /*start_idx=*/lb);
215-
LLVM_DEBUG(PDBGS() << "Created BoundsOp " << boundsOp << "\n");
216-
boundsOps.push_back(boundsOp);
193+
if (fir::isBoxAddress(var.getType())) {
194+
unsigned int rank = 0;
195+
rank = fir::getBoxRank(fir::unwrapRefType(var.getType()));
196+
mlir::Location loc = var.getLoc();
197+
mlir::Type idxTy = builder.getIndexType();
198+
mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
199+
mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
200+
mlir::Type boundTy = builder.getType<omp::MapBoundsType>();
201+
mlir::Value box = builder.create<fir::LoadOp>(loc, var);
202+
for (unsigned int i = 0; i < rank; ++i) {
203+
mlir::Value dimNo = builder.createIntegerConstant(loc, idxTy, i);
204+
auto dimInfo = builder.create<fir::BoxDimsOp>(loc, idxTy, idxTy, idxTy,
205+
box, dimNo);
206+
mlir::Value lb = dimInfo.getLowerBound();
207+
mlir::Value extent = dimInfo.getExtent();
208+
mlir::Value byteStride = dimInfo.getByteStride();
209+
mlir::Value ub = builder.create<mlir::arith::SubIOp>(loc, extent, one);
210+
211+
mlir::Value boundsOp = builder.create<omp::MapBoundsOp>(
212+
loc, boundTy, /*lower_bound=*/zero,
213+
/*upper_bound=*/ub, /*extent=*/extent, /*stride=*/byteStride,
214+
/*stride_in_bytes = */ true, /*start_idx=*/lb);
215+
LLVM_DEBUG(PDBGS() << "Created BoundsOp " << boundsOp << "\n");
216+
boundsOps.push_back(boundsOp);
217+
}
218+
} else {
219+
mlir::Location loc = var.getLoc();
220+
fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr(builder, var, /*isOptional=*/false, loc);
221+
fir::ExtendedValue extendedValue =
222+
hlfir::translateToExtendedValue(loc, builder,
223+
hlfir::Entity{info.addr},
224+
/*continguousHint=*/true).first;
225+
llvm::SmallVector<mlir::Value> boundsOpsVec =
226+
fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
227+
mlir::omp::MapBoundsType>(
228+
builder, info, extendedValue,
229+
/*dataExvIsAssumedSize=*/false, loc);
230+
for (auto bounds : boundsOpsVec)
231+
boundsOps.push_back(bounds);
217232
}
218233
}
219234
};

flang/test/Fir/convert-to-llvm-openmp-and-fir.fir

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,3 +1288,30 @@ omp.declare_mapper @my_mapper : !fir.type<_QFdeclare_mapperTmy_type{data:i32}> {
12881288
omp.declare_mapper.info map_entries(%4, %3 : !fir.ref<!fir.type<_QFdeclare_mapperTmy_type{data:i32}>>, !fir.ref<i32>)
12891289
// CHECK: }
12901290
}
1291+
1292+
// -----
1293+
omp.private {type = firstprivate} @boxchar_privatizer : !fir.boxchar<1> copy {
1294+
^bb0(%arg0: !fir.boxchar<1>, %arg1: !fir.boxchar<1>):
1295+
omp.yield(%arg1 : !fir.boxchar<1>)
1296+
}
1297+
1298+
func.func @map_privatized_boxchar(%arg0 : !fir.boxchar<1>) {
1299+
%0 = fir.alloca !fir.boxchar<1>
1300+
fir.store %arg0 to %0 : !fir.ref<!fir.boxchar<1>>
1301+
%7 = fir.box_offset %0 base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
1302+
%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>>
1303+
%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>>
1304+
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>) {
1305+
omp.terminator
1306+
}
1307+
return
1308+
}
1309+
1310+
// CHECK-LABEL: llvm.func @map_privatized_boxchar(
1311+
// CHECK-SAME: %[[ARG0:.*]]: !llvm.struct<(ptr, i64)>) {
1312+
// CHECK: %[[BOXCHAR_ALLOCA:.*]] = llvm.alloca {{.*}} x !llvm.struct<(ptr, i64)> : (i64) -> !llvm.ptr
1313+
// CHECK: llvm.store %[[ARG0]], %[[BOXCHAR_ALLOCA]] : !llvm.struct<(ptr, i64)>, !llvm.ptr
1314+
// CHECK: %[[BASE_ADDR:.*]] = llvm.getelementptr %[[BOXCHAR_ALLOCA]][0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64)>
1315+
// 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
1316+
// 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
1317+
// 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)>) {

0 commit comments

Comments
 (0)