Skip to content

Commit

Permalink
[flang][hlfir] custom intrinsic handling for scalar arguments
Browse files Browse the repository at this point in the history
This should produce the same results as the FIR lowering

Differential Revision: https://reviews.llvm.org/D155291
  • Loading branch information
tblah committed Jul 18, 2023
1 parent eb5d798 commit b0935fc
Show file tree
Hide file tree
Showing 2 changed files with 486 additions and 2 deletions.
96 changes: 94 additions & 2 deletions flang/lib/Lower/ConvertCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,97 @@ genIsPresentIfArgMaybeAbsent(mlir::Location loc, hlfir::Entity actual,
.getResult();
}

// Lower a reference to an intrinsic procedure with custom optional handling
static std::optional<hlfir::EntityWithAttributes>
genCustomIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
CallContext &callContext) {
mlir::Location loc = callContext.loc;
if (callContext.isElementalProcWithArrayArgs())
TODO(loc, "Elemental proc with array args with custom optional argument "
"handling");
fir::FirOpBuilder &builder = callContext.getBuilder();
auto &converter = callContext.converter;
auto &stmtCtx = callContext.stmtCtx;
assert(intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling(
callContext.procRef, *intrinsic, converter));
Fortran::lower::PreparedActualArguments loweredActuals;

// callback for optional arguments
auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) {
hlfir::EntityWithAttributes actual = Fortran::lower::convertExprToHLFIR(
loc, converter, expr, callContext.symMap, callContext.stmtCtx);
mlir::Value isPresent =
genIsPresentIfArgMaybeAbsent(loc, actual, expr, callContext,
/*passAsAllocatableOrPointer*/ false)
.value();
loweredActuals.emplace_back(
Fortran::lower::PreparedActualArgument{actual, {isPresent}});
};

// callback for non-optional arguments
auto prepareOtherArg = [&](const Fortran::lower::SomeExpr &expr,
fir::LowerIntrinsicArgAs lowerAs) {
auto getActualFortranElementType = [&]() -> mlir::Type {
return hlfir::getFortranElementType(converter.genType(expr));
};
hlfir::EntityWithAttributes actual = Fortran::lower::convertExprToHLFIR(
loc, converter, expr, callContext.symMap, callContext.stmtCtx);
std::optional<fir::ExtendedValue> exv;
switch (lowerAs) {
case fir::LowerIntrinsicArgAs::Value:
exv = Fortran::lower::convertToValue(loc, converter, actual, stmtCtx);
break;
case fir::LowerIntrinsicArgAs::Addr:
exv = Fortran::lower::convertToAddress(loc, converter, actual, stmtCtx,
getActualFortranElementType());
break;
case fir::LowerIntrinsicArgAs::Box:
exv = Fortran::lower::convertToBox(loc, converter, actual, stmtCtx,
getActualFortranElementType());
break;
case fir::LowerIntrinsicArgAs::Inquired:
TODO(loc, "Inquired non-optional arg to intrinsic with custom handling");
return;
}
if (!exv)
llvm_unreachable("bad switch");
actual = extendedValueToHlfirEntity(loc, builder, exv.value(),
"tmp.custom_intrinsic_arg");
loweredActuals.emplace_back(Fortran::lower::PreparedActualArgument{
actual, /*isPresent=*/std::nullopt});
};

Fortran::lower::prepareCustomIntrinsicArgument(
callContext.procRef, *intrinsic, callContext.resultType,
prepareOptionalArg, prepareOtherArg, converter);

// helper to get a particular prepared argument
auto getArgument = [&](std::size_t i, bool loadArg) -> fir::ExtendedValue {
if (!loweredActuals[i])
return fir::getAbsentIntrinsicArgument();
hlfir::Entity actual = loweredActuals[i]->getActual(loc, builder);
if (loadArg && fir::conformsWithPassByRef(actual.getType())) {
return hlfir::loadTrivialScalar(loc, builder, actual);
}
return actual;
};
// helper to get the isPresent flag for a particular prepared argument
auto isPresent = [&](std::size_t i) -> std::optional<mlir::Value> {
if (!loweredActuals[i])
return {builder.createBool(loc, false)};
if (loweredActuals[i]->handleDynamicOptional())
return {loweredActuals[i]->getIsPresent()};
return std::nullopt;
};

fir::ExtendedValue result = Fortran::lower::lowerCustomIntrinsic(
builder, loc, callContext.getProcedureName(), callContext.resultType,
isPresent, getArgument, loweredActuals.size(), stmtCtx);

return {hlfir::EntityWithAttributes{extendedValueToHlfirEntity(
loc, builder, result, ".tmp.custom_intrinsic_result")}};
}

/// Lower an intrinsic procedure reference.
/// \p intrinsic is null if this is an intrinsic module procedure that must be
/// lowered as if it were an intrinsic module procedure (like C_LOC which is a
Expand All @@ -1751,8 +1842,9 @@ genIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
mlir::Location loc = callContext.loc;
auto &converter = callContext.converter;
if (intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling(
callContext.procRef, *intrinsic, converter))
TODO(loc, "special cases of intrinsic with optional arguments");
callContext.procRef, *intrinsic, converter)) {
return genCustomIntrinsicRef(intrinsic, callContext);
}

Fortran::lower::PreparedActualArguments loweredActuals;
const fir::IntrinsicArgumentLoweringRules *argLowering =
Expand Down
Loading

0 comments on commit b0935fc

Please sign in to comment.