Skip to content

Conversation

NimishMishra
Copy link
Contributor

This PR adds support for -finit-local-zero. It follows the following semantics:

  1. Initialises local INTEGER, REAL, and COMPLEX variables to zero, LOGICAL variables to false, and CHARACTER variables to a string of null bytes.

  2. These options do not initialise: (1) objects with the POINTER attribute, (2) allocatable arrays, and (3) variables that appear in an EQUIVALENCE statement.

Fixes #157042

@NimishMishra NimishMishra marked this pull request as ready for review October 22, 2025 06:25
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' flang:driver flang Flang issues not falling into any other category flang:fir-hlfir labels Oct 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 22, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-flang-driver
@llvm/pr-subscribers-clang-driver

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

Author: None (NimishMishra)

Changes

This PR adds support for -finit-local-zero. It follows the following semantics:

  1. Initialises local INTEGER, REAL, and COMPLEX variables to zero, LOGICAL variables to false, and CHARACTER variables to a string of null bytes.

  2. These options do not initialise: (1) objects with the POINTER attribute, (2) allocatable arrays, and (3) variables that appear in an EQUIVALENCE statement.

Fixes #157042


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

7 Files Affected:

  • (modified) clang/include/clang/Driver/Options.td (+6-1)
  • (modified) clang/lib/Driver/ToolChains/Flang.cpp (+1-1)
  • (modified) flang/include/flang/Lower/LoweringOptions.def (+3)
  • (modified) flang/lib/Frontend/CompilerInvocation.cpp (+5)
  • (modified) flang/lib/Lower/Bridge.cpp (+204)
  • (added) flang/test/Driver/finit-local-zero.f90 (+8)
  • (added) flang/test/Lower/init-local-zero.f90 (+52)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7ae153deb9a55..321695306e3c1 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -7113,7 +7113,12 @@ defm dump_parse_tree : BooleanFFlag<"dump-parse-tree">, Group<gfortran_Group>;
 defm external_blas : BooleanFFlag<"external-blas">, Group<gfortran_Group>;
 defm f2c : BooleanFFlag<"f2c">, Group<gfortran_Group>;
 defm frontend_optimize : BooleanFFlag<"frontend-optimize">, Group<gfortran_Group>;
-defm init_local_zero : BooleanFFlag<"init-local-zero">, Group<gfortran_Group>;
+defm init_local_zero
+    : BooleanFFlag<"init-local-zero">,
+      Group<gfortran_Group>,
+      Visibility<[FlangOption, FC1Option]>,
+      HelpText<"Initialize real/integer/character/logical/complex type "
+               "to zero.">;
 defm integer_4_integer_8 : BooleanFFlag<"integer-4-integer-8">, Group<gfortran_Group>;
 defm max_identifier_length : BooleanFFlag<"max-identifier-length">, Group<gfortran_Group>;
 defm module_private : BooleanFFlag<"module-private">, Group<gfortran_Group>;
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index a56fa41c49d34..d6ea83800a6d8 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -225,7 +225,7 @@ void Flang::addCodegenOptions(const ArgList &Args,
        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_fno_repack_arrays, options::OPT_finit_local_zero,
        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 39f197d8d35c8..a7389ad62131a 100644
--- a/flang/include/flang/Lower/LoweringOptions.def
+++ b/flang/include/flang/Lower/LoweringOptions.def
@@ -79,5 +79,8 @@ ENUM_LOWERINGOPT(ComplexDivisionToRuntime, unsigned, 1, 1)
 /// of the lowering pipeline.
 ENUM_LOWERINGOPT(RegisterMLIRDiagnosticsHandler, unsigned, 1, 1)
 
+/// When true, it enables semantics for -finit-local-zero during codegen.
+ENUM_LOWERINGOPT(InitLocalZeroDef, unsigned, 1, 0)
+
 #undef LOWERINGOPT
 #undef ENUM_LOWERINGOPT
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 548ca675db5ea..fa4edb35e12eb 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1617,6 +1617,11 @@ bool CompilerInvocation::createFromArgs(
   else
     invoc.loweringOpts.setInitGlobalZero(false);
 
+  // -finit-local-zero
+  if (args.hasArg(clang::driver::options::OPT_finit_local_zero)) {
+    invoc.loweringOpts.setInitLocalZeroDef(1);
+  }
+
   // 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 3b711ccbe786a..87a53ce94181f 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -384,6 +384,159 @@ class TypeInfoConverter {
   llvm::SmallSetVector<Fortran::semantics::SymbolRef, 32> seen;
 };
 
+// Helper class to encapsulate utilities related to emission of implicit
+// assignments. `Implicit` here implies the assignment does not
+// exist in the Fortran source, but is implicit through definition
+// of one or more flagsets (like -finit-* family of flags).
+// General purpose usage of these utilities outside the
+// scope detailed here is discouraged, and is probably wrong.
+class ImplicitAssignmentGenerator {
+private:
+  Fortran::lower::LoweringBridge &bridge;
+  bool isInitLocalZeroFlagDefined;
+
+  /*
+   * Generates a parser::Variable for `sym` and fills
+   * in the correct source location for the designator.
+   */
+  Fortran::parser::Variable generateLHS(const Fortran::semantics::Symbol &sym) {
+    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)}};
+    return variable;
+  }
+
+  /*
+   * Integer, Real, and Complex types can be initialized through
+   * IntLiteralConstant. Further implicit casts will ensure
+   * type compatiblity. Default initialization to `0`.
+   */
+  Fortran::parser::Expr generateIntLiteralConstant(uint32_t init = 0) {
+    std::string val = std::to_string(init);
+    return Fortran::parser::Expr{
+        Fortran::parser::LiteralConstant{Fortran::parser::IntLiteralConstant{
+            Fortran::parser::CharBlock{val.c_str(), val.size()},
+            std::optional<Fortran::parser::KindParam>{}}}};
+  }
+
+  /*
+   * Logical types can be initialized with a LogicalLiteralConstant
+   * set to <true/false>. Defaults to `false`.
+   */
+  Fortran::parser::Expr generateLogicalLiteralConstant(bool init = false) {
+    return (init == false)
+               ? Fortran::parser::Expr{Fortran::parser::LiteralConstant{
+                     Fortran::parser::LogicalLiteralConstant{
+                         false, std::optional<Fortran::parser::KindParam>{}}}}
+               : Fortran::parser::Expr{Fortran::parser::LiteralConstant{
+                     Fortran::parser::LogicalLiteralConstant{
+                         true, std::optional<Fortran::parser::KindParam>{}}}};
+  }
+
+  /*
+   * Character types can be initialized with a FunctionReference
+   * to `achar(init)`. Defaults to `achar(0)`.
+   */
+  Fortran::parser::Expr
+  generateACharReference(Fortran::parser::CharBlock &currentPosition,
+                         const Fortran::semantics::Symbol &sym,
+                         std::string init = "0") {
+    // Construct a parser::Name for `achar`
+    std::string funcNameStr = "achar";
+    Fortran::parser::CharBlock funcCharBlock =
+        Fortran::parser::CharBlock{funcNameStr.c_str(), funcNameStr.size()};
+    Fortran::parser::Name funcName = Fortran::parser::Name{
+        Fortran::parser::CharBlock{funcNameStr.c_str(), funcNameStr.size()}};
+    Fortran::semantics::Scope &scope =
+        bridge.getSemanticsContext().FindScope(currentPosition);
+    Fortran::semantics::Symbol *funcSym = scope.FindSymbol(funcCharBlock);
+    if (funcSym) {
+      funcName.symbol = std::move(funcSym);
+    } else {
+      Fortran::semantics::Symbol &symbol =
+          bridge.getSemanticsContext()
+              .FindScope(currentPosition)
+              .MakeSymbol(
+                  funcCharBlock,
+                  Fortran::semantics::Attrs{Fortran::semantics::Attr::ELEMENTAL,
+                                            Fortran::semantics::Attr::INTRINSIC,
+                                            Fortran::semantics::Attr::PURE},
+                  Fortran::semantics::ProcEntityDetails{});
+      funcName.symbol = std::move(&symbol);
+    }
+
+    // Construct a RHS expression including a FunctionReference
+    // to `achar(init)`
+    Fortran::parser::Expr intExpr = Fortran::parser::Expr{
+        Fortran::parser::LiteralConstant{Fortran::parser::IntLiteralConstant{
+            Fortran::parser::CharBlock{init.c_str(), init.size()},
+            std::optional<Fortran::parser::KindParam>{}}}};
+    Fortran::common::Indirection<Fortran::parser::Expr> indirExpr{
+        std::move(intExpr)};
+    Fortran::parser::ActualArg actualArg{std::move(indirExpr)};
+
+    Fortran::parser::ActualArgSpec argSpec = Fortran::parser::ActualArgSpec{
+        std::make_tuple(std::nullopt, std::move(actualArg))};
+    std::list<Fortran::parser::ActualArgSpec> argSpecList;
+    argSpecList.push_back(std::move(argSpec));
+    Fortran::parser::ProcedureDesignator procDesignator =
+        Fortran::parser::ProcedureDesignator{std::move(funcName)};
+    Fortran::parser::Call call = Fortran::parser::Call{
+        std::make_tuple(std::move(procDesignator), std::move(argSpecList))};
+    Fortran::parser::FunctionReference funcRef =
+        Fortran::parser::FunctionReference{std::move(call)};
+    funcRef.source = Fortran::parser::FindSourceLocation(sym.name());
+    return Fortran::parser::Expr{std::move(funcRef)};
+  }
+
+  /*
+   * Utility to wrap the LHS variable `var` and RHS expression `expr` into
+   * an assignment.
+   */
+  inline std::unique_ptr<Fortran::parser::AssignmentStmt>
+  makeAssignment(Fortran::parser::Variable &var, Fortran::parser::Expr expr) {
+    Fortran::parser::AssignmentStmt stmt = Fortran::parser::AssignmentStmt{
+        std::make_tuple(std::move(var), std::move(expr))};
+    return std::make_unique<Fortran::parser::AssignmentStmt>(std::move(stmt));
+  }
+
+public:
+  ImplicitAssignmentGenerator(Fortran::lower::LoweringBridge &bridge,
+                              bool isInitLocalZeroFlagDefined)
+      : bridge(bridge), isInitLocalZeroFlagDefined(isInitLocalZeroFlagDefined) {
+  }
+
+  std::unique_ptr<Fortran::parser::AssignmentStmt>
+  emitAssignment(Fortran::parser::CharBlock &currentPosition,
+                 const Fortran::semantics::Symbol &sym) {
+    if (isInitLocalZeroFlagDefined) {
+      Fortran::parser::Variable var = generateLHS(sym);
+      const Fortran::semantics::DeclTypeSpec *declTy = sym.GetType();
+
+      if (declTy->IsNumeric(Fortran::semantics::TypeCategory::Integer) ||
+          declTy->IsNumeric(Fortran::semantics::TypeCategory::Real) ||
+          declTy->IsNumeric(Fortran::semantics::TypeCategory::Complex))
+        return makeAssignment(var, generateIntLiteralConstant());
+
+      else if (declTy->category() ==
+               Fortran::semantics::DeclTypeSpec::Category::Logical)
+        return makeAssignment(var, generateLogicalLiteralConstant());
+
+      else if (declTy->category() ==
+               Fortran::semantics::DeclTypeSpec::Category::Character)
+        return makeAssignment(var,
+                              generateACharReference(currentPosition, sym));
+    }
+
+    return nullptr;
+  }
+};
+
 using IncrementLoopNestInfo = llvm::SmallVector<IncrementLoopInfo, 8>;
 } // namespace
 
@@ -5877,6 +6030,57 @@ 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;
+    };
+
+    if (isEligibleForImplicitAssignment()) {
+      // Internal state of this class holds only the -finit-* flagsets. Hence
+      // can be reused for different symbols. Also minimizes the number of
+      // calls to `getLoweringOptions()`.
+      static ImplicitAssignmentGenerator implicitAssignmentGenerator{
+          bridge,
+          /*isInitLocalZeroFlagDefined=*/getLoweringOptions()
+                  .getInitLocalZeroDef() == 1};
+      std::unique_ptr<Fortran::parser::AssignmentStmt> stmt =
+          implicitAssignmentGenerator.emitAssignment(currentPosition,
+                                                     var.getSymbol());
+      if (stmt.get()) {
+        Fortran::evaluate::ExpressionAnalyzer ea{bridge.getSemanticsContext()};
+        const Fortran::evaluate::Assignment *assign = ea.Analyze(*stmt.get());
+        if (assign)
+          genAssignment(*assign);
+      }
+    }
+
     if (var.hasSymbol())
       genOpenMPSymbolProperties(*this, var);
   }
diff --git a/flang/test/Driver/finit-local-zero.f90 b/flang/test/Driver/finit-local-zero.f90
new file mode 100644
index 0000000000000..e24ea8ba2f1f0
--- /dev/null
+++ b/flang/test/Driver/finit-local-zero.f90
@@ -0,0 +1,8 @@
+! Check that the driver passes through -finit-global-zero:
+! RUN: %flang -### -S -finit-local-zero %s -o - 2>&1 | FileCheck %s
+      
+! Check that the compiler accepts -finit-local-zero:
+! RUN: %flang_fc1 -emit-hlfir -finit-local-zero %s -o -
+
+
+! CHECK: "-fc1"{{.*}}"-finit-local-zero"
diff --git a/flang/test/Lower/init-local-zero.f90 b/flang/test/Lower/init-local-zero.f90
new file mode 100644
index 0000000000000..2fcd0f874bfef
--- /dev/null
+++ b/flang/test/Lower/init-local-zero.f90
@@ -0,0 +1,52 @@
+! RUN: %flang_fc1 -emit-fir -finit-local-zero -o - %s | FileCheck %s
+
+!CHECK: %[[const:.*]] =  arith.constant 0 : i32
+!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFuninitialized_integerEx"}
+!CHECK: %[[X_DECL:.*]] = fir.declare %[[X]] {uniq_name = "_QFuninitialized_integerEx"} : (!fir.ref<i32>) -> !fir.ref<i32>
+!CHECK: fir.store %[[const]] to %[[X_DECL]] : !fir.ref<i32>
+subroutine uninitialized_integer
+  integer :: x
+end subroutine
+
+!CHECK: %[[const:.*]] =  arith.constant 0.000000e+00 : f32
+!CHECK: %[[X:.*]] = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFuninitialized_realEx"}
+!CHECK: %[[X_DECL:.*]] = fir.declare %[[X]] {uniq_name = "_QFuninitialized_realEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+!CHECK: fir.store %[[const]] to %[[X_DECL]] : !fir.ref<f32>
+subroutine uninitialized_real
+   real :: x
+end subroutine
+
+!CHECK: %false = arith.constant false
+!CHECK: %[[X:.*]] = fir.alloca !fir.logical<4> {bindc_name = "x", uniq_name = "_QFuninitialized_logicalEx"}
+!CHECK: %[[X_DECL:.*]] = fir.declare %[[X]] {uniq_name = "_QFuninitialized_logicalEx"} : (!fir.ref<!fir.logical<4>>) -> !fir.ref<!fir.logical<4>>
+!CHECK: %[[CVT:.*]] = fir.convert %false : (i1) -> !fir.logical<4>
+!CHECK: fir.store %[[CVT]] to %[[X_DECL]] : !fir.ref<!fir.logical<4>>
+subroutine uninitialized_logical
+   logical :: x
+end subroutine
+
+!CHECK: %[[const:.*]] =  arith.constant 0.000000e+00 : f32
+!CHECK: %[[X:.*]] = fir.alloca complex<f32> {bindc_name = "x", uniq_name = "_QFuninitialized_complexEx"}
+!CHECK: %[[X_DECL:.*]] = fir.declare %[[X]] {uniq_name = "_QFuninitialized_complexEx"} : (!fir.ref<complex<f32>>) -> !fir.ref<complex<f32>>
+!CHECK: %[[undef:.*]] = fir.undefined complex<f32>
+!CHECK: %[[REAL:.*]] = fir.insert_value %[[undef]], %[[const]], [0 : index] : (complex<f32>, f32) -> complex<f32>
+!CHECK: %[[COMPLEX:.*]] = fir.insert_value %[[REAL]], %[[const]], [1 : index] : (complex<f32>, f32) -> complex<f32>
+!CHECK: fir.store %[[COMPLEX]] to %[[X_DECL]] : !fir.ref<complex<f32>>
+subroutine uninitialized_complex
+   complex :: x
+end subroutine
+
+!CHECK: %[[X:.*]] = fir.alloca !fir.char<1> {bindc_name = "x", uniq_name = "_QFuninitialized_characterEx"}
+!CHECK: %[[X_DECL:.*]] = fir.declare %[[X]]  typeparams %c1 {uniq_name = "_QFuninitialized_characterEx"} : (!fir.ref<!fir.char<1>>, index) -> !fir.ref<!fir.char<1>>
+!CHECK: %[[ADDR:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1>>
+!CHECK: %[[FUNC_DECL:.*]] = fir.declare %[[ADDR]] {{.*}}
+!CHECK: %[[LOAD:.*]] = fir.load %[[FUNC_DECL]]
+!CHECK: fir.store %[[LOAD]] to %[[X_DECL]]
+subroutine uninitialized_character
+   character :: x
+end subroutine
+
+!CHECK: fir.global linkonce @{{.*}} constant : !fir.char<1> {
+!CHECK: %[[VAL:.*]] = fir.string_lit "\00"(1) : !fir.char<1>
+!CHECK: fir.has_value %[[VAL]] : !fir.char<1>
+!CHECK: }

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this feature!

Fortran::lower::AggregateStoreMap &storeMap) {
Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap);

/// Implicit assignment is defined by the `-finit-*` family of flags.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move the logic to where other cases of initializations is handled in instantiateLocal.
That way, it is a lot clearer that this code is not overriding any initializations.

// of one or more flagsets (like -finit-* family of flags).
// General purpose usage of these utilities outside the
// scope detailed here is discouraged, and is probably wrong.
class ImplicitAssignmentGenerator {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to create parser:: node to create the assignments?

You could simply work at the FIR level and generate hlfir.assign.

You can get the zero values using builder.createZeroValue for numerical and logical (using the element type from getFortranElementType).

For characters, you can should be able to use fir::factory::CharacterExprHelper::createSingletonFromCode()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. That could be done. Can you help me understand whether such changes will still enable us to do the following:

  1. Make calls like achar(...), which would be required when we upstream support for -finit-character
  2. Make calls like x = ieee_value(x, ieee_quiet_nan), which would be required when we support -finit-real (would fix Flang does not support the -finit-real flag #159794). We also need similar ieee_value calls for inf/nan/snan/-inf.

The reason I thought to handle assignments through parser:: is that I could not understand how we could directly emit such assignments as I exemplified here through HLFIR. Although I understand such calls are not needed for this PR, I intend to share functionality for all -finit-* flags. If there is a way where we can handle these cases in HLFIR, I would be happy to rework this PR.

Copy link
Contributor

@jeanPerier jeanPerier Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createSingletonFromCode is the implementation of achar in lowering, you can use that directly.

For ieee_value(x, ieee_quiet_nan), you can use fir::IntrinsicLibrary::genQNan defined here .

I expect you may want to support snan/inf/+inf, and while there may not be existing FIR level helper to get them, I pretty sure you can easily extract the implementation to get those from ieee_value implementation in IntrinsicCall.cpp (just like genQNan did).

how we could directly emit such assignments as I exemplified here through HLFIR

Why is hlfir.assign not covering your use case? It implements the Fortran intrinsic assignment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay thanks, I have a clearer idea now. Let me explore this and modify this PR.

Copy link
Contributor

@tarunprabhu tarunprabhu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have only reviewed the driver-related code and the associated test.

defm init_local_zero : BooleanFFlag<"init-local-zero">, Group<gfortran_Group>;
defm init_local_zero
: BooleanFFlag<"init-local-zero">,
Group<gfortran_Group>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that the gfortran_Group was intended for options that were supported in gfortran but not handled by flang. I don't think this is necessary any longer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the review. I am currently reworking the lowering portion of the PR; I will address these changes in the next revision of the PR.

Comment on lines +7120 to +7121
HelpText<"Initialize real/integer/character/logical/complex type "
"to zero.">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
HelpText<"Initialize real/integer/character/logical/complex type "
"to zero.">;
HelpText<"Initialize real, integer, character, logical and complex variables "
"to zero.">;

/// of the lowering pipeline.
ENUM_LOWERINGOPT(RegisterMLIRDiagnosticsHandler, unsigned, 1, 1)

/// When true, it enables semantics for -finit-local-zero during codegen.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:

Suggested change
/// When true, it enables semantics for -finit-local-zero during codegen.
/// When true, enables semantics for -finit-local-zero during codegen.

invoc.loweringOpts.setInitGlobalZero(false);

// -finit-local-zero
if (args.hasArg(clang::driver::options::OPT_finit_local_zero)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Braces are not necessary here.

@@ -0,0 +1,8 @@
! Check that the driver passes through -finit-global-zero:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
! Check that the driver passes through -finit-global-zero:
! Check that the driver passes through -finit-local-zero:

! Check that the compiler accepts -finit-local-zero:
! RUN: %flang_fc1 -emit-hlfir -finit-local-zero %s -o -


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could probably do without this empty line.

! RUN: %flang -### -S -finit-local-zero %s -o - 2>&1 | FileCheck %s

! Check that the compiler accepts -finit-local-zero:
! RUN: %flang_fc1 -emit-hlfir -finit-local-zero %s -o -
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider explicitly redirecting to /dev/null if you will not be checking the output. Since this uses -o -, my first thought on looking at it was that a pipe to FileCheck was missing.

Suggested change
! RUN: %flang_fc1 -emit-hlfir -finit-local-zero %s -o -
! RUN: %flang_fc1 -emit-hlfir -finit-local-zero %s -o /dev/null

@@ -0,0 +1,52 @@
! RUN: %flang_fc1 -emit-fir -finit-local-zero -o - %s | FileCheck %s

!CHECK: %[[const:.*]] = arith.constant 0 : i32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be consistent with the casing of pattern names. Screaming snake case is used almost exclusively in LLVM, and also in the rest of this test.

Suggested change
!CHECK: %[[const:.*]] = arith.constant 0 : i32
!CHECK: %[[ZERO:.*]] = arith.constant 0 : i32

!CHECK: %[[X:.*]] = fir.alloca complex<f32> {bindc_name = "x", uniq_name = "_QFuninitialized_complexEx"}
!CHECK: %[[X_DECL:.*]] = fir.declare %[[X]] {uniq_name = "_QFuninitialized_complexEx"} : (!fir.ref<complex<f32>>) -> !fir.ref<complex<f32>>
!CHECK: %[[undef:.*]] = fir.undefined complex<f32>
!CHECK: %[[REAL:.*]] = fir.insert_value %[[undef]], %[[const]], [0 : index] : (complex<f32>, f32) -> complex<f32>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: The name of this pattern is odd. The result is a complex, but is named real. Maybe C0 (or something else suggestive of a complex number) would be better.


!CHECK: %[[X:.*]] = fir.alloca !fir.char<1> {bindc_name = "x", uniq_name = "_QFuninitialized_characterEx"}
!CHECK: %[[X_DECL:.*]] = fir.declare %[[X]] typeparams %c1 {uniq_name = "_QFuninitialized_characterEx"} : (!fir.ref<!fir.char<1>>, index) -> !fir.ref<!fir.char<1>>
!CHECK: %[[ADDR:.*]] = fir.address_of(@{{.*}}) : !fir.ref<!fir.char<1>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to make it clear that one is taking the address of the global that is being matched starting on line 49. That would make it clear that the variable is being initialized to an empty string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category flang:driver flang:fir-hlfir flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flang does not support the -finit-local-zero flag

4 participants