[flang-commits] [flang] [flang] Preserve DO variable updates through aliases (PR #211191)
via flang-commits
flang-commits at lists.llvm.org
Wed Jul 22 00:47:33 PDT 2026
https://github.com/khaki3 created https://github.com/llvm/llvm-project/pull/211191
Use FIR ModRef analysis to retain memory-driven induction when a loop body may update the DO variable through another reference.
>From 1521ee605093534b6211f5112716877df357d57a Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Wed, 22 Jul 2026 00:43:50 -0700
Subject: [PATCH] [flang] Preserve DO variable updates through aliases
Use FIR ModRef analysis to retain memory-driven induction when a loop body may update the DO variable through another reference.
---
flang/lib/Lower/Bridge.cpp | 50 ++++++++++++++++-----
flang/lib/Lower/CMakeLists.txt | 2 +
flang/test/Lower/do_loop_alias_update.f90 | 53 +++++++++++++++++++++++
3 files changed, 93 insertions(+), 12 deletions(-)
create mode 100644 flang/test/Lower/do_loop_alias_update.f90
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 7cde3ae492e14..f34d9c5f06008 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -32,6 +32,7 @@
#include "flang/Lower/StatementContext.h"
#include "flang/Lower/Support/ReductionProcessor.h"
#include "flang/Lower/Support/Utils.h"
+#include "flang/Optimizer/Analysis/AliasAnalysis.h"
#include "flang/Optimizer/Builder/BoxValue.h"
#include "flang/Optimizer/Builder/CUFCommon.h"
#include "flang/Optimizer/Builder/Character.h"
@@ -132,6 +133,7 @@ struct IncrementLoopInfo {
// Data members for structured loops.
mlir::Operation *loopOp = nullptr;
+ mlir::Operation *loopVariableStore = nullptr;
// Data members for unstructured loops.
bool hasRealControl = false;
@@ -3062,18 +3064,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
if (genDoConcurrent)
continue;
- // Lower the loop without the secondary-induction iter_arg so memory
- // recurrences (e.g. reductions) stay visible to later analyses. The DO
- // variable is recomputed from the induction variable in the body; its
- // post-loop value is materialized in genFIRIncrementLoopEnd.
+ // Start with SSA-controlled induction. After lowering the body, switch
+ // to memory-controlled induction if another reference may modify it.
auto loopOp = fir::DoLoopOp::create(
*builder, loc, lowerValue, upperValue, stepValue,
/*unordered=*/false, /*finalCountValue=*/false,
/*iterArgs=*/mlir::ValueRange{});
info.loopOp = loopOp;
builder->setInsertionPointToStart(loopOp.getBody());
- fir::StoreOp::create(*builder, loc, loopOp.getInductionVar(),
- info.loopVariable);
+ info.loopVariableStore = fir::StoreOp::create(
+ *builder, loc, loopOp.getInductionVar(), info.loopVariable);
addLoopAnnotationAttr(info, dirs);
continue;
}
@@ -3214,13 +3214,39 @@ class FirConverter : public Fortran::lower::AbstractConverter {
continue;
}
- // End fir.do_loop. The loop carries no secondary-induction iter_arg, so
- // materialize the Fortran post-loop value lb + tripCount*step after the
- // loop for later uses of the DO variable. Compute it in the loop's
- // index type (matching how the loop counts iterations) so the trip
- // arithmetic does not overflow the DO variable's type for empty
- // range-extreme loops.
+ // Detect writes that may update the DO variable through another
+ // reference.
auto doLoopOp = mlir::cast<fir::DoLoopOp>(info.loopOp);
+ fir::AliasAnalysis aliasAnalysis;
+ bool loopVariableMayBeModified = false;
+ for (mlir::Operation &op : doLoopOp.getBody()->without_terminator()) {
+ if (&op != info.loopVariableStore &&
+ aliasAnalysis.getModRef(&op, info.loopVariable).isMod()) {
+ loopVariableMayBeModified = true;
+ break;
+ }
+ }
+ if (loopVariableMayBeModified) {
+ builder->setInsertionPoint(doLoopOp);
+ fir::StoreOp::create(*builder, loc, doLoopOp.getLowerBound(),
+ info.loopVariable);
+ info.loopVariableStore->erase();
+ info.loopVariableStore = nullptr;
+
+ builder->setInsertionPoint(doLoopOp.getBody()->getTerminator());
+ mlir::Value value =
+ fir::LoadOp::create(*builder, loc, info.loopVariable);
+ mlir::Value step = builder->createConvert(
+ loc, info.getLoopVariableType(), doLoopOp.getStep());
+ value =
+ mlir::arith::AddIOp::create(*builder, loc, value, step, iofAttr);
+ fir::StoreOp::create(*builder, loc, value, info.loopVariable);
+ builder->setInsertionPointAfter(doLoopOp);
+ continue;
+ }
+
+ // Compute the SSA-controlled post-loop value in index type to avoid
+ // narrow integer overflow for empty range-extreme loops.
builder->setInsertionPointAfter(doLoopOp);
mlir::Type idxTy = builder->getIndexType();
mlir::Value lb =
diff --git a/flang/lib/Lower/CMakeLists.txt b/flang/lib/Lower/CMakeLists.txt
index 2db97f4f7ec45..d90e98953a9f0 100644
--- a/flang/lib/Lower/CMakeLists.txt
+++ b/flang/lib/Lower/CMakeLists.txt
@@ -53,6 +53,7 @@ add_flang_library(FortranLower
DEPENDS
CUFAttrs
CUFDialect
+ FIRAnalysis
FIRDialect
FIRTransforms
HLFIRDialect
@@ -61,6 +62,7 @@ add_flang_library(FortranLower
LINK_LIBS
CUFAttrs
CUFDialect
+ FIRAnalysis
FIRDialect
FIRDialectSupport
FIRBuilder
diff --git a/flang/test/Lower/do_loop_alias_update.f90 b/flang/test/Lower/do_loop_alias_update.f90
new file mode 100644
index 0000000000000..56fb2461c3016
--- /dev/null
+++ b/flang/test/Lower/do_loop_alias_update.f90
@@ -0,0 +1,53 @@
+! RUN: %flang_fc1 -emit-hlfir -mmlir --unsafe-cray-pointers -o - %s | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPcray_pointer_loop()
+subroutine cray_pointer_loop
+ integer :: g, g5
+ integer(8) :: lm
+ pointer(lm, gpl6l)
+
+ ! CHECK: %[[G_REF:.*]] = fir.alloca i32 {bindc_name = "g"
+ ! CHECK: %[[G:.*]]:2 = hlfir.declare %[[G_REF]]
+ lm = loc(g)
+ g5 = 0
+
+ ! CHECK: %[[LB:.*]] = arith.constant -2 : i32
+ ! CHECK: %[[UB:.*]] = arith.constant -7 : i32
+ ! CHECK: %[[STEP:.*]] = arith.constant -2 : i32
+ ! CHECK: fir.store %[[LB]] to %[[G]]#0 : !fir.ref<i32>
+ ! CHECK: fir.do_loop %[[IV:.*]] = %[[LB]] to %[[UB]] step %[[STEP]] : i32 {
+ ! CHECK-NOT: fir.store %[[IV]] to %[[G]]#0
+ do g = -2, -7, -2
+ g5 = g5 + 5
+ gpl6l = g - 3
+ ! CHECK: %[[UPDATED:.*]] = fir.load %[[G]]#0 : !fir.ref<i32>
+ ! CHECK: %[[NEXT:.*]] = arith.addi %[[UPDATED]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[NEXT]] to %[[G]]#0 : !fir.ref<i32>
+ ! CHECK: fir.result
+ ! CHECK: }
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPpointer_alias_loop()
+subroutine pointer_alias_loop
+ integer, target :: i
+ integer, pointer :: p
+
+ p => i
+ ! CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i"
+ ! CHECK: %[[I:.*]]:2 = hlfir.declare %[[I_REF]]
+ ! CHECK: %[[LB:.*]] = arith.constant 1 : i32
+ ! CHECK: %[[UB:.*]] = arith.constant 3 : i32
+ ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32
+ ! CHECK: fir.store %[[LB]] to %[[I]]#0 : !fir.ref<i32>
+ ! CHECK: fir.do_loop %[[IV:.*]] = %[[LB]] to %[[UB]] step %[[STEP]] : i32 {
+ ! CHECK-NOT: fir.store %[[IV]] to %[[I]]#0
+ do i = 1, 3
+ p = i + 1
+ ! CHECK: %[[UPDATED:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
+ ! CHECK: %[[NEXT:.*]] = arith.addi %[[UPDATED]], %[[STEP]] overflow<nsw> : i32
+ ! CHECK: fir.store %[[NEXT]] to %[[I]]#0 : !fir.ref<i32>
+ ! CHECK: fir.result
+ ! CHECK: }
+ end do
+end subroutine
More information about the flang-commits
mailing list