Skip to content

Commit a482741

Browse files
[Flang][mlir] - In fortran lowering, handle block arguments defined outside omp target
This patch handles block arguments that are live-in into the target region of an omp.target op. This is done by simply reusing the mapping mechanism in place for values that are not block arguments. Further, in MapInfoFinalizationPass, this patch adds bounds to maps that map `!fir.ref<!fir.char<k, ?>>` types. Also, we don't clone bounds when binding entry block arguments any more.
1 parent 703d7f3 commit a482741

File tree

4 files changed

+87
-150
lines changed

4 files changed

+87
-150
lines changed

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#ifndef FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_
1818
#define FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_
1919

20+
#include "BoxValue.h"
21+
#include "FIRBuilder.h"
2022
#include "flang/Optimizer/Builder/BoxValue.h"
2123
#include "flang/Optimizer/Builder/FIRBuilder.h"
2224
#include "flang/Optimizer/Builder/Todo.h"
@@ -131,6 +133,31 @@ gatherBoundsOrBoundValues(fir::FirOpBuilder &builder, mlir::Location loc,
131133
}
132134
return values;
133135
}
136+
template <typename BoundsOp, typename BoundsType>
137+
mlir::Value
138+
genBoundsOpFromBoxChar(fir::FirOpBuilder &builder, mlir::Location loc,
139+
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();
145+
mlir::Type refType = builder.getRefType(boxCharType.getEleTy());
146+
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{};
160+
}
134161

135162
/// Generate the bounds operation from the descriptor information.
136163
template <typename BoundsOp, typename BoundsType>
@@ -258,6 +285,10 @@ genImplicitBoundsOps(fir::FirOpBuilder &builder, AddrAndBoundsInfo &info,
258285
bounds = genBaseBoundsOps<BoundsOp, BoundsType>(builder, loc, dataExv,
259286
dataExvIsAssumedSize);
260287
}
288+
if (characterWithDynamicLen(fir::unwrapRefType(baseOp.getType()))) {
289+
bounds = {genBoundsOpFromBoxChar<BoundsOp, BoundsType>(builder, loc,
290+
dataExv, info)};
291+
}
261292

262293
return bounds;
263294
}

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 27 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -217,111 +217,36 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter,
217217
assert(args.isValid() && "invalid args");
218218
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
219219

220-
auto bindSingleMapLike = [&converter,
221-
&firOpBuilder](const semantics::Symbol &sym,
222-
const mlir::Value val,
223-
const mlir::BlockArgument &arg) {
224-
// Clones the `bounds` placing them inside the entry block and returns
225-
// them.
226-
auto cloneBound = [&](mlir::Value bound) {
227-
if (mlir::isMemoryEffectFree(bound.getDefiningOp())) {
228-
mlir::Operation *definingOp = bound.getDefiningOp();
229-
mlir::Operation *clonedOp = firOpBuilder.clone(*definingOp);
230-
// Todo: Do we need to check for more operation types?
231-
// For now, specializing only for fir::UnboxCharOp
232-
if (auto unboxCharOp = mlir::dyn_cast<fir::UnboxCharOp>(definingOp))
233-
return clonedOp->getResult(1);
234-
return clonedOp->getResult(0);
235-
}
236-
TODO(converter.getCurrentLocation(),
237-
"target map-like clause operand unsupported bound type");
238-
};
239-
240-
auto cloneBounds = [cloneBound](llvm::ArrayRef<mlir::Value> bounds) {
241-
llvm::SmallVector<mlir::Value> clonedBounds;
242-
llvm::transform(bounds, std::back_inserter(clonedBounds),
243-
[&](mlir::Value bound) { return cloneBound(bound); });
244-
return clonedBounds;
245-
};
246-
220+
auto bindSingleMapLike = [&converter](const semantics::Symbol &sym,
221+
const mlir::BlockArgument &arg) {
247222
fir::ExtendedValue extVal = converter.getSymbolExtendedValue(sym);
248223
auto refType = mlir::dyn_cast<fir::ReferenceType>(arg.getType());
249224
if (refType && fir::isa_builtin_cptr_type(refType.getElementType())) {
250225
converter.bindSymbol(sym, arg);
251226
} else {
252227
extVal.match(
253228
[&](const fir::BoxValue &v) {
254-
converter.bindSymbol(sym,
255-
fir::BoxValue(arg, cloneBounds(v.getLBounds()),
256-
v.getExplicitParameters(),
257-
v.getExplicitExtents()));
229+
converter.bindSymbol(sym, fir::BoxValue(arg, v.getLBounds(),
230+
v.getExplicitParameters(),
231+
v.getExplicitExtents()));
258232
},
259233
[&](const fir::MutableBoxValue &v) {
260234
converter.bindSymbol(
261-
sym, fir::MutableBoxValue(arg, cloneBounds(v.getLBounds()),
235+
sym, fir::MutableBoxValue(arg, v.getLBounds(),
262236
v.getMutableProperties()));
263237
},
264238
[&](const fir::ArrayBoxValue &v) {
265-
converter.bindSymbol(
266-
sym, fir::ArrayBoxValue(arg, cloneBounds(v.getExtents()),
267-
cloneBounds(v.getLBounds()),
268-
v.getSourceBox()));
239+
converter.bindSymbol(sym, fir::ArrayBoxValue(arg, v.getExtents(),
240+
v.getLBounds(),
241+
v.getSourceBox()));
269242
},
270243
[&](const fir::CharArrayBoxValue &v) {
271-
converter.bindSymbol(
272-
sym, fir::CharArrayBoxValue(arg, cloneBound(v.getLen()),
273-
cloneBounds(v.getExtents()),
274-
cloneBounds(v.getLBounds())));
244+
converter.bindSymbol(sym, fir::CharArrayBoxValue(arg, v.getLen(),
245+
v.getExtents(),
246+
v.getLBounds()));
275247
},
276248
[&](const fir::CharBoxValue &v) {
277-
// In some cases, v.len could reference the input to the
278-
// hlfir.declare which is the corresponding v.addr. While this isn't
279-
// a big problem by itself, it is desirable to extract this out of
280-
// v.addr itself since it's first result will be of type
281-
// fir.boxchar<>. For example, consider the following
282-
//
283-
// func.func private @_QFPrealtest(%arg0: !fir.boxchar<1>)
284-
// %2 = fir.dummy_scope : !fir.dscope
285-
// %3:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) ->
286-
// (!fir.ref<!fir.char<1,?>>, index)
287-
// %4:2 = hlfir.declare (%3#0, %3#1, %2):(!fir.ref<!fir.char<1,?>>,
288-
// index,!fir.dscope) ->
289-
// (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
290-
291-
// In the case above,
292-
// v.addr is
293-
// %4:2 = hlfir.declare (%3#0, %3#1, %2):(!fir.ref<!fir.char<1,?>>,
294-
// index,!fir.dscope) ->
295-
// (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
296-
// v.len is
297-
// %3:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) ->
298-
// (!fir.ref<!fir.char<1,?>>, index)
299-
300-
// Mapping this to the target will create a use of %arg0 on the
301-
// target. Since omp.target is IsolatedFromAbove, %arg0 will have to
302-
// be mapped. Presently, OpenMP lowering of target barfs when it has
303-
// to map a value that doesnt have a defining op. This can be fixed.
304-
// Or we ensure that v.len is fir.unboxchar %4#0 which will
305-
// cause %4#1 to be used on the target and consequently be
306-
// mapped to the target. As such then, there wont be any use of the
307-
// block argument %arg0 on the target.
308-
309-
mlir::Value len = v.getLen();
310-
if (auto declareOp = val.getDefiningOp<hlfir::DeclareOp>()) {
311-
mlir::Value base = declareOp.getBase();
312-
if (auto boxCharType =
313-
mlir::dyn_cast<fir::BoxCharType>(base.getType())) {
314-
mlir::Type lenType = firOpBuilder.getCharacterLengthType();
315-
mlir::Type refType =
316-
firOpBuilder.getRefType(boxCharType.getEleTy());
317-
mlir::Location loc = converter.getCurrentLocation();
318-
auto unboxed = firOpBuilder.create<fir::UnboxCharOp>(
319-
loc, refType, lenType, base);
320-
len = unboxed.getResult(1);
321-
}
322-
}
323-
auto charBoxValue = fir::CharBoxValue(arg, cloneBound(len));
324-
converter.bindSymbol(sym, charBoxValue);
249+
converter.bindSymbol(sym, fir::CharBoxValue(arg, v.getLen()));
325250
},
326251
[&](const fir::UnboxedValue &v) { converter.bindSymbol(sym, arg); },
327252
[&](const auto &) {
@@ -333,7 +258,6 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter,
333258

334259
auto bindMapLike =
335260
[&bindSingleMapLike](llvm::ArrayRef<const semantics::Symbol *> syms,
336-
llvm::ArrayRef<mlir::Value> vars,
337261
llvm::ArrayRef<mlir::BlockArgument> args) {
338262
// Structure component symbols don't have bindings, and can only be
339263
// explicitly mapped individually. If a member is captured implicitly
@@ -342,8 +266,8 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter,
342266
llvm::copy_if(syms, std::back_inserter(processedSyms),
343267
[](auto *sym) { return !sym->owner().IsDerivedType(); });
344268

345-
for (auto [sym, var, arg] : llvm::zip_equal(processedSyms, vars, args))
346-
bindSingleMapLike(*sym, var, arg);
269+
for (auto [sym, arg] : llvm::zip_equal(processedSyms, args))
270+
bindSingleMapLike(*sym, arg);
347271
};
348272

349273
auto bindPrivateLike = [&converter, &firOpBuilder](
@@ -374,20 +298,17 @@ static void bindEntryBlockArgs(lower::AbstractConverter &converter,
374298
// Process in clause name alphabetical order to match block arguments order.
375299
// Do not bind host_eval variables because they cannot be used inside of the
376300
// corresponding region, except for very specific cases handled separately.
377-
bindMapLike(args.hasDeviceAddr.syms, args.hasDeviceAddr.vars,
378-
op.getHasDeviceAddrBlockArgs());
301+
bindMapLike(args.hasDeviceAddr.syms, op.getHasDeviceAddrBlockArgs());
379302
bindPrivateLike(args.inReduction.syms, args.inReduction.vars,
380303
op.getInReductionBlockArgs());
381-
bindMapLike(args.map.syms, args.map.vars, op.getMapBlockArgs());
304+
bindMapLike(args.map.syms, op.getMapBlockArgs());
382305
bindPrivateLike(args.priv.syms, args.priv.vars, op.getPrivateBlockArgs());
383306
bindPrivateLike(args.reduction.syms, args.reduction.vars,
384307
op.getReductionBlockArgs());
385308
bindPrivateLike(args.taskReduction.syms, args.taskReduction.vars,
386309
op.getTaskReductionBlockArgs());
387-
bindMapLike(args.useDeviceAddr.syms, args.useDeviceAddr.vars,
388-
op.getUseDeviceAddrBlockArgs());
389-
bindMapLike(args.useDevicePtr.syms, args.useDevicePtr.vars,
390-
op.getUseDevicePtrBlockArgs());
310+
bindMapLike(args.useDeviceAddr.syms, op.getUseDeviceAddrBlockArgs());
311+
bindMapLike(args.useDevicePtr.syms, op.getUseDevicePtrBlockArgs());
391312
}
392313

393314
/// Get the list of base values that the specified map-like variables point to.
@@ -1427,14 +1348,13 @@ static void genBodyOfTargetOp(
14271348
while (!valuesDefinedAbove.empty()) {
14281349
for (mlir::Value val : valuesDefinedAbove) {
14291350
mlir::Operation *valOp = val.getDefiningOp();
1430-
assert(valOp != nullptr);
14311351

14321352
// NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the
14331353
// indices separately, as the alternative is to eventually map the Box,
14341354
// which comes with a fairly large overhead comparatively. We could be
14351355
// more robust about this and check using a BackwardsSlice to see if we
14361356
// run the risk of mapping a box.
1437-
if (mlir::isMemoryEffectFree(valOp) &&
1357+
if (valOp && mlir::isMemoryEffectFree(valOp) &&
14381358
!mlir::isa<fir::BoxDimsOp>(valOp)) {
14391359
mlir::Operation *clonedOp = valOp->clone();
14401360
entryBlock->push_front(clonedOp);
@@ -1447,7 +1367,13 @@ static void genBodyOfTargetOp(
14471367
valOp->replaceUsesWithIf(clonedOp, replace);
14481368
} else {
14491369
auto savedIP = firOpBuilder.getInsertionPoint();
1450-
firOpBuilder.setInsertionPointAfter(valOp);
1370+
1371+
if (valOp)
1372+
firOpBuilder.setInsertionPointAfter(valOp);
1373+
else
1374+
// This means val is a block argument
1375+
firOpBuilder.setInsertionPoint(targetOp);
1376+
14511377
auto copyVal =
14521378
firOpBuilder.createTemporary(val.getLoc(), val.getType());
14531379
firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);

flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
#include <iterator>
4848
#include <numeric>
4949

50+
#define DEBUG_TYPE "omp-map-info-finalization"
51+
#define PDBGS() (llvm::dbgs() << "[" << DEBUG_TYPE << "]: ")
5052
namespace flangomp {
5153
#define GEN_PASS_DEF_MAPINFOFINALIZATIONPASS
5254
#include "flang/Optimizer/OpenMP/Passes.h.inc"
@@ -554,52 +556,31 @@ class MapInfoFinalizationPass
554556
// with an underlying type of fir.char<k, ?>, i.e a character
555557
// with dynamic length. If so, check if they need bounds added.
556558
func->walk([&](mlir::omp::MapInfoOp op) {
557-
mlir::Value varPtr = op.getVarPtr();
558-
mlir::Type underlyingVarType = fir::unwrapRefType(varPtr.getType());
559-
if (!mlir::isa<fir::CharacterType>(underlyingVarType))
559+
if (!op.getBounds().empty())
560560
return mlir::WalkResult::advance();
561561

562-
fir::CharacterType cType =
563-
mlir::cast<fir::CharacterType>(underlyingVarType);
564-
if (!cType.hasDynamicLen())
565-
return mlir::WalkResult::advance();
562+
mlir::Value varPtr = op.getVarPtr();
563+
mlir::Type underlyingVarType = fir::unwrapRefType(varPtr.getType());
566564

567-
if (!op.getBounds().empty())
568-
return mlir::WalkResult::advance();
569-
// This means varPtr is a BlockArgument. I do not know how to get to a
570-
// fir.boxchar<> type of mlir::Value for varPtr. So, skipping this for
571-
// now.
572-
mlir::Operation *definingOp = varPtr.getDefiningOp();
573-
if (!definingOp)
565+
if (!fir::characterWithDynamicLen(underlyingVarType))
574566
return mlir::WalkResult::advance();
575567

576-
if (auto declOp = mlir::dyn_cast<hlfir::DeclareOp>(definingOp)) {
577-
mlir::Value base = declOp.getBase();
578-
assert(mlir::isa<fir::BoxCharType>(base.getType()));
579-
// mlir::value unboxChar
580-
builder.setInsertionPoint(op);
581-
fir::BoxCharType boxCharType =
582-
mlir::cast<fir::BoxCharType>(base.getType());
583-
mlir::Type idxTy = builder.getIndexType();
584-
mlir::Type lenType = builder.getCharacterLengthType();
585-
mlir::Type refType = builder.getRefType(boxCharType.getEleTy());
586-
mlir::Location location = op.getLoc();
587-
auto unboxed = builder.create<fir::UnboxCharOp>(location, refType,
588-
lenType, base);
589-
// len = unboxed.getResult(1);
590-
mlir::Value zero = builder.createIntegerConstant(location, idxTy, 0);
591-
mlir::Value one = builder.createIntegerConstant(location, idxTy, 1);
592-
mlir::Value extent = unboxed.getResult(1);
593-
mlir::Value stride = one;
594-
mlir::Value ub =
595-
builder.create<mlir::arith::SubIOp>(location, extent, one);
596-
mlir::Type boundTy = builder.getType<mlir::omp::MapBoundsType>();
597-
mlir::Value boundsOp = builder.create<mlir::omp::MapBoundsOp>(
598-
location, boundTy, /*lower_bound=*/zero,
599-
/*upper_bound=*/ub, /*extent=*/extent, /*stride=*/stride,
600-
/*stride_in_bytes = */ true, /*start_idx=*/zero);
601-
op.getBoundsMutable().append({boundsOp});
602-
}
568+
fir::factory::AddrAndBoundsInfo info =
569+
fir::factory::getDataOperandBaseAddr(
570+
builder, varPtr, /*isOptional=*/false, varPtr.getLoc());
571+
fir::ExtendedValue extendedValue =
572+
hlfir::translateToExtendedValue(varPtr.getLoc(), builder,
573+
hlfir::Entity{info.addr},
574+
/*continguousHint=*/true)
575+
.first;
576+
builder.setInsertionPoint(op);
577+
llvm::SmallVector<mlir::Value> boundsOps =
578+
fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
579+
mlir::omp::MapBoundsType>(
580+
builder, info, extendedValue,
581+
/*dataExvIsAssumedSize=*/false, varPtr.getLoc());
582+
583+
op.getBoundsMutable().append(boundsOps);
603584
return mlir::WalkResult::advance();
604585
});
605586

0 commit comments

Comments
 (0)