[flang-commits] [flang] [flang][hlfir] Optimize MINLOC/MAXLOC with equality mask (PR #211722)
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Thu Sep 17 18:54:39 PDT 2026
================
@@ -0,0 +1,393 @@
+//===- LoopIdiomRecognize.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Eliminate redundant minMax tracking in equality-mask
+// location-search loops after HLFIR-to-FIR lowering and LICM.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/HLFIR/HLFIROps.h"
+#include "flang/Optimizer/Transforms/Passes.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Pass/Pass.h"
+
+namespace fir {
+#define GEN_PASS_DEF_LOOPIDIOMRECOGNIZE
+#include "flang/Optimizer/Transforms/Passes.h.inc"
+} // namespace fir
+
+namespace {
+
+/// Return the array base reached via array_coor, designate, or apply, or
+/// nullptr.
+static mlir::Value getBase(mlir::Value v) {
+ while (v) {
+ while (auto conv = v.getDefiningOp<fir::ConvertOp>())
+ v = conv.getOperand();
+
+ if (!v)
+ break;
+
+ mlir::Operation *def = v.getDefiningOp();
+ if (!def)
+ break;
+
+ if (auto coor = mlir::dyn_cast<fir::ArrayCoorOp>(def))
+ return coor.getMemref();
+ if (auto desig = mlir::dyn_cast<hlfir::DesignateOp>(def))
+ return desig.getMemref();
+ if (auto apply = mlir::dyn_cast<hlfir::ApplyOp>(def))
+ return apply.getExpr();
+
+ if (auto load = mlir::dyn_cast<fir::LoadOp>(def)) {
+ if (fir::isa_volatile_type(load.getMemref().getType()) ||
+ fir::isa_volatile_type(load.getType()))
+ break;
+ v = load.getMemref();
+ continue;
+ }
+
+ break;
+ }
+ return nullptr;
+}
+
+/// Return the array being searched, extracted from the minMax then-yield.
+static mlir::Value getSearchArray(fir::IfOp ifOp, unsigned minMaxIdx) {
+ mlir::Block &thenBlock = ifOp.getThenRegion().front();
+ auto thenYield = mlir::cast<fir::ResultOp>(thenBlock.getTerminator());
+ mlir::Value minMax = thenYield.getOperand(minMaxIdx);
+
+ while (auto sel = minMax.getDefiningOp<mlir::arith::SelectOp>())
+ minMax = sel.getTrueValue();
+
+ return getBase(minMax);
+}
+
+/// Match arith.cmpi eq where one side loads from searchArray and the other is
+/// loop-invariant.
+static mlir::Value getFIREqualityMaskTarget(mlir::Value cond,
+ mlir::Value searchArray,
+ fir::DoLoopOp rootLoop) {
+ while (auto conv = cond.getDefiningOp<fir::ConvertOp>())
+ cond = conv.getOperand();
+
+ auto cmpOp = cond.getDefiningOp<mlir::arith::CmpIOp>();
+ if (!cmpOp || cmpOp.getPredicate() != mlir::arith::CmpIPredicate::eq)
+ return nullptr;
+
+ auto canonicalizeBase = [](mlir::Value v) -> mlir::Value {
+ while (v) {
+ mlir::Operation *def = v.getDefiningOp();
+ if (!def)
+ break;
+ if (auto decl = mlir::dyn_cast<hlfir::DeclareOp>(def))
+ v = decl.getMemref();
+ else if (mlir::isa<fir::ConvertOp, hlfir::AsExprOp>(def))
+ v = def->getOperand(0);
+ else
+ break;
+ }
+ return v;
+ };
+
+ mlir::Value canonSearch = canonicalizeBase(searchArray);
+ mlir::Value lhsBase = canonicalizeBase(getBase(cmpOp.getLhs()));
+ mlir::Value rhsBase = canonicalizeBase(getBase(cmpOp.getRhs()));
+
+ auto isInvariant = [&](mlir::Value v) -> bool {
+ if (mlir::Operation *def = v.getDefiningOp())
+ return !rootLoop->isAncestor(def);
+ if (auto blockArg = mlir::dyn_cast<mlir::BlockArgument>(v)) {
+ mlir::Operation *ownerOp = blockArg.getOwner()->getParentOp();
+ return !rootLoop->isAncestor(ownerOp) &&
+ (ownerOp != rootLoop.getOperation());
+ }
+ return true;
+ };
+
+ if (lhsBase && lhsBase == canonSearch && !rhsBase &&
----------------
vzakhari wrote:
I do not think this guarantees that the min/max select and the comparison are actually using the same value loaded from the array. The base might be the same, but indices might be different. I am not sure why you need all this complexity with handling the array base. All we care is the value produced by the load.
https://github.com/llvm/llvm-project/pull/211722
More information about the flang-commits
mailing list