Skip to content

Commit f92b8a0

Browse files
authored
Merge pull request #984 from flang-compiler/jpr-elemental-char
Lower calls to elemental procedure with character arguments
2 parents 04376a9 + e648538 commit f92b8a0

File tree

5 files changed

+500
-23
lines changed

5 files changed

+500
-23
lines changed

flang/include/flang/Lower/CharacterExpr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class CharacterExprHelper {
6262
/// Take care of type conversions before emboxing.
6363
/// \p len is converted to the integer type for character lengths if needed.
6464
mlir::Value createEmboxChar(mlir::Value addr, mlir::Value len);
65+
/// Create a fir.boxchar for \p str. If \p str is not in memory, a temp is
66+
/// allocated to create the fir.boxchar.
6567
mlir::Value createEmbox(const fir::CharBoxValue &str);
6668
/// Embox a string array. Note that the size/shape of the array is not
6769
/// retrievable from the resulting mlir::Value.
@@ -82,6 +84,9 @@ class CharacterExprHelper {
8284
/// Returns related fir.ref<fir.array<len x fir.char<kind>>>.
8385
fir::CharBoxValue createCharacterTemp(mlir::Type type, int len);
8486

87+
/// Create a temporary with the same kind, length, and value as source.
88+
fir::CharBoxValue createTempFrom(const fir::ExtendedValue &source);
89+
8590
/// Return true if \p type is a character literal type (is
8691
/// `fir.array<len x fir.char<kind>>`).;
8792
static bool isCharacterLiteral(mlir::Type type);

flang/lib/Lower/CharacterExpr.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,13 +180,21 @@ static mlir::Type getSingletonCharType(mlir::MLIRContext *ctxt, int kind) {
180180

181181
mlir::Value
182182
Fortran::lower::CharacterExprHelper::createEmbox(const fir::CharBoxValue &box) {
183-
// BoxChar require a reference. Base CharBoxValue of CharArrayBoxValue
184-
// are ok here (do not require a scalar type)
183+
// Base CharBoxValue of CharArrayBoxValue are ok here (do not require a scalar
184+
// type)
185185
auto charTy = recoverCharacterType(box.getBuffer().getType());
186186
auto boxCharType =
187187
fir::BoxCharType::get(builder.getContext(), charTy.getFKind());
188188
auto refType = fir::ReferenceType::get(boxCharType.getEleTy());
189-
auto buff = builder.createConvert(loc, refType, box.getBuffer());
189+
mlir::Value buff = box.getBuffer();
190+
// fir.boxchar requires a memory reference. Allocate temp if the character is
191+
// not in memory.
192+
if (!fir::isa_ref_type(buff.getType())) {
193+
auto temp = builder.createTemporary(loc, buff.getType());
194+
builder.create<fir::StoreOp>(loc, buff, temp);
195+
buff = temp;
196+
}
197+
buff = builder.createConvert(loc, refType, buff);
190198
// Convert in case the provided length is not of the integer type that must
191199
// be used in boxchar.
192200
auto len = builder.createConvert(loc, builder.getCharacterLengthType(),
@@ -398,6 +406,24 @@ Fortran::lower::CharacterExprHelper::createCharacterTemp(mlir::Type type,
398406
return {ref, len};
399407
}
400408

409+
fir::CharBoxValue Fortran::lower::CharacterExprHelper::createTempFrom(
410+
const fir::ExtendedValue &source) {
411+
const auto *charBox = source.getCharBox();
412+
if (!charBox)
413+
fir::emitFatalError(loc, "source must be a fir::CharBoxValue");
414+
auto len = charBox->getLen();
415+
auto sourceTy = charBox->getBuffer().getType();
416+
auto temp = createCharacterTemp(sourceTy, len);
417+
if (fir::isa_ref_type(sourceTy)) {
418+
createCopy(temp, *charBox, len);
419+
} else {
420+
auto ref = builder.createConvert(loc, builder.getRefType(sourceTy),
421+
temp.getBuffer());
422+
builder.create<fir::StoreOp>(loc, charBox->getBuffer(), ref);
423+
}
424+
return temp;
425+
}
426+
401427
// Simple length one character assignment without loops.
402428
void Fortran::lower::CharacterExprHelper::createLengthOneAssign(
403429
const fir::CharBoxValue &lhs, const fir::CharBoxValue &rhs) {

flang/lib/Lower/ConvertExpr.cpp

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3556,19 +3556,13 @@ class ArrayExprLowering {
35563556
case PassBy::Value: {
35573557
// True pass-by-value semantics.
35583558
PushSemantics(ConstituentSemantics::RefTransparent);
3559-
auto lambda = genarr(*expr);
3560-
operands[arg.firArgument] = [=](IterSpace iters) {
3561-
return lambda(iters);
3562-
};
3559+
operands[arg.firArgument] = genarr(*expr);
35633560
} break;
35643561
case PassBy::BaseAddressValueAttribute: {
35653562
// VALUE attribute or pass-by-reference to a copy semantics. (byval*)
35663563
if (isArray(*expr)) {
35673564
PushSemantics(ConstituentSemantics::ByValueArg);
3568-
auto lambda = genarr(*expr);
3569-
operands[arg.firArgument] = [=](IterSpace iters) {
3570-
return lambda(iters);
3571-
};
3565+
operands[arg.firArgument] = genarr(*expr);
35723566
} else {
35733567
// Store scalar value in a temp to fulfill VALUE attribute.
35743568
auto val = fir::getBase(asScalar(*expr));
@@ -3582,25 +3576,39 @@ class ArrayExprLowering {
35823576
}
35833577
} break;
35843578
case PassBy::BaseAddress: {
3579+
if (isArray(*expr)) {
3580+
PushSemantics(ConstituentSemantics::RefOpaque);
3581+
operands[arg.firArgument] = genarr(*expr);
3582+
} else {
3583+
auto exv = asScalarRef(*expr);
3584+
operands[arg.firArgument] = [=](IterSpace iters) { return exv; };
3585+
}
3586+
} break;
3587+
case PassBy::CharBoxValueAttribute: {
35853588
if (isArray(*expr)) {
35863589
PushSemantics(ConstituentSemantics::RefOpaque);
35873590
auto lambda = genarr(*expr);
35883591
operands[arg.firArgument] = [=](IterSpace iters) {
3589-
return lambda(iters);
3592+
return Fortran::lower::CharacterExprHelper{builder, loc}
3593+
.createTempFrom(lambda(iters));
35903594
};
35913595
} else {
3592-
auto exv = asScalarRef(*expr);
3593-
operands[arg.firArgument] = [=](IterSpace iters) { return exv; };
3596+
Fortran::lower::CharacterExprHelper helper(builder, loc);
3597+
auto argVal = helper.createTempFrom(asScalarRef(*expr));
3598+
operands[arg.firArgument] = [=](IterSpace iters) -> ExtValue {
3599+
return argVal;
3600+
};
35943601
}
35953602
} break;
3596-
case PassBy::CharBoxValueAttribute:
3597-
TODO(loc, "CHARACTER, VALUE");
3598-
break;
3599-
case PassBy::BoxChar:
3600-
TODO(loc, "CHARACTER");
3601-
break;
3603+
case PassBy::BoxChar: {
3604+
PushSemantics(ConstituentSemantics::RefOpaque);
3605+
operands[arg.firArgument] = genarr(*expr);
3606+
} break;
36023607
case PassBy::AddressAndLength:
3603-
TODO(loc, "address and length argument");
3608+
// PassBy::AddressAndLength is only used for character results. Results
3609+
// are not handled here.
3610+
fir::emitFatalError(
3611+
loc, "unexpected PassBy::AddressAndLength in elemental call");
36043612
break;
36053613
case PassBy::Box:
36063614
case PassBy::MutableBox:
@@ -3611,15 +3619,28 @@ class ArrayExprLowering {
36113619

36123620
if (caller.getIfIndirectCallSymbol())
36133621
fir::emitFatalError(loc, "cannot be indirect call");
3622+
3623+
// TODO: share logic with the scalar function calls when the result must be
3624+
// allocated on the caller side.
3625+
if (caller.callerAllocateResult())
3626+
TODO(loc, "elemental call requiring result allocation");
36143627
auto funcSym = builder.getSymbolRefAttr(caller.getMangledName());
36153628
auto resTys = caller.getFuncOp().getType().getResults();
36163629
if (caller.getFuncOp().getType().getResults() !=
36173630
caller.genFunctionType().getResults())
36183631
fir::emitFatalError(loc, "type mismatch on declared function");
36193632
return [=](IterSpace iters) -> ExtValue {
36203633
llvm::SmallVector<mlir::Value> args;
3621-
for (const auto &cc : operands)
3622-
args.push_back(fir::getBase(cc(iters)));
3634+
for (const auto &cc : operands) {
3635+
auto exv = cc(iters);
3636+
auto arg = exv.match(
3637+
[&](const fir::CharBoxValue &cb) -> mlir::Value {
3638+
return Fortran::lower::CharacterExprHelper{builder, loc}
3639+
.createEmbox(cb);
3640+
},
3641+
[&](const auto &) { return fir::getBase(exv); });
3642+
args.push_back(arg);
3643+
}
36233644
auto call = builder.create<fir::CallOp>(loc, resTys, funcSym, args);
36243645
return call.getResult(0);
36253646
};

0 commit comments

Comments
 (0)