-
Notifications
You must be signed in to change notification settings - Fork 14.6k
[flang][clang] Add support for -finit-logical in Flang #150939
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang-driver Author: None (NimishMishra) ChangesThis PR adds the GNU gfortran compatible flag Full diff: https://github.com/llvm/llvm-project/pull/150939.diff 6 Files Affected:
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
|
@llvm/pr-subscribers-flang-fir-hlfir Author: None (NimishMishra) ChangesThis PR adds the GNU gfortran compatible flag Full diff: https://github.com/llvm/llvm-project/pull/150939.diff 6 Files Affected:
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
|
@llvm/pr-subscribers-clang Author: None (NimishMishra) ChangesThis PR adds the GNU gfortran compatible flag Full diff: https://github.com/llvm/llvm-project/pull/150939.diff 6 Files Affected:
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
|
@llvm/pr-subscribers-flang-driver Author: None (NimishMishra) ChangesThis PR adds the GNU gfortran compatible flag Full diff: https://github.com/llvm/llvm-project/pull/150939.diff 6 Files Affected:
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
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few trivial comments.
def finit_logical_EQ : Joined<["-"], "finit-logical=">, | ||
Group<gfortran_Group>, | ||
Visibility<[FlangOption, FC1Option]>, | ||
HelpText<"Initialize logical type.">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: list the possible values here.
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>; | ||
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>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be moved from the gfortran group.
if (argValue.lower() == "true") | ||
invoc.loweringOpts.setLogicalInit(1); | ||
else if (argValue.lower() == "false") | ||
invoc.loweringOpts.setLogicalInit(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: braces to match the else.
def finit_logical_EQ : Joined<["-"], "finit-logical=">, Group<gfortran_Group>; | ||
def finit_logical_EQ : Joined<["-"], "finit-logical=">, | ||
Group<gfortran_Group>, | ||
Visibility<[FlangOption, FC1Option]>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need a driver test as well.
!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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is probably better to test that the variable is assigned the relevant value.
logical :: x | ||
real :: y | ||
equivalence(x,y) | ||
end subroutine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Add a check that derived components are not affected.
/// 1) Any variable already initialized | ||
/// 2) objects with the POINTER attribute | ||
/// 3) allocatable arrays | ||
/// 4) variables that appear in an EQUIVALENCE statement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this to match the implementation in gfortran?
@@ -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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: It may be better to add OPT_finit_logical_EQ
before OPT_finit_global_zero
. This way, we don't split OPT_finit_global_zero
and OPT_fno_init_global_zero
since the OPT_<name>
and OPT_no_<name>
values are typically listed next to one another here.
|
||
/// Initialization for logical type | ||
/// -1 : No initialization | ||
/// 0 : Initialized to .FALSE. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: Perhaps align the colons.
if (const auto *arg = | ||
args.getLastArg(clang::driver::options::OPT_finit_logical_EQ)) { | ||
llvm::StringRef argValue = llvm::StringRef(arg->getValue()); | ||
if (argValue.lower() == "true") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using StringRef::compare_insensitive
here. lower()
creates a new std::string which seems unnecessary.
else if (argValue.lower() == "false") | ||
invoc.loweringOpts.setLogicalInit(0); | ||
else { | ||
const unsigned diagID = diags.getCustomDiagID( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use an existing clang driver diagnostic here instead of creating custom id? For instance
diags.Report(clang::diag::err_drv_invalid_value_with_suggestion)
<< arg->getAsString(args) << arg->getValue() << "false true";
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No action required. But have you considered just generating an hlfir.assign
?
This PR adds the GNU gfortran compatible flag
-finit-logical
. It follows similar semantics as gfortran does