https://github.com/junfengd-nv updated 
https://github.com/llvm/llvm-project/pull/222790

>From 2159a1b1068f3d9e9a771092f45e97224493ea91 Mon Sep 17 00:00:00 2001
From: Junfeng Dong <[email protected]>
Date: Thu, 10 Sep 2026 14:25:57 -0700
Subject: [PATCH 1/3] [flang] Diagnose integer MOD/MODULO when the divisor is
 zero

Inlined integer remainder is undefined for a zero second argument, so
direct calls and unrestricted-intrinsic wrappers could yield a garbage
value. Emit a P==0 check that reports the same fatal error as the
runtime IntMod, and keep the inlined rem when P is a known nonzero
constant.
---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 27 +++++++++++++--
 .../forall-pointer-assignment-scheduling.f90  |  2 ++
 flang/test/Lower/Intrinsics/mod.f90           | 34 +++++++++++++++++++
 flang/test/Lower/dummy-procedure.f90          | 21 ++++++++++++
 4 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index ddd083ef029e8..c4c47fc4b8c52 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -6916,6 +6916,26 @@ static mlir::Value genFastMod(fir::FirOpBuilder 
&builder, mlir::Location loc,
   return subResult;
 }
 
+/// A zero divisor makes the inlined integer remainder undefined. Guard it
+/// with a test that reports the same fatal error as the runtime IntMod.
+/// A divisor known to be nonzero needs no test.
+static void genIntegerZeroDivisorCheck(fir::FirOpBuilder &builder,
+                                       mlir::Location loc, mlir::Value p,
+                                       bool isModulo) {
+  if (std::optional<llvm::APInt> constantP = fir::getIntIfConstant(p))
+    if (!constantP->isZero())
+      return;
+  mlir::Value zero = builder.createIntegerConstant(loc, p.getType(), 0);
+  mlir::Value isZero = mlir::arith::CmpIOp::create(
+      builder, loc, mlir::arith::CmpIPredicate::eq, p, zero);
+  builder.genIfThen(loc, isZero)
+      .genThen([&]() {
+        fir::runtime::genReportFatalUserError(
+            builder, loc, isModulo ? "MODULO with P==0" : "MOD with P==0");
+      })
+      .end();
+}
+
 mlir::Value IntrinsicLibrary::genMod(mlir::Type resultType,
                                      llvm::ArrayRef<mlir::Value> args) {
   auto mod = builder.getModule();
@@ -6931,8 +6951,10 @@ mlir::Value IntrinsicLibrary::genMod(mlir::Type 
resultType,
     return builder.createUnsigned<mlir::arith::RemUIOp>(loc, signlessType,
                                                         args[0], args[1]);
   }
-  if (mlir::isa<mlir::IntegerType>(resultType))
+  if (mlir::isa<mlir::IntegerType>(resultType)) {
+    genIntegerZeroDivisorCheck(builder, loc, args[1], /*isModulo=*/false);
     return mlir::arith::RemSIOp::create(builder, loc, args[0], args[1]);
+  }
 
   if (resultType.isFloat() && useFastRealMod) {
     // Treat MOD as an approximate function and code-gen inline code
@@ -6949,8 +6971,6 @@ mlir::Value IntrinsicLibrary::genMod(mlir::Type 
resultType,
 // MODULO
 mlir::Value IntrinsicLibrary::genModulo(mlir::Type resultType,
                                         llvm::ArrayRef<mlir::Value> args) {
-  // TODO: we'd better generate a runtime call here, when runtime error
-  // checking is needed (to detect 0 divisor) or when precise math is 
requested.
   assert(args.size() == 2);
   // No floored modulo op in LLVM/MLIR yet. TODO: add one to MLIR.
   // In the meantime, use a simple inlined implementation based on truncated
@@ -6968,6 +6988,7 @@ mlir::Value IntrinsicLibrary::genModulo(mlir::Type 
resultType,
                                                         args[0], args[1]);
   }
   if (mlir::isa<mlir::IntegerType>(resultType)) {
+    genIntegerZeroDivisorCheck(builder, loc, args[1], /*isModulo=*/true);
     auto remainder =
         mlir::arith::RemSIOp::create(builder, loc, args[0], args[1]);
     auto argXor = mlir::arith::XOrIOp::create(builder, loc, args[0], args[1]);
diff --git 
a/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90 
b/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90
index 73b147a25048f..7b6d0b74f5a5d 100644
--- 
a/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90
+++ 
b/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90
@@ -80,6 +80,8 @@ subroutine test_need_to_save_lhs_and_rhs(n, a)
  forall(i=1:n) a(a(n+1-i)%p%i)%p => a(modulo(-2*i, n+1))%p
 end subroutine
 ! CHECK: ------------ scheduling forall in 
_QMforall_pointersPtest_need_to_save_lhs_and_rhs ------------
+! CHECK-NEXT: unknown effect: fir.call @_FortranAReportFatalUserError
+! CHECK-NEXT: unknown effect: fir.call @_FortranAReportFatalUserError
 ! CHECK-NEXT: conflict: R/W
 ! CHECK-NEXT: run 1 save    : forall/region_assign1/rhs
 ! CHECK-NEXT: conflict: R/W
diff --git a/flang/test/Lower/Intrinsics/mod.f90 
b/flang/test/Lower/Intrinsics/mod.f90
index 5bc81d923b800..83952b12c6e1a 100644
--- a/flang/test/Lower/Intrinsics/mod.f90
+++ b/flang/test/Lower/Intrinsics/mod.f90
@@ -36,3 +36,37 @@ subroutine mod_testr16(r, a, p)
 ! CHECK-KIND16: fir.call @_FortranAModReal16(%{{.*}}, %{{.*}}, %{{.*}}, 
%{{.*}}) {{.*}}: (f128, f128, !fir.ref<i8>, i32) -> f128
   r = mod(a, p)
 end subroutine
+
+! A divisor that is not a known nonzero constant is tested, and a fatal
+! error is reported instead of the inlined remainder yielding an undefined 
value.
+! CHECK-LABEL: func @_QPmod_testi4(
+subroutine mod_testi4(r, a, p)
+  integer(4) :: r, a, p
+! CHECK: %[[A:.*]] = fir.declare{{.*}}a"
+! CHECK: %[[P:.*]] = fir.declare{{.*}}p"
+! CHECK: %[[A_LOAD:.*]] = fir.load %[[A]]
+! CHECK: %[[P_LOAD:.*]] = fir.load %[[P]]
+! CHECK: %[[ISZERO:.*]] = arith.cmpi eq, %[[P_LOAD]], %c0{{.*}} : i32
+! CHECK: fir.if %[[ISZERO]] {
+! CHECK:   fir.call @_FortranAReportFatalUserError
+! CHECK: }
+! CHECK: arith.remsi %[[A_LOAD]], %[[P_LOAD]] : i32
+  r = mod(a, p)
+end subroutine
+
+! CHECK-LABEL: func @_QPmod_testi8(
+subroutine mod_testi8(r, a, p)
+  integer(8) :: r, a, p
+! CHECK: fir.call @_FortranAReportFatalUserError
+! CHECK: arith.remsi %{{.*}}, %{{.*}} : i64
+  r = mod(a, p)
+end subroutine
+
+! A constant nonzero divisor keeps the inlined remainder with no test.
+! CHECK-LABEL: func @_QPmod_testi4_constant(
+subroutine mod_testi4_constant(r, a)
+  integer(4) :: r, a
+! CHECK-NOT: fir.call @_FortranAReportFatalUserError
+! CHECK: arith.remsi %{{.*}}, %c8{{.*}} : i32
+  r = mod(a, 8)
+end subroutine
diff --git a/flang/test/Lower/dummy-procedure.f90 
b/flang/test/Lower/dummy-procedure.f90
index 0359897258d2f..79042f97cce9c 100644
--- a/flang/test/Lower/dummy-procedure.f90
+++ b/flang/test/Lower/dummy-procedure.f90
@@ -113,6 +113,16 @@ subroutine test_atan2()
   call foo_atan2(atan2)
 end subroutine
 
+! Integer MOD wrapper must diagnose a zero divisor (direct and dummy-proc 
uses).
+! CHECK-LABEL: func.func @_QPtest_mod
+subroutine test_mod()
+  intrinsic :: mod
+  ! CHECK: %[[f:.*]] = fir.address_of(@fir.mod.i32.ref_i32.ref_i32) : 
(!fir.ref<i32>, !fir.ref<i32>) -> i32
+  ! CHECK: %[[fcast:.*]] = fir.emboxproc %[[f]] : ((!fir.ref<i32>, 
!fir.ref<i32>) -> i32) -> !fir.boxproc<() -> ()>
+  ! CHECK: fir.call @_QPfoo_mod(%[[fcast]]) {{.*}}: (!fir.boxproc<() -> ()>) 
-> ()
+  call foo_mod(mod)
+end subroutine
+
 ! Intrinsic implemented inlined
 ! CHECK-LABEL: func.func @_QPtest_aimag
 subroutine test_aimag()
@@ -166,6 +176,17 @@ subroutine todo3(dummy_proc)
   ! CHECK: %[[atan2:.*]] = math.atan2 %[[xload]], %[[yload]] 
fastmath<contract> : f32
   ! CHECK: return %[[atan2]] : f32
 
+! CHECK-LABEL: func.func private @fir.mod.i32.ref_i32.ref_i32(
+! CHECK-SAME: %[[a:.*]]: !fir.ref<i32>, %[[p:.*]]: !fir.ref<i32>) -> i32
+  ! CHECK-DAG: %[[aload:.*]] = fir.load %[[a]] : !fir.ref<i32>
+  ! CHECK-DAG: %[[pload:.*]] = fir.load %[[p]] : !fir.ref<i32>
+  ! CHECK: %[[iszero:.*]] = arith.cmpi eq, %[[pload]], %c0{{.*}} : i32
+  ! CHECK: fir.if %[[iszero]] {
+  ! CHECK:   fir.call @_FortranAReportFatalUserError
+  ! CHECK: }
+  ! CHECK: %[[res:.*]] = arith.remsi %[[aload]], %[[pload]] : i32
+  ! CHECK: return %[[res]] : i32
+
 !CHECK-LABEL: func.func private @fir.aimag.f32.ref_z32(%arg0: 
!fir.ref<complex<f32>>)
   !CHECK: %[[load:.*]] = fir.load %arg0
   !CHECK: %[[imag:.*]] = fir.extract_value %[[load]], [1 : index] : 
(complex<f32>) -> f32

>From 6567ca64ce348ea5ba1c7fdf93c771f97e180995 Mon Sep 17 00:00:00 2001
From: Junfeng Dong <[email protected]>
Date: Mon, 14 Sep 2026 12:39:05 -0700
Subject: [PATCH 2/3] [flang] Gate integer MOD/MODULO zero checks behind
 -fcheck-integer-mod-zero

Keep the default inlined remainder, and only insert the P==0 fatal check
when the new opt-in flag is set so the extra branch is not paid always.
---
 clang/include/clang/Options/FlangOptions.td   |  4 ++
 clang/lib/Driver/ToolChains/Flang.cpp         |  4 ++
 flang/include/flang/Support/LangOptions.def   |  2 +
 flang/lib/Frontend/CompilerInvocation.cpp     |  3 ++
 flang/lib/Frontend/FrontendActions.cpp        |  8 ++++
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp |  5 +++
 flang/test/Driver/check-integer-mod-zero.f90  | 12 ++++++
 .../forall-pointer-assignment-scheduling.f90  |  2 -
 flang/test/Lower/Intrinsics/mod.f90           | 38 ++++++++++---------
 flang/test/Lower/Intrinsics/modulo.f90        |  7 ++++
 flang/test/Lower/dummy-procedure.f90          |  7 +++-
 11 files changed, 72 insertions(+), 20 deletions(-)
 create mode 100644 flang/test/Driver/check-integer-mod-zero.f90

diff --git a/clang/include/clang/Options/FlangOptions.td 
b/clang/include/clang/Options/FlangOptions.td
index 8fd0d78a2659c..2511bad109e29 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -315,6 +315,10 @@ def ffast_real_mod : Flag<["-"], "ffast-real-mod">, 
Group<f_Group>,
 def fno_fast_real_mod : Flag<["-"], "fno-fast-real-mod">, Group<f_Group>,
   HelpText<"Disable optimization of MOD for REAL types in presence of 
-ffast-math">;
 
+def fcheck_integer_mod_zero
+    : Flag<["-"], "fcheck-integer-mod-zero">, Group<f_Group>,
+      HelpText<"Check for a zero divisor in integer MOD and MODULO">;
+
 defm fp_sum_reassociation
     : BoolOptionWithoutMarshalling<
           "f", "fp-sum-reassociation",
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp 
b/clang/lib/Driver/ToolChains/Flang.cpp
index 0e6858d3bb645..a0517f9343414 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -1367,6 +1367,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction 
&JA,
   // not skipped by the -ffast-math fast path in addFloatingPointOptions().
   addIEEEFPModesOptions(D, Args, CmdArgs, Triple);
 
+  // Integer MOD/MODULO zero-divisor check. Forwarded here with -ffpe-trap=
+  // rather than in addFloatingPointOptions() so -ffast-math does not drop it.
+  Args.AddLastArg(CmdArgs, options::OPT_fcheck_integer_mod_zero);
+
   // Add target args, features, etc.
   addTargetOptions(Args, CmdArgs, JA.getOffloadingArch(),
                    JA.getOffloadingDeviceKind());
diff --git a/flang/include/flang/Support/LangOptions.def 
b/flang/include/flang/Support/LangOptions.def
index 80d2302cc8c72..ecdf4518ea1fe 100644
--- a/flang/include/flang/Support/LangOptions.def
+++ b/flang/include/flang/Support/LangOptions.def
@@ -69,6 +69,8 @@ LANGOPT(OpenMPSimd, 1, false)
 LANGOPT(NoReallocateLHS, 1, false)
 /// Enable fast MOD operations for REAL
 LANGOPT(FastRealMod, 1, false)
+/// Check for a zero divisor in integer MOD and MODULO.
+LANGOPT(CheckIntegerModZero, 1, false)
 /// Bitmask of floating-point exceptions to trap on (from -ffpe-trap=)
 LANGOPT(FPExceptionTraps, 8, 0)
 LANGOPT(VScaleMin, 32, 0)  ///< Minimum vscale range value
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp 
b/flang/lib/Frontend/CompilerInvocation.cpp
index b76b38ff6497f..dd8a0f6ee2fc6 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1586,6 +1586,9 @@ static bool parseFloatingPointArgs(CompilerInvocation 
&invoc,
       opts.FastRealMod = false;
   }
 
+  if (args.getLastArg(clang::options::OPT_fcheck_integer_mod_zero))
+    opts.CheckIntegerModZero = true;
+
   // Set the initial IEEE floating point modes
   setIEEEFPModesArgs(opts, args);
 
diff --git a/flang/lib/Frontend/FrontendActions.cpp 
b/flang/lib/Frontend/FrontendActions.cpp
index da3c1de7e9903..76122094c2994 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -292,6 +292,14 @@ bool CodeGenAction::beginSourceFileAction() {
         mlir::BoolAttr::get(mod.getContext(), true));
   }
 
+  if (ci.getInvocation().getLangOpts().CheckIntegerModZero) {
+    mlir::ModuleOp mod = lb.getModule();
+    mod.getOperation()->setAttr(
+        mlir::StringAttr::get(mod.getContext(),
+                              llvm::Twine{"fir.check_integer_mod_zero"}),
+        mlir::BoolAttr::get(mod.getContext(), true));
+  }
+
   // Create a parse tree and lower it to FIR
   parseAndLowerTree(ci, lb);
 
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index c4c47fc4b8c52..2d40a86d9d91a 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -6922,6 +6922,11 @@ static mlir::Value genFastMod(fir::FirOpBuilder 
&builder, mlir::Location loc,
 static void genIntegerZeroDivisorCheck(fir::FirOpBuilder &builder,
                                        mlir::Location loc, mlir::Value p,
                                        bool isModulo) {
+  mlir::ModuleOp mod = builder.getModule();
+  auto checkEnabled =
+      mod->getAttrOfType<mlir::BoolAttr>("fir.check_integer_mod_zero");
+  if (!checkEnabled || !checkEnabled.getValue())
+    return;
   if (std::optional<llvm::APInt> constantP = fir::getIntIfConstant(p))
     if (!constantP->isZero())
       return;
diff --git a/flang/test/Driver/check-integer-mod-zero.f90 
b/flang/test/Driver/check-integer-mod-zero.f90
new file mode 100644
index 0000000000000..5f695b962d28f
--- /dev/null
+++ b/flang/test/Driver/check-integer-mod-zero.f90
@@ -0,0 +1,12 @@
+! Test driver handling of -fcheck-integer-mod-zero.
+
+! RUN: %flang -fcheck-integer-mod-zero -### %s 2>&1 \
+! RUN:   | FileCheck %s --check-prefix=ENABLE
+! ENABLE: "-fc1"
+! ENABLE-SAME: "-fcheck-integer-mod-zero"
+
+! RUN: %flang -### %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
+! DEFAULT: "-fc1"
+! DEFAULT-NOT: "check-integer-mod-zero"
+
+end
diff --git 
a/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90 
b/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90
index 7b6d0b74f5a5d..73b147a25048f 100644
--- 
a/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90
+++ 
b/flang/test/HLFIR/order_assignments/forall-pointer-assignment-scheduling.f90
@@ -80,8 +80,6 @@ subroutine test_need_to_save_lhs_and_rhs(n, a)
  forall(i=1:n) a(a(n+1-i)%p%i)%p => a(modulo(-2*i, n+1))%p
 end subroutine
 ! CHECK: ------------ scheduling forall in 
_QMforall_pointersPtest_need_to_save_lhs_and_rhs ------------
-! CHECK-NEXT: unknown effect: fir.call @_FortranAReportFatalUserError
-! CHECK-NEXT: unknown effect: fir.call @_FortranAReportFatalUserError
 ! CHECK-NEXT: conflict: R/W
 ! CHECK-NEXT: run 1 save    : forall/region_assign1/rhs
 ! CHECK-NEXT: conflict: R/W
diff --git a/flang/test/Lower/Intrinsics/mod.f90 
b/flang/test/Lower/Intrinsics/mod.f90
index 83952b12c6e1a..a88df834a2894 100644
--- a/flang/test/Lower/Intrinsics/mod.f90
+++ b/flang/test/Lower/Intrinsics/mod.f90
@@ -1,4 +1,5 @@
 ! RUN: bbc -emit-fir %s -o - | FileCheck %s --check-prefixes=CHECK%if 
target=x86_64{{.*}} %{,CHECK-KIND10%}%if flang-supports-f128-math 
%{,CHECK-KIND16%}
+! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero %s -o - | FileCheck %s 
--check-prefix=CHECK-MOD-ZERO
 
 ! CHECK-LABEL: func @_QPmod_testr4(
 subroutine mod_testr4(r, a, p)
@@ -37,36 +38,39 @@ subroutine mod_testr16(r, a, p)
   r = mod(a, p)
 end subroutine
 
-! A divisor that is not a known nonzero constant is tested, and a fatal
-! error is reported instead of the inlined remainder yielding an undefined 
value.
+! By default, integer MOD remains an unchecked inlined remainder.
 ! CHECK-LABEL: func @_QPmod_testi4(
+! CHECK-NOT: fir.call @_FortranAReportFatalUserError
+! CHECK: arith.remsi %{{.*}}, %{{.*}} : i32
+
+! With -fcheck-integer-mod-zero, a divisor that is not a known nonzero
+! constant is tested and a fatal error is reported.
+! CHECK-MOD-ZERO-LABEL: func @_QPmod_testi4(
 subroutine mod_testi4(r, a, p)
   integer(4) :: r, a, p
-! CHECK: %[[A:.*]] = fir.declare{{.*}}a"
-! CHECK: %[[P:.*]] = fir.declare{{.*}}p"
-! CHECK: %[[A_LOAD:.*]] = fir.load %[[A]]
-! CHECK: %[[P_LOAD:.*]] = fir.load %[[P]]
-! CHECK: %[[ISZERO:.*]] = arith.cmpi eq, %[[P_LOAD]], %c0{{.*}} : i32
-! CHECK: fir.if %[[ISZERO]] {
-! CHECK:   fir.call @_FortranAReportFatalUserError
-! CHECK: }
-! CHECK: arith.remsi %[[A_LOAD]], %[[P_LOAD]] : i32
+! CHECK-MOD-ZERO: %[[A:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+! CHECK-MOD-ZERO: %[[P:.*]] = fir.load %{{.*}} : !fir.ref<i32>
+! CHECK-MOD-ZERO: %[[ISZERO:.*]] = arith.cmpi eq, %[[P]], %c0{{.*}} : i32
+! CHECK-MOD-ZERO: fir.if %[[ISZERO]] {
+! CHECK-MOD-ZERO:   fir.call @_FortranAReportFatalUserError
+! CHECK-MOD-ZERO: }
+! CHECK-MOD-ZERO: arith.remsi %[[A]], %[[P]] : i32
   r = mod(a, p)
 end subroutine
 
-! CHECK-LABEL: func @_QPmod_testi8(
+! CHECK-MOD-ZERO-LABEL: func @_QPmod_testi8(
 subroutine mod_testi8(r, a, p)
   integer(8) :: r, a, p
-! CHECK: fir.call @_FortranAReportFatalUserError
-! CHECK: arith.remsi %{{.*}}, %{{.*}} : i64
+! CHECK-MOD-ZERO: fir.call @_FortranAReportFatalUserError
+! CHECK-MOD-ZERO: arith.remsi %{{.*}}, %{{.*}} : i64
   r = mod(a, p)
 end subroutine
 
 ! A constant nonzero divisor keeps the inlined remainder with no test.
-! CHECK-LABEL: func @_QPmod_testi4_constant(
+! CHECK-MOD-ZERO-LABEL: func @_QPmod_testi4_constant(
 subroutine mod_testi4_constant(r, a)
   integer(4) :: r, a
-! CHECK-NOT: fir.call @_FortranAReportFatalUserError
-! CHECK: arith.remsi %{{.*}}, %c8{{.*}} : i32
+! CHECK-MOD-ZERO-NOT: fir.call @_FortranAReportFatalUserError
+! CHECK-MOD-ZERO: arith.remsi %{{.*}}, %c8{{.*}} : i32
   r = mod(a, 8)
 end subroutine
diff --git a/flang/test/Lower/Intrinsics/modulo.f90 
b/flang/test/Lower/Intrinsics/modulo.f90
index 0cb91f3862f20..14458f30f6ebc 100644
--- a/flang/test/Lower/Intrinsics/modulo.f90
+++ b/flang/test/Lower/Intrinsics/modulo.f90
@@ -1,5 +1,6 @@
 ! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s 
-check-prefixes=HONORINF,ALL
 ! RUN: %flang_fc1 -menable-no-infs -emit-hlfir %s -o - | FileCheck %s 
-check-prefixes=CHECK,ALL,%if flang-supports-f128-math %{F128%} %else %{F64%}
+! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero %s -o - | FileCheck %s 
-check-prefix=CHECK-MOD-ZERO
 
 ! ALL-LABEL: func @_QPmodulo_testr(
 ! ALL-SAME: %[[arg0:.*]]: !fir.ref<f64>{{.*}}, %[[arg1:.*]]: 
!fir.ref<f64>{{.*}}, %[[arg2:.*]]: !fir.ref<f64>{{.*}}) {
@@ -25,6 +26,7 @@ subroutine modulo_testr(r, a, p)
 end subroutine
 
 ! ALL-LABEL: func @_QPmodulo_testi(
+! CHECK-MOD-ZERO-LABEL: func @_QPmodulo_testi(
 ! ALL-SAME: %[[arg0:.*]]: !fir.ref<i64>{{.*}}, %[[arg1:.*]]: 
!fir.ref<i64>{{.*}}, %[[arg2:.*]]: !fir.ref<i64>{{.*}}) {
 subroutine modulo_testi(r, a, p)
   integer(8) :: r, a, p
@@ -33,6 +35,11 @@ subroutine modulo_testi(r, a, p)
   ! ALL: %[[r_decl:.*]]:2 = hlfir.declare %[[arg0]] {{.*}} {uniq_name = 
"_QFmodulo_testiEr"} : (!fir.ref<i64>, !fir.dscope) -> (!fir.ref<i64>, 
!fir.ref<i64>)
   ! ALL-DAG: %[[a:.*]] = fir.load %[[a_decl]]#0 : !fir.ref<i64>
   ! ALL-DAG: %[[p:.*]] = fir.load %[[p_decl]]#0 : !fir.ref<i64>
+  ! CHECK-MOD-ZERO: arith.cmpi eq, %{{.*}}, %c0{{.*}} : i64
+  ! CHECK-MOD-ZERO: fir.if %{{.*}} {
+  ! CHECK-MOD-ZERO:   fir.call @_FortranAReportFatalUserError
+  ! CHECK-MOD-ZERO: }
+  ! CHECK-MOD-ZERO: arith.remsi
   ! ALL-DAG: %[[rem:.*]] = arith.remsi %[[a]], %[[p]] : i64
   ! ALL-DAG: %[[argXor:.*]] = arith.xori %[[a]], %[[p]] : i64
   ! ALL-DAG: %[[signDifferent:.*]] = arith.cmpi slt, %[[argXor]], %c0{{.*}} : 
i64
diff --git a/flang/test/Lower/dummy-procedure.f90 
b/flang/test/Lower/dummy-procedure.f90
index 79042f97cce9c..60fe656d98ad2 100644
--- a/flang/test/Lower/dummy-procedure.f90
+++ b/flang/test/Lower/dummy-procedure.f90
@@ -1,4 +1,5 @@
-! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s --check-prefix=NO-MOD-ZERO
 
 ! Test dummy procedures
 
@@ -187,6 +188,10 @@ subroutine todo3(dummy_proc)
   ! CHECK: %[[res:.*]] = arith.remsi %[[aload]], %[[pload]] : i32
   ! CHECK: return %[[res]] : i32
 
+! NO-MOD-ZERO-LABEL: func.func private @fir.mod.i32.ref_i32.ref_i32(
+  ! NO-MOD-ZERO-NOT: fir.call @_FortranAReportFatalUserError
+  ! NO-MOD-ZERO: arith.remsi
+
 !CHECK-LABEL: func.func private @fir.aimag.f32.ref_z32(%arg0: 
!fir.ref<complex<f32>>)
   !CHECK: %[[load:.*]] = fir.load %arg0
   !CHECK: %[[imag:.*]] = fir.extract_value %[[load]], [1 : index] : 
(complex<f32>) -> f32

>From d969105b414451d0f4c7fadda875ef010338b736 Mon Sep 17 00:00:00 2001
From: Junfeng Dong <[email protected]>
Date: Tue, 15 Sep 2026 10:41:36 -0700
Subject: [PATCH 3/3] [flang] Rename -fcheck-integer-mod-zero-divisor and share
 the FIR attr name

Use a more specific driver flag and a constexpr StringRef in FIRAttr.h
so the module attribute is not a duplicated magic string.
---
 clang/include/clang/Options/FlangOptions.td          |  4 ++--
 clang/lib/Driver/ToolChains/Flang.cpp                |  2 +-
 flang/include/flang/Optimizer/Dialect/FIRAttr.h      |  5 +++++
 flang/include/flang/Support/LangOptions.def          |  2 +-
 flang/lib/Frontend/CompilerInvocation.cpp            |  4 ++--
 flang/lib/Frontend/FrontendActions.cpp               |  5 +++--
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp        |  4 ++--
 flang/test/Driver/check-integer-mod-zero-divisor.f90 | 12 ++++++++++++
 flang/test/Driver/check-integer-mod-zero.f90         | 12 ------------
 flang/test/Lower/Intrinsics/mod.f90                  |  4 ++--
 flang/test/Lower/Intrinsics/modulo.f90               |  2 +-
 flang/test/Lower/dummy-procedure.f90                 |  2 +-
 12 files changed, 32 insertions(+), 26 deletions(-)
 create mode 100644 flang/test/Driver/check-integer-mod-zero-divisor.f90
 delete mode 100644 flang/test/Driver/check-integer-mod-zero.f90

diff --git a/clang/include/clang/Options/FlangOptions.td 
b/clang/include/clang/Options/FlangOptions.td
index 2511bad109e29..a456c3c888e28 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -315,8 +315,8 @@ def ffast_real_mod : Flag<["-"], "ffast-real-mod">, 
Group<f_Group>,
 def fno_fast_real_mod : Flag<["-"], "fno-fast-real-mod">, Group<f_Group>,
   HelpText<"Disable optimization of MOD for REAL types in presence of 
-ffast-math">;
 
-def fcheck_integer_mod_zero
-    : Flag<["-"], "fcheck-integer-mod-zero">, Group<f_Group>,
+def fcheck_integer_mod_zero_divisor
+    : Flag<["-"], "fcheck-integer-mod-zero-divisor">, Group<f_Group>,
       HelpText<"Check for a zero divisor in integer MOD and MODULO">;
 
 defm fp_sum_reassociation
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp 
b/clang/lib/Driver/ToolChains/Flang.cpp
index a0517f9343414..cc5d136d98dbf 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -1369,7 +1369,7 @@ void Flang::ConstructJob(Compilation &C, const JobAction 
&JA,
 
   // Integer MOD/MODULO zero-divisor check. Forwarded here with -ffpe-trap=
   // rather than in addFloatingPointOptions() so -ffast-math does not drop it.
-  Args.AddLastArg(CmdArgs, options::OPT_fcheck_integer_mod_zero);
+  Args.AddLastArg(CmdArgs, options::OPT_fcheck_integer_mod_zero_divisor);
 
   // Add target args, features, etc.
   addTargetOptions(Args, CmdArgs, JA.getOffloadingArch(),
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.h 
b/flang/include/flang/Optimizer/Dialect/FIRAttr.h
index 7c071e5d391e6..d92516fed8a3b 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.h
@@ -161,6 +161,11 @@ class RealAttr
   llvm::APFloat getValue() const;
 };
 
+/// Module attribute set when -fcheck-integer-mod-zero-divisor is enabled.
+static constexpr llvm::StringRef getCheckIntegerModZeroDivisorAttrName() {
+  return "fir.check_integer_mod_zero_divisor";
+}
+
 mlir::Attribute parseFirAttribute(FIROpsDialect *dialect,
                                   mlir::DialectAsmParser &parser,
                                   mlir::Type type);
diff --git a/flang/include/flang/Support/LangOptions.def 
b/flang/include/flang/Support/LangOptions.def
index ecdf4518ea1fe..09988ec3214d0 100644
--- a/flang/include/flang/Support/LangOptions.def
+++ b/flang/include/flang/Support/LangOptions.def
@@ -70,7 +70,7 @@ LANGOPT(NoReallocateLHS, 1, false)
 /// Enable fast MOD operations for REAL
 LANGOPT(FastRealMod, 1, false)
 /// Check for a zero divisor in integer MOD and MODULO.
-LANGOPT(CheckIntegerModZero, 1, false)
+LANGOPT(CheckIntegerModZeroDivisor, 1, false)
 /// Bitmask of floating-point exceptions to trap on (from -ffpe-trap=)
 LANGOPT(FPExceptionTraps, 8, 0)
 LANGOPT(VScaleMin, 32, 0)  ///< Minimum vscale range value
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp 
b/flang/lib/Frontend/CompilerInvocation.cpp
index dd8a0f6ee2fc6..231f490457459 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1586,8 +1586,8 @@ static bool parseFloatingPointArgs(CompilerInvocation 
&invoc,
       opts.FastRealMod = false;
   }
 
-  if (args.getLastArg(clang::options::OPT_fcheck_integer_mod_zero))
-    opts.CheckIntegerModZero = true;
+  if (args.getLastArg(clang::options::OPT_fcheck_integer_mod_zero_divisor))
+    opts.CheckIntegerModZeroDivisor = true;
 
   // Set the initial IEEE floating point modes
   setIEEEFPModesArgs(opts, args);
diff --git a/flang/lib/Frontend/FrontendActions.cpp 
b/flang/lib/Frontend/FrontendActions.cpp
index 76122094c2994..93177b2fb3473 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -17,6 +17,7 @@
 #include "flang/Frontend/ParserActions.h"
 #include "flang/Lower/Bridge.h"
 #include "flang/Lower/Support/Verifier.h"
+#include "flang/Optimizer/Dialect/FIRAttr.h"
 #include "flang/Optimizer/Dialect/Support/FIRContext.h"
 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
 #include "flang/Optimizer/Passes/Pipelines.h"
@@ -292,11 +293,11 @@ bool CodeGenAction::beginSourceFileAction() {
         mlir::BoolAttr::get(mod.getContext(), true));
   }
 
-  if (ci.getInvocation().getLangOpts().CheckIntegerModZero) {
+  if (ci.getInvocation().getLangOpts().CheckIntegerModZeroDivisor) {
     mlir::ModuleOp mod = lb.getModule();
     mod.getOperation()->setAttr(
         mlir::StringAttr::get(mod.getContext(),
-                              llvm::Twine{"fir.check_integer_mod_zero"}),
+                              fir::getCheckIntegerModZeroDivisorAttrName()),
         mlir::BoolAttr::get(mod.getContext(), true));
   }
 
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp 
b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 2d40a86d9d91a..9408dc213e2e1 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -6923,8 +6923,8 @@ static void genIntegerZeroDivisorCheck(fir::FirOpBuilder 
&builder,
                                        mlir::Location loc, mlir::Value p,
                                        bool isModulo) {
   mlir::ModuleOp mod = builder.getModule();
-  auto checkEnabled =
-      mod->getAttrOfType<mlir::BoolAttr>("fir.check_integer_mod_zero");
+  auto checkEnabled = mod->getAttrOfType<mlir::BoolAttr>(
+      fir::getCheckIntegerModZeroDivisorAttrName());
   if (!checkEnabled || !checkEnabled.getValue())
     return;
   if (std::optional<llvm::APInt> constantP = fir::getIntIfConstant(p))
diff --git a/flang/test/Driver/check-integer-mod-zero-divisor.f90 
b/flang/test/Driver/check-integer-mod-zero-divisor.f90
new file mode 100644
index 0000000000000..6f18085611104
--- /dev/null
+++ b/flang/test/Driver/check-integer-mod-zero-divisor.f90
@@ -0,0 +1,12 @@
+! Test driver handling of -fcheck-integer-mod-zero-divisor.
+
+! RUN: %flang -fcheck-integer-mod-zero-divisor -### %s 2>&1 \
+! RUN:   | FileCheck %s --check-prefix=ENABLE
+! ENABLE: "-fc1"
+! ENABLE-SAME: "-fcheck-integer-mod-zero-divisor"
+
+! RUN: %flang -### %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
+! DEFAULT: "-fc1"
+! DEFAULT-NOT: "check-integer-mod-zero-divisor"
+
+end
diff --git a/flang/test/Driver/check-integer-mod-zero.f90 
b/flang/test/Driver/check-integer-mod-zero.f90
deleted file mode 100644
index 5f695b962d28f..0000000000000
--- a/flang/test/Driver/check-integer-mod-zero.f90
+++ /dev/null
@@ -1,12 +0,0 @@
-! Test driver handling of -fcheck-integer-mod-zero.
-
-! RUN: %flang -fcheck-integer-mod-zero -### %s 2>&1 \
-! RUN:   | FileCheck %s --check-prefix=ENABLE
-! ENABLE: "-fc1"
-! ENABLE-SAME: "-fcheck-integer-mod-zero"
-
-! RUN: %flang -### %s 2>&1 | FileCheck %s --check-prefix=DEFAULT
-! DEFAULT: "-fc1"
-! DEFAULT-NOT: "check-integer-mod-zero"
-
-end
diff --git a/flang/test/Lower/Intrinsics/mod.f90 
b/flang/test/Lower/Intrinsics/mod.f90
index a88df834a2894..a78344267fbb6 100644
--- a/flang/test/Lower/Intrinsics/mod.f90
+++ b/flang/test/Lower/Intrinsics/mod.f90
@@ -1,5 +1,5 @@
 ! RUN: bbc -emit-fir %s -o - | FileCheck %s --check-prefixes=CHECK%if 
target=x86_64{{.*}} %{,CHECK-KIND10%}%if flang-supports-f128-math 
%{,CHECK-KIND16%}
-! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero %s -o - | FileCheck %s 
--check-prefix=CHECK-MOD-ZERO
+! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero-divisor %s -o - | 
FileCheck %s --check-prefix=CHECK-MOD-ZERO
 
 ! CHECK-LABEL: func @_QPmod_testr4(
 subroutine mod_testr4(r, a, p)
@@ -43,7 +43,7 @@ subroutine mod_testr16(r, a, p)
 ! CHECK-NOT: fir.call @_FortranAReportFatalUserError
 ! CHECK: arith.remsi %{{.*}}, %{{.*}} : i32
 
-! With -fcheck-integer-mod-zero, a divisor that is not a known nonzero
+! With -fcheck-integer-mod-zero-divisor, a divisor that is not a known nonzero
 ! constant is tested and a fatal error is reported.
 ! CHECK-MOD-ZERO-LABEL: func @_QPmod_testi4(
 subroutine mod_testi4(r, a, p)
diff --git a/flang/test/Lower/Intrinsics/modulo.f90 
b/flang/test/Lower/Intrinsics/modulo.f90
index 14458f30f6ebc..b3f98a895643f 100644
--- a/flang/test/Lower/Intrinsics/modulo.f90
+++ b/flang/test/Lower/Intrinsics/modulo.f90
@@ -1,6 +1,6 @@
 ! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s 
-check-prefixes=HONORINF,ALL
 ! RUN: %flang_fc1 -menable-no-infs -emit-hlfir %s -o - | FileCheck %s 
-check-prefixes=CHECK,ALL,%if flang-supports-f128-math %{F128%} %else %{F64%}
-! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero %s -o - | FileCheck %s 
-check-prefix=CHECK-MOD-ZERO
+! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero-divisor %s -o - | 
FileCheck %s -check-prefix=CHECK-MOD-ZERO
 
 ! ALL-LABEL: func @_QPmodulo_testr(
 ! ALL-SAME: %[[arg0:.*]]: !fir.ref<f64>{{.*}}, %[[arg1:.*]]: 
!fir.ref<f64>{{.*}}, %[[arg2:.*]]: !fir.ref<f64>{{.*}}) {
diff --git a/flang/test/Lower/dummy-procedure.f90 
b/flang/test/Lower/dummy-procedure.f90
index 60fe656d98ad2..ad0f35b77088e 100644
--- a/flang/test/Lower/dummy-procedure.f90
+++ b/flang/test/Lower/dummy-procedure.f90
@@ -1,4 +1,4 @@
-! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero %s -o - | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -fcheck-integer-mod-zero-divisor %s -o - | 
FileCheck %s
 ! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s --check-prefix=NO-MOD-ZERO
 
 ! Test dummy procedures

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to