[flang-commits] [flang] [flang] Guard absent optional operands in elemental character MIN/MAX (PR #191244)

Sairudra More via flang-commits flang-commits at lists.llvm.org
Fri Apr 10 22:31:50 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];
----------------
Saieiei wrote:

Yes, dropped this workaround in the https://github.com/llvm/llvm-project/commit/b23993eb475f81e6c315364b8972bce41218007e update.

https://github.com/llvm/llvm-project/pull/191244


More information about the flang-commits mailing list