[flang-commits] [flang] [llvm] [flang] Guard absent optional operands in elemental character MIN/MAX (PR #191244)
via flang-commits
flang-commits at lists.llvm.org
Fri Apr 10 08:46:17 PDT 2026
================
@@ -465,7 +465,55 @@ mlir::Value HlfirCharExtremumLowering::lowerImpl(
const Fortran::lower::PreparedActualArguments &loweredActuals,
const fir::IntrinsicArgumentLoweringRules *argLowering,
mlir::Type stmtResultType) {
- auto operands = getOperandVector(loweredActuals, argLowering);
+ // Check whether any argument is dynamically optional. When an optional
+ // character argument is absent, calling getActual() to read the character
+ // length from the descriptor is unsafe. Guard each optional argument's
+ // element access inside a fir.if.
+ bool hasDynamicOptional = llvm::any_of(loweredActuals, [](const auto &arg) {
+ return arg.has_value() && arg->handleDynamicOptional();
+ });
+ if (!hasDynamicOptional) {
+ auto operands = getOperandVector(loweredActuals, argLowering);
+ assert(operands.size() >= 2);
+ return createOp<hlfir::CharExtremumOp>(pred, mlir::ValueRange{operands});
+ }
+
+ // For absent optional arguments, use the first required argument's element
+ // as a neutral dummy so that min/max semantics are preserved:
+ // min(a, b, a) == min(a, b) and max(a, b, a) == max(a, b).
+ // Scan ahead to find the first non-optional argument so it can be used as
+ // the neutral element for any optional arguments that appear earlier.
+ mlir::Value firstRequired;
+ for (const auto &opt_arg : loweredActuals) {
+ if (opt_arg && !opt_arg->handleDynamicOptional()) {
+ firstRequired = loadTrivialScalar(*opt_arg);
+ break;
+ }
+ }
+ assert(firstRequired &&
+ "MIN/MAX must have at least one non-optional argument");
+ llvm::SmallVector<mlir::Value> operands;
+ for (const auto &opt_arg : loweredActuals) {
+ if (!opt_arg)
+ continue;
+ if (!opt_arg->handleDynamicOptional()) {
+ mlir::Value elem = loadTrivialScalar(*opt_arg);
+ operands.push_back(elem);
+ } else {
+ mlir::Value isPresent = opt_arg->getIsPresent();
+ mlir::Type elemType = firstRequired.getType();
+ const Fortran::lower::PreparedActualArgument &argRef = *opt_arg;
+ mlir::Value elem =
+ builder.genIfOp(loc, {elemType}, isPresent, /*withElseRegion=*/true)
+ .genThen([&]() {
+ fir::ResultOp::create(builder, loc, loadTrivialScalar(argRef));
+ })
+ .genElse(
+ [&]() { fir::ResultOp::create(builder, loc, firstRequired); })
+ .getResults()[0];
----------------
jeanPerier wrote:
This will cause extra processing time.
Also, you have no guarantee that the type of firstRequired is the same as the type of the current element (they may have different length, one may be an expression and not the other...)
https://github.com/llvm/llvm-project/pull/191244
More information about the flang-commits
mailing list