[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-clang
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