[flang-commits] [clang] [flang] [flang][clang] Add support for -finit-logical in Flang (PR #150939)

via flang-commits flang-commits at lists.llvm.org
Mon Jul 28 06:06:57 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (NimishMishra)

<details>
<summary>Changes</summary>

This PR adds the GNU gfortran compatible flag `-finit-logical`. It follows similar semantics as gfortran does

---
Full diff: https://github.com/llvm/llvm-project/pull/150939.diff


6 Files Affected:

- (modified) clang/include/clang/Driver/Options.td (+5-1) 
- (modified) clang/lib/Driver/ToolChains/Flang.cpp (+2-2) 
- (modified) flang/include/flang/Lower/LoweringOptions.def (+6) 
- (modified) flang/lib/Frontend/CompilerInvocation.cpp (+16) 
- (modified) flang/lib/Lower/Bridge.cpp (+73) 
- (added) flang/test/Lower/logical_init.f90 (+82) 


``````````diff
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index e2ab046b26ae6..9b6ab62e13255 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -6960,6 +6960,7 @@ def A_DASH : Joined<["-"], "A-">, Group<gfortran_Group>;
 def static_libgfortran : Flag<["-"], "static-libgfortran">, Group<gfortran_Group>;
 
 // "f" options with values for gfortran.
+// Some of these options are visible for LLVM Flang too.
 def fblas_matmul_limit_EQ : Joined<["-"], "fblas-matmul-limit=">, Group<gfortran_Group>;
 def fcheck_EQ : Joined<["-"], "fcheck=">, Group<gfortran_Group>;
 def fcoarray_EQ : Joined<["-"], "fcoarray=">, Group<gfortran_Group>;
@@ -6967,7 +6968,10 @@ def ffpe_trap_EQ : Joined<["-"], "ffpe-trap=">, Group<gfortran_Group>;
 def ffree_line_length_VALUE : Joined<["-"], "ffree-line-length-">, Group<gfortran_Group>;
 def finit_character_EQ : Joined<["-"], "finit-character=">, Group<gfortran_Group>;
 def finit_integer_EQ : Joined<["-"], "finit-integer=">, Group<gfortran_Group>;
-def finit_logical_EQ : Joined<["-"], "finit-logical=">, Group<gfortran_Group>;
+def finit_logical_EQ : Joined<["-"], "finit-logical=">,
+                       Group<gfortran_Group>,
+                       Visibility<[FlangOption, FC1Option]>,
+                       HelpText<"Initialize logical type.">;
 def finit_real_EQ : Joined<["-"], "finit-real=">, Group<gfortran_Group>;
 def fmax_array_constructor_EQ : Joined<["-"], "fmax-array-constructor=">, Group<gfortran_Group>;
 def fmax_errors_EQ : Joined<["-"], "fmax-errors=">, Group<gfortran_Group>;
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 7ab41e9b85a04..8478ce4ac57d5 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -172,8 +172,8 @@ void Flang::addCodegenOptions(const ArgList &Args,
        options::OPT_flang_deprecated_no_hlfir,
        options::OPT_fno_ppc_native_vec_elem_order,
        options::OPT_fppc_native_vec_elem_order, options::OPT_finit_global_zero,
-       options::OPT_fno_init_global_zero, options::OPT_frepack_arrays,
-       options::OPT_fno_repack_arrays,
+       options::OPT_finit_logical_EQ, options::OPT_fno_init_global_zero,
+       options::OPT_frepack_arrays, options::OPT_fno_repack_arrays,
        options::OPT_frepack_arrays_contiguity_EQ,
        options::OPT_fstack_repack_arrays, options::OPT_fno_stack_repack_arrays,
        options::OPT_ftime_report, options::OPT_ftime_report_EQ,
diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def
index 8135704971aa4..3e2bd9afe7ce8 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -74,5 +74,11 @@ ENUM_LOWERINGOPT(SkipExternalRttiDefinition, unsigned, 1, 0)
 /// If false, lower to the complex dialect of MLIR.
 /// On by default.
 ENUM_LOWERINGOPT(ComplexDivisionToRuntime, unsigned, 1, 1)
+
+/// Initialization for logical type
+/// 	-1  : No initialization
+///	 0  : Initialized to .FALSE.
+///	 1  : Initialized to .TRUE.
+ENUM_LOWERINGOPT(LogicalInit, signed, 2, -1)
 #undef LOWERINGOPT
 #undef ENUM_LOWERINGOPT
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index f55d866435997..97fae23f0e54b 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1541,6 +1541,22 @@ bool CompilerInvocation::createFromArgs(
   else
     invoc.loweringOpts.setInitGlobalZero(false);
 
+  // -finit-logical
+  if (const auto *arg =
+          args.getLastArg(clang::driver::options::OPT_finit_logical_EQ)) {
+    llvm::StringRef argValue = llvm::StringRef(arg->getValue());
+    if (argValue.lower() == "true")
+      invoc.loweringOpts.setLogicalInit(1);
+    else if (argValue.lower() == "false")
+      invoc.loweringOpts.setLogicalInit(0);
+    else {
+      const unsigned diagID = diags.getCustomDiagID(
+          clang::DiagnosticsEngine::Error,
+          "Invalid argument to -finit-logical. Must be <true/false>");
+      diags.Report(diagID);
+    }
+  }
+
   // Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or
   // -Rpass-analysis. This will be used later when processing and outputting the
   // remarks generated by LLVM in ExecuteCompilerInvocation.cpp.
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 92aae792248c5..db66d9693b369 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -5720,6 +5720,79 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   void instantiateVar(const Fortran::lower::pft::Variable &var,
                       Fortran::lower::AggregateStoreMap &storeMap) {
     Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap);
+
+    /// Implicit assignment is defined by the `-finit-*` family of flags.
+    /// These options do not initialize:
+    ///   1) Any variable already initialized
+    ///   2) objects with the POINTER attribute
+    ///   3) allocatable arrays
+    ///   4) variables that appear in an EQUIVALENCE statement
+
+    auto isEligibleForImplicitAssignment = [&var]() -> bool {
+      if (!var.hasSymbol())
+        return false;
+
+      const Fortran::semantics::Symbol &sym = var.getSymbol();
+      if (const auto *details =
+              sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
+        if (details->init())
+          return false;
+      }
+
+      if (sym.attrs().test(Fortran::semantics::Attr::POINTER))
+        return false;
+
+      if (sym.Rank() > 0 &&
+          sym.attrs().test(Fortran::semantics::Attr::ALLOCATABLE))
+        return false;
+
+      if (Fortran::lower::pft::getDependentVariableList(sym).size() > 1)
+        return false;
+
+      return true;
+    };
+
+    auto processImplicitAssignment = [&]() -> void {
+      const Fortran::semantics::Symbol &sym = var.getSymbol();
+      const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
+      bool isInitLogicalFlagDefined =
+          (getLoweringOptions().getLogicalInit() == 1 ||
+           getLoweringOptions().getLogicalInit() == 0);
+
+      /*
+       * Process -finit-logical=true|false
+       * Create an implicit assignment of form `var = value`,
+       * where `value` is either true or false, and generically
+       * build the assignment.
+       */
+      if (isInitLogicalFlagDefined &&
+          declTy->category() ==
+              Fortran::semantics::DeclTypeSpec::Category::Logical) {
+        Fortran::parser::Expr expr =
+            Fortran::parser::Expr{Fortran::parser::LiteralConstant{
+                Fortran::parser::LogicalLiteralConstant{
+                    (getLoweringOptions().getLogicalInit() == 0) ? false : true,
+                    std::optional<Fortran::parser::KindParam>{}}}};
+        Fortran::parser::Designator designator = Fortran::parser::Designator{
+            Fortran::parser::DataRef{Fortran::parser::Name{
+                Fortran::parser::FindSourceLocation(sym.name()),
+                const_cast<Fortran::semantics::Symbol *>(&sym)}}};
+        designator.source = Fortran::parser::FindSourceLocation(sym.name());
+        Fortran::parser::Variable variable = Fortran::parser::Variable{
+            Fortran::common::Indirection<Fortran::parser::Designator>{
+                std::move(designator)}};
+        Fortran::parser::AssignmentStmt stmt = Fortran::parser::AssignmentStmt{
+            std::make_tuple(std::move(variable), std::move(expr))};
+        Fortran::evaluate::ExpressionAnalyzer ea{bridge.getSemanticsContext()};
+        const Fortran::evaluate::Assignment *assign = ea.Analyze(stmt);
+        if (assign)
+          genAssignment(*assign);
+      }
+    };
+
+    if (isEligibleForImplicitAssignment())
+      processImplicitAssignment();
+
     if (var.hasSymbol())
       genOpenMPSymbolProperties(*this, var);
   }
diff --git a/flang/test/Lower/logical_init.f90 b/flang/test/Lower/logical_init.f90
new file mode 100644
index 0000000000000..4fd4506496e46
--- /dev/null
+++ b/flang/test/Lower/logical_init.f90
@@ -0,0 +1,82 @@
+! RUN: %flang_fc1 -emit-fir -o - %s | FileCheck --check-prefix=CHECK-UNINT %s
+! RUN: %flang_fc1 -emit-fir -finit-logical=true -o - %s | FileCheck --check-prefix=CHECK-TRUE %s
+! RUN: %flang_fc1 -emit-fir -finit-logical=false -o - %s | FileCheck --check-prefix=CHECK-FALSE %s
+
+subroutine logical_scalar
+!CHECK-UNINT-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK-UNINT-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+
+!CHECK-TRUE: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK-TRUE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+
+!CHECK-FALSE: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-FALSE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+  logical :: x
+end subroutine
+
+
+subroutine logical_allocatable
+!CHECK-UNINT-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-UINIT-NOT: {{.*}} = fir.convert %true : (i1) -> !fir.logical<4>
+
+!CHECK-TRUE: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK-TRUE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+
+!CHECK-FALSE: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-FALSE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+  logical, allocatable :: x
+end subroutine
+
+
+subroutine logical_array
+!CHECK-UNINT-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-UINIT-NOT: {{.*}} = fir.convert %true : (i1) -> !fir.logical<4>
+
+!CHECK-TRUE: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK-TRUE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+
+!CHECK-FALSE: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-FALSE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+  logical :: x(5)
+end subroutine
+
+
+subroutine logical_pointer
+!CHECK-UNINT-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-UINIT-NOT: {{.*}} = fir.convert %true : (i1) -> !fir.logical<4>
+
+!CHECK-TRUE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK-TRUE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+
+!CHECK-FALSE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-FALSE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+  logical, pointer :: x
+end subroutine
+
+
+subroutine logical_allocatable_array
+!CHECK-UNINT-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-UINIT-NOT: {{.*}} = fir.convert %true : (i1) -> !fir.logical<4>
+
+!CHECK-TRUE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK-TRUE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+
+!CHECK-FALSE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-FALSE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+  logical, allocatable :: x(:)
+end subroutine
+
+
+subroutine logical_in_equivalence
+!CHECK-UNINT-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-UINIT-NOT: {{.*}} = fir.convert %true : (i1) -> !fir.logical<4>
+
+!CHECK-TRUE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+!CHECK-TRUE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+
+!CHECK-FALSE-NOT: {{.*}} = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK-FALSE-NOT: {{.}} = fir.convert %true : (i1) -> !fir.logical<4>
+  logical :: x
+  real :: y
+  equivalence(x,y)
+end subroutine

``````````

</details>


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


More information about the flang-commits mailing list