https://github.com/NimishMishra updated https://github.com/llvm/llvm-project/pull/159788
>From 80000310c58c79c9081eb64e00c40c9e4d3ffe73 Mon Sep 17 00:00:00 2001 From: NimishMishra <[email protected]> Date: Tue, 21 Jul 2026 19:16:00 +0530 Subject: [PATCH 1/7] Address review comments --- clang/include/clang/Options/FlangOptions.td | 4 +- clang/lib/Driver/ToolChains/Flang.cpp | 2 +- flang/include/flang/Lower/LoweringOptions.def | 3 + flang/lib/Frontend/CompilerInvocation.cpp | 5 + flang/lib/Lower/ConvertVariable.cpp | 91 +++++++++++++++++++ flang/test/Driver/finit-local-zero.f90 | 8 ++ flang/test/Lower/init-local-zero.f90 | 66 ++++++++++++++ 7 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 flang/test/Driver/finit-local-zero.f90 create mode 100644 flang/test/Lower/init-local-zero.f90 diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td index bafc063663fe2..79cabe35e9406 100644 --- a/clang/include/clang/Options/FlangOptions.td +++ b/clang/include/clang/Options/FlangOptions.td @@ -59,7 +59,9 @@ 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, and complex variables " + "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 d900037230f20..34452206ed6db 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -263,7 +263,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 0b02ffd5a3b22..2b75d579c021e 100644 --- a/flang/include/flang/Lower/LoweringOptions.def +++ b/flang/include/flang/Lower/LoweringOptions.def @@ -93,5 +93,8 @@ ENUM_LOWERINGOPT(PreserveUseDebugInfo, unsigned, 1, 0) /// Portable, Extremum, ExtremeNum). Default: Legacy. ENUM_LOWERINGOPT(FPMaxminBehavior, Fortran::common::FPMaxminBehavior, 2, 0) +/// 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 79ad08353b64c..32f03215f3469 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -1684,6 +1684,11 @@ bool CompilerInvocation::createFromArgs( else invoc.loweringOpts.setInitGlobalZero(false); + // -finit-local-zero + if (args.hasArg(clang::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/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 007b536d97098..607f40e48e133 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -31,6 +31,7 @@ #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Builder/IntrinsicCall.h" +#include "flang/Optimizer/Builder/Runtime/Assign.h" #include "flang/Optimizer/Builder/Runtime/Derived.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/CUF/CUFOps.h" @@ -1225,6 +1226,54 @@ getSafeRepackAttrs(Fortran::lower::AbstractConverter &converter) { return attrs.empty() ? mlir::ArrayAttr{} : builder.getArrayAttr(attrs); } +// 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: + bool isInitLocalZeroFlagDefined; + +public: + ImplicitAssignmentGenerator(bool isInitLocalZeroFlagDefined) + : isInitLocalZeroFlagDefined(isInitLocalZeroFlagDefined) {} + + void emitAssignment(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, const Fortran::semantics::Symbol &sym, + Fortran::lower::SymMap &symMap) { + if (isInitLocalZeroFlagDefined) { + mlir::Type eleTy = hlfir::getFortranElementType(converter.genType(sym)); + auto *builder = &converter.getFirOpBuilder(); + + if (mlir::isa<fir::CharacterType>(eleTy)) { + fir::factory::CharacterExprHelper helper{*builder, loc}; + fir::CharacterType::KindTy kind = + helper.getCharacterType(eleTy).getFKind(); + mlir::Value zeroCode = + builder->createIntegerConstant(loc, builder->getI32Type(), 0); + mlir::Value zero = helper.createSingletonFromCode(zeroCode, kind); + hlfir::Entity lhs{symMap.lookupSymbol(sym).getAddr()}; + lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs); + mlir::Value rhsTmp = builder->createTemporary(loc, zero.getType()); + builder->create<fir::StoreOp>(loc, zero, rhsTmp); + builder->create<hlfir::AssignOp>(loc, rhsTmp, lhs); + } + + else if (fir::isa_integer(eleTy) || fir::isa_real(eleTy) || + fir::isa_complex(eleTy) || mlir::isa<fir::LogicalType>(eleTy)) { + mlir::Value zero = fir::factory::createZeroValue(*builder, loc, eleTy); + hlfir::Entity lhs{symMap.lookupSymbol(sym).getAddr()}; + lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs); + mlir::Value rhsTmp = builder->createTemporary(loc, zero.getType()); + builder->create<fir::StoreOp>(loc, zero, rhsTmp); + builder->create<hlfir::AssignOp>(loc, rhsTmp, lhs); + } + } + } +}; + /// Instantiate a local variable. Precondition: Each variable will be visited /// such that if its properties depend on other variables, the variables upon /// which its properties depend will already have been visited. @@ -1317,6 +1366,48 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter, Fortran::lower::genUnpackArray(*converterPtr, loc, *varDef, *sym); }); } + + /// 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{ + /*isInitLocalZeroFlagDefined=*/converter.getLoweringOptions() + .getInitLocalZeroDef() == 1}; + + implicitAssignmentGenerator.emitAssignment( + converter, converter.getCurrentLocation(), var.getSymbol(), symMap); + } } //===----------------------------------------------------------------===// diff --git a/flang/test/Driver/finit-local-zero.f90 b/flang/test/Driver/finit-local-zero.f90 new file mode 100644 index 0000000000000..7dd2612e624ad --- /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..61a4d70ad788d --- /dev/null +++ b/flang/test/Lower/init-local-zero.f90 @@ -0,0 +1,66 @@ +! RUN: %flang_fc1 -emit-hlfir -finit-local-zero -o - %s | FileCheck %s + + +!CHECK-LABEL: func.func @_QPuninitialized_integer() { +!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca i32 +!CHECK: %[[X_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFuninitialized_integerEx"} +!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_integerEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) +!CHECK: %[[ZERO:.*]] = arith.constant 0 : i32 +!CHECK: fir.store %[[ZERO]] to %[[ZERO_ALLOCA]] : !fir.ref<i32> +!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<i32>, !fir.ref<i32> +subroutine uninitialized_integer + integer :: x +end subroutine + +!CHECK-LABEL: func.func @_QPuninitialized_real() { +!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca f32 +!CHECK: %[[X_ALLOCA:.*]] = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFuninitialized_realEx"} +!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_realEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>) +!CHECK: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32 +!CHECK: fir.store %[[ZERO]] to %[[ZERO_ALLOCA]] : !fir.ref<f32> +!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<f32>, !fir.ref<f32> +subroutine uninitialized_real + real :: x +end subroutine + +!CHECK-LABEL: func.func @_QPuninitialized_logical() { +!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca !fir.logical<4> +!CHECK: %[[X_ALLOCA:.*]] = fir.alloca !fir.logical<4> {bindc_name = "x", uniq_name = "_QFuninitialized_logicalEx"} +!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_logicalEx"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>) +!CHECK: %false = arith.constant false +!CHECK: %[[CVT:.*]] = fir.convert %false : (i1) -> !fir.logical<4> +!CHECK: fir.store %[[CVT]] to %[[ZERO_ALLOCA]] : !fir.ref<!fir.logical<4>> +!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>> +subroutine uninitialized_logical + logical :: x +end subroutine + + +!CHECK-LABEL: func.func @_QPuninitialized_complex() { +!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca complex<f32> +!CHECK: %[[X_ALLOCA:.*]] = fir.alloca complex<f32> {bindc_name = "x", uniq_name = "_QFuninitialized_complexEx"} +!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_complexEx"} : (!fir.ref<complex<f32>>) -> (!fir.ref<complex<f32>>, !fir.ref<complex<f32>>) +!CHECK: %[[CONST:.*]] = arith.constant 0.000000e+00 : f32 +!CHECK: %[[UNDEF:.*]] = fir.undefined complex<f32> +!CHECK: %[[IDX0:.*]] = fir.insert_value %[[UNDEF]], %[[CONST]], [0 : index] : (complex<f32>, f32) -> complex<f32> +!CHECK: %[[IDX1:.*]] = fir.insert_value %[[IDX0]], %[[CONST]], [1 : index] : (complex<f32>, f32) -> complex<f32> +!CHECK: fir.store %[[IDX1]] to %[[ZERO_ALLOCA]] : !fir.ref<complex<f32>> +!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<complex<f32>>, !fir.ref<complex<f32>> +subroutine uninitialized_complex + complex :: x +end subroutine + +!CHECK-LABEL: func.func @_QPuninitialized_character() { +!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca !fir.char<1> +!CHECK: %[[ONE:.*]] = arith.constant 1 : index +!CHECK: %[[X_ALLOCA:.*]] = fir.alloca !fir.char<1> {bindc_name = "x", uniq_name = "_QFuninitialized_characterEx"} +!CHECK: %3:2 = hlfir.declare %[[X_ALLOCA]] typeparams %[[ONE]] {uniq_name = "_QFuninitialized_characterEx"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>) +!CHECK: %[[CONST:.*]] = arith.constant 0 : i32 +!CHECK: %[[CVT:.*]] = fir.convert %[[CONST]] : (i32) -> i8 +!CHECK: %[[UNDEF:.*]] = fir.undefined !fir.char<1> +!CHECK: %[[VAL:.*]] = fir.insert_value %[[UNDEF]], %[[CVT]], [0 : index] : (!fir.char<1>, i8) -> !fir.char<1> +!CHECK: fir.store %[[VAL]] to %[[ZERO_ALLOCA]] : !fir.ref<!fir.char<1>> +!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>> +subroutine uninitialized_character + character :: x +end subroutine >From a5f6b3cde11ec8ee5c1ae53b7629f91b784ceede Mon Sep 17 00:00:00 2001 From: NimishMishra <[email protected]> Date: Tue, 21 Jul 2026 19:19:51 +0530 Subject: [PATCH 2/7] fix test --- flang/test/Driver/finit-local-zero.f90 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/flang/test/Driver/finit-local-zero.f90 b/flang/test/Driver/finit-local-zero.f90 index 7dd2612e624ad..8cfadc9372edc 100644 --- a/flang/test/Driver/finit-local-zero.f90 +++ b/flang/test/Driver/finit-local-zero.f90 @@ -1,8 +1,7 @@ -! Check that the driver passes through -finit-global-zero: +! Check that the driver passes through -finit-local-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 - - +! RUN: %flang_fc1 -emit-hlfir -finit-local-zero %s -o /dev/null ! CHECK: "-fc1"{{.*}}"-finit-local-zero" >From 1ad6500f8025ebcb4109469a38f95a83537ce0a5 Mon Sep 17 00:00:00 2001 From: NimishMishra <[email protected]> Date: Tue, 21 Jul 2026 19:28:04 +0530 Subject: [PATCH 3/7] Update LoweringOptions.def --- flang/include/flang/Lower/LoweringOptions.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def index 2b75d579c021e..3155cf7878608 100644 --- a/flang/include/flang/Lower/LoweringOptions.def +++ b/flang/include/flang/Lower/LoweringOptions.def @@ -93,7 +93,7 @@ ENUM_LOWERINGOPT(PreserveUseDebugInfo, unsigned, 1, 0) /// Portable, Extremum, ExtremeNum). Default: Legacy. ENUM_LOWERINGOPT(FPMaxminBehavior, Fortran::common::FPMaxminBehavior, 2, 0) -/// When true, it enables semantics for -finit-local-zero during codegen. +/// When true, enables semantics for -finit-local-zero during codegen. ENUM_LOWERINGOPT(InitLocalZeroDef, unsigned, 1, 0) #undef LOWERINGOPT >From 02e4431915267f05fa6b988d10a3c05c20503f0d Mon Sep 17 00:00:00 2001 From: NimishMishra <[email protected]> Date: Tue, 21 Jul 2026 19:29:30 +0530 Subject: [PATCH 4/7] Update CompilerInvocation.cpp --- flang/lib/Frontend/CompilerInvocation.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 32f03215f3469..903818824a266 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -1685,9 +1685,8 @@ bool CompilerInvocation::createFromArgs( invoc.loweringOpts.setInitGlobalZero(false); // -finit-local-zero - if (args.hasArg(clang::options::OPT_finit_local_zero)) { + if (args.hasArg(clang::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 >From ec112fef380534224585cdb88d1fb9d230960e69 Mon Sep 17 00:00:00 2001 From: NimishMishra <[email protected]> Date: Sun, 26 Jul 2026 18:33:53 +0530 Subject: [PATCH 5/7] Address review comments --- flang/lib/Lower/ConvertVariable.cpp | 115 ++++++++++++++----------- flang/test/Driver/finit-local-zero.f90 | 4 +- flang/test/Lower/init-local-zero.f90 | 45 +++++----- 3 files changed, 93 insertions(+), 71 deletions(-) diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 607f40e48e133..8278340f3b7d2 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -1226,53 +1226,68 @@ getSafeRepackAttrs(Fortran::lower::AbstractConverter &converter) { return attrs.empty() ? mlir::ArrayAttr{} : builder.getArrayAttr(attrs); } -// Helper class to encapsulate utilities related to emission of implicit +// Helper function to 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 +// General purpose usage of this function outside the // scope detailed here is discouraged, and is probably wrong. -class ImplicitAssignmentGenerator { -private: - bool isInitLocalZeroFlagDefined; - -public: - ImplicitAssignmentGenerator(bool isInitLocalZeroFlagDefined) - : isInitLocalZeroFlagDefined(isInitLocalZeroFlagDefined) {} - - void emitAssignment(Fortran::lower::AbstractConverter &converter, - mlir::Location loc, const Fortran::semantics::Symbol &sym, - Fortran::lower::SymMap &symMap) { - if (isInitLocalZeroFlagDefined) { - mlir::Type eleTy = hlfir::getFortranElementType(converter.genType(sym)); - auto *builder = &converter.getFirOpBuilder(); - - if (mlir::isa<fir::CharacterType>(eleTy)) { - fir::factory::CharacterExprHelper helper{*builder, loc}; - fir::CharacterType::KindTy kind = - helper.getCharacterType(eleTy).getFKind(); - mlir::Value zeroCode = - builder->createIntegerConstant(loc, builder->getI32Type(), 0); - mlir::Value zero = helper.createSingletonFromCode(zeroCode, kind); - hlfir::Entity lhs{symMap.lookupSymbol(sym).getAddr()}; - lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs); - mlir::Value rhsTmp = builder->createTemporary(loc, zero.getType()); - builder->create<fir::StoreOp>(loc, zero, rhsTmp); - builder->create<hlfir::AssignOp>(loc, rhsTmp, lhs); - } +static void emitImplicitAssignment(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, + const Fortran::semantics::Symbol &sym, + Fortran::lower::SymMap &symMap) { + if (converter.getLoweringOptions().getInitLocalZeroDef()) { + mlir::Type eleTy = hlfir::getFortranElementType(converter.genType(sym)); + auto *builder = &converter.getFirOpBuilder(); + + if (mlir::isa<fir::CharacterType>(eleTy)) { + fir::ExtendedValue ext = converter.getSymbolExtendedValue(sym); + const auto *charBox = ext.getCharBox(); + mlir::Value buffer = charBox->getBuffer(); + assert(buffer && "CharBox buffer is null"); + auto eleTy = fir::unwrapRefType(buffer.getType()); + auto charTy = + mlir::cast<fir::CharacterType>(fir::unwrapSequenceType(eleTy)); + unsigned kindBytes = + builder->getKindMap().getCharacterBitsize(charTy.getFKind()) / 8; + auto lenVal = charBox->getLen(); + mlir::Value byteLen; + if (lenVal) { + + mlir::Value lenI64 = + builder->createConvert(loc, builder->getI64Type(), lenVal); + mlir::Value kind = builder->createIntegerConstant( + loc, builder->getI64Type(), kindBytes); + byteLen = mlir::arith::MulIOp::create(*builder, loc, lenI64, kind); + byteLen = builder->createConvert(loc, builder->getI64Type(), byteLen); + } else { - else if (fir::isa_integer(eleTy) || fir::isa_real(eleTy) || - fir::isa_complex(eleTy) || mlir::isa<fir::LogicalType>(eleTy)) { - mlir::Value zero = fir::factory::createZeroValue(*builder, loc, eleTy); - hlfir::Entity lhs{symMap.lookupSymbol(sym).getAddr()}; - lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs); - mlir::Value rhsTmp = builder->createTemporary(loc, zero.getType()); - builder->create<fir::StoreOp>(loc, zero, rhsTmp); - builder->create<hlfir::AssignOp>(loc, rhsTmp, lhs); + assert(charTy.hasConstantLen() && "expected constant character length"); + byteLen = builder->createIntegerConstant(loc, builder->getI64Type(), + charTy.getLen() * kindBytes); } + + auto ptrTy = mlir::LLVM::LLVMPointerType::get(builder->getContext()); + mlir::Value ptr = builder->createConvert(loc, ptrTy, buffer); + mlir::Value zero = + builder->createIntegerConstant(loc, builder->getI8Type(), 0); + mlir::ModuleOp mod = builder->getModule(); + mlir::OpBuilder modBuilder(mod.getBodyRegion()); + modBuilder.setInsertionPointToEnd(zero.getParentBlock()); + mlir::LLVM::MemsetOp::create( + modBuilder, loc, ptr, zero, byteLen, + fir::isa_volatile_type(converter.genType(sym))); + } + + else if (fir::isa_integer(eleTy) || fir::isa_real(eleTy) || + fir::isa_complex(eleTy) || mlir::isa<fir::LogicalType>(eleTy)) { + mlir::Value zero = fir::factory::createZeroValue(*builder, loc, eleTy); + hlfir::Entity lhs{symMap.lookupSymbol(sym).getAddr()}; + lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs); + builder->create<hlfir::AssignOp>(loc, zero, lhs); } } -}; +} /// Instantiate a local variable. Precondition: Each variable will be visited /// such that if its properties depend on other variables, the variables upon @@ -1373,11 +1388,13 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter, /// 3) allocatable arrays /// 4) variables that appear in an EQUIVALENCE statement - auto isEligibleForImplicitAssignment = [&var]() -> bool { + auto isEligibleForImplicitAssignment = [&var, &converter]() -> bool { if (!var.hasSymbol()) return false; const Fortran::semantics::Symbol &sym = var.getSymbol(); + if (!sym.GetType()) + return false; if (const auto *details = sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) { if (details->init()) @@ -1394,19 +1411,19 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter, if (Fortran::lower::pft::getDependentVariableList(sym).size() > 1) return false; + if (auto ty = converter.genType(sym)) { + auto charTy = + mlir::dyn_cast<fir::CharacterType>(hlfir::getFortranElementType(ty)); + if (charTy && !charTy.hasConstantLen()) + 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{ - /*isInitLocalZeroFlagDefined=*/converter.getLoweringOptions() - .getInitLocalZeroDef() == 1}; - - implicitAssignmentGenerator.emitAssignment( - converter, converter.getCurrentLocation(), var.getSymbol(), symMap); + emitImplicitAssignment(converter, converter.getCurrentLocation(), + var.getSymbol(), symMap); } } diff --git a/flang/test/Driver/finit-local-zero.f90 b/flang/test/Driver/finit-local-zero.f90 index 8cfadc9372edc..b69fe60ba1e70 100644 --- a/flang/test/Driver/finit-local-zero.f90 +++ b/flang/test/Driver/finit-local-zero.f90 @@ -1,7 +1,9 @@ ! Check that the driver passes through -finit-local-zero: ! RUN: %flang -### -S -finit-local-zero %s -o - 2>&1 | FileCheck %s +! RUN: %flang -### -S %s -o - 2>&1 | FileCheck %s --check-prefixes=NO-INIT ! Check that the compiler accepts -finit-local-zero: -! RUN: %flang_fc1 -emit-hlfir -finit-local-zero %s -o /dev/null +! RUN: %flang_fc1 -finit-local-zero %s -o /dev/null ! CHECK: "-fc1"{{.*}}"-finit-local-zero" +! NO-INIT-NOT: -finit-local-zero diff --git a/flang/test/Lower/init-local-zero.f90 b/flang/test/Lower/init-local-zero.f90 index 61a4d70ad788d..2ed8ca2f615dd 100644 --- a/flang/test/Lower/init-local-zero.f90 +++ b/flang/test/Lower/init-local-zero.f90 @@ -1,66 +1,69 @@ ! RUN: %flang_fc1 -emit-hlfir -finit-local-zero -o - %s | FileCheck %s - !CHECK-LABEL: func.func @_QPuninitialized_integer() { -!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca i32 !CHECK: %[[X_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFuninitialized_integerEx"} !CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_integerEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>) !CHECK: %[[ZERO:.*]] = arith.constant 0 : i32 -!CHECK: fir.store %[[ZERO]] to %[[ZERO_ALLOCA]] : !fir.ref<i32> -!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<i32>, !fir.ref<i32> +!CHECK: hlfir.assign %[[ZERO]] to %[[X]]#0 : i32, !fir.ref<i32> subroutine uninitialized_integer integer :: x end subroutine !CHECK-LABEL: func.func @_QPuninitialized_real() { -!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca f32 !CHECK: %[[X_ALLOCA:.*]] = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFuninitialized_realEx"} !CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_realEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>) !CHECK: %[[ZERO:.*]] = arith.constant 0.000000e+00 : f32 -!CHECK: fir.store %[[ZERO]] to %[[ZERO_ALLOCA]] : !fir.ref<f32> -!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<f32>, !fir.ref<f32> +!CHECK: hlfir.assign %[[ZERO]] to %[[X]]#0 : f32, !fir.ref<f32> subroutine uninitialized_real real :: x end subroutine !CHECK-LABEL: func.func @_QPuninitialized_logical() { -!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca !fir.logical<4> !CHECK: %[[X_ALLOCA:.*]] = fir.alloca !fir.logical<4> {bindc_name = "x", uniq_name = "_QFuninitialized_logicalEx"} !CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_logicalEx"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>) !CHECK: %false = arith.constant false !CHECK: %[[CVT:.*]] = fir.convert %false : (i1) -> !fir.logical<4> -!CHECK: fir.store %[[CVT]] to %[[ZERO_ALLOCA]] : !fir.ref<!fir.logical<4>> -!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>> +!CHECK: hlfir.assign %[[CVT]] to %[[X]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>> subroutine uninitialized_logical logical :: x end subroutine !CHECK-LABEL: func.func @_QPuninitialized_complex() { -!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca complex<f32> !CHECK: %[[X_ALLOCA:.*]] = fir.alloca complex<f32> {bindc_name = "x", uniq_name = "_QFuninitialized_complexEx"} !CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {uniq_name = "_QFuninitialized_complexEx"} : (!fir.ref<complex<f32>>) -> (!fir.ref<complex<f32>>, !fir.ref<complex<f32>>) !CHECK: %[[CONST:.*]] = arith.constant 0.000000e+00 : f32 !CHECK: %[[UNDEF:.*]] = fir.undefined complex<f32> !CHECK: %[[IDX0:.*]] = fir.insert_value %[[UNDEF]], %[[CONST]], [0 : index] : (complex<f32>, f32) -> complex<f32> !CHECK: %[[IDX1:.*]] = fir.insert_value %[[IDX0]], %[[CONST]], [1 : index] : (complex<f32>, f32) -> complex<f32> -!CHECK: fir.store %[[IDX1]] to %[[ZERO_ALLOCA]] : !fir.ref<complex<f32>> -!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<complex<f32>>, !fir.ref<complex<f32>> +!CHECK: hlfir.assign %[[IDX1]] to %[[X]]#0 : complex<f32>, !fir.ref<complex<f32>> subroutine uninitialized_complex complex :: x end subroutine !CHECK-LABEL: func.func @_QPuninitialized_character() { -!CHECK: %[[ZERO_ALLOCA:.*]] = fir.alloca !fir.char<1> !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[X_ALLOCA:.*]] = fir.alloca !fir.char<1> {bindc_name = "x", uniq_name = "_QFuninitialized_characterEx"} -!CHECK: %3:2 = hlfir.declare %[[X_ALLOCA]] typeparams %[[ONE]] {uniq_name = "_QFuninitialized_characterEx"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>) -!CHECK: %[[CONST:.*]] = arith.constant 0 : i32 -!CHECK: %[[CVT:.*]] = fir.convert %[[CONST]] : (i32) -> i8 -!CHECK: %[[UNDEF:.*]] = fir.undefined !fir.char<1> -!CHECK: %[[VAL:.*]] = fir.insert_value %[[UNDEF]], %[[CVT]], [0 : index] : (!fir.char<1>, i8) -> !fir.char<1> -!CHECK: fir.store %[[VAL]] to %[[ZERO_ALLOCA]] : !fir.ref<!fir.char<1>> -!CHECK: hlfir.assign %[[ZERO_ALLOCA]] to %[[X]]#0 : !fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>> +!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] typeparams %[[ONE]] {uniq_name = "_QFuninitialized_characterEx"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>) +!CHECK: %[[CVT:.*]] = fir.convert %[[ONE]] : (index) -> i64 +!CHECK: %[[CONST:.*]] = arith.constant 1 : i64 +!CHECK: %[[COUNT:.*]] = arith.muli %[[CVT]], %[[CONST]] : i64 +!CHECK: %[[CVT:.*]] = fir.convert %[[X]]#0 : (!fir.ref<!fir.char<1>>) -> !llvm.ptr +!CHECK: %[[ZERO:.*]] = arith.constant 0 : i8 +!CHECK: "llvm.intr.memset"(%[[CVT]], %[[ZERO]], %[[COUNT]]) <{isVolatile = false}> : (!llvm.ptr, i8, i64) -> () subroutine uninitialized_character character :: x end subroutine + +!CHECK: %[[X_ALLOCA:.*]] = fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "x", uniq_name = "_QFallocatable_scalarEx"} +!CHECK: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap<i32> +!CHECK: %[[EMBOX:.*]] = fir.embox %[[ZERO_BITS]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>> +!CHECK: fir.store %[[EMBOX]] to %[[X_ALLOCA]] : !fir.ref<!fir.box<!fir.heap<i32>>> +!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFallocatable_scalarEx"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>) +!CHECK: %[[ZERO:.*]] = arith.constant 0 : i32 +!CHECK: %[[LOAD:.*]] = fir.load %[[X]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>> +!CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32> +!CHECK: hlfir.assign %[[ZERO]] to %[[ADDR]] : i32, !fir.heap<i32> +subroutine allocatable_scalar + integer, allocatable :: x +end subroutine >From 0227f5e2f61e0688b81221354a29fcfbd0dc3822 Mon Sep 17 00:00:00 2001 From: NimishMishra <[email protected]> Date: Sun, 26 Jul 2026 18:35:00 +0530 Subject: [PATCH 6/7] Do not run the entire pipeline for the test --- flang/test/Driver/finit-local-zero.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flang/test/Driver/finit-local-zero.f90 b/flang/test/Driver/finit-local-zero.f90 index b69fe60ba1e70..2de41e4df34f8 100644 --- a/flang/test/Driver/finit-local-zero.f90 +++ b/flang/test/Driver/finit-local-zero.f90 @@ -3,7 +3,7 @@ ! RUN: %flang -### -S %s -o - 2>&1 | FileCheck %s --check-prefixes=NO-INIT ! Check that the compiler accepts -finit-local-zero: -! RUN: %flang_fc1 -finit-local-zero %s -o /dev/null +! RUN: %flang_fc1 -fsyntax-only -finit-local-zero %s -o /dev/null ! CHECK: "-fc1"{{.*}}"-finit-local-zero" ! NO-INIT-NOT: -finit-local-zero >From 00729b38755169cbf58e11a4293a326c85033a5d Mon Sep 17 00:00:00 2001 From: NimishMishra <[email protected]> Date: Mon, 3 Aug 2026 14:55:11 +0530 Subject: [PATCH 7/7] Address review comments --- .../flang/Optimizer/Builder/Character.h | 10 ++ flang/lib/Lower/ConvertVariable.cpp | 99 +++++-------------- flang/lib/Optimizer/Builder/Character.cpp | 31 ++++++ flang/test/Lower/init-local-zero.f90 | 15 +-- 4 files changed, 69 insertions(+), 86 deletions(-) diff --git a/flang/include/flang/Optimizer/Builder/Character.h b/flang/include/flang/Optimizer/Builder/Character.h index 658118eddcc90..f68c57852e6ec 100644 --- a/flang/include/flang/Optimizer/Builder/Character.h +++ b/flang/include/flang/Optimizer/Builder/Character.h @@ -13,9 +13,12 @@ #ifndef FORTRAN_OPTIMIZER_BUILDER_CHARACTER_H #define FORTRAN_OPTIMIZER_BUILDER_CHARACTER_H +#include "flang/Lower/AbstractConverter.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/LowLevelIntrinsics.h" #include "flang/Optimizer/Builder/Runtime/Character.h" +#include "flang/Semantics/symbol.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" namespace fir { class FirOpBuilder; @@ -240,6 +243,13 @@ fir::CharBoxValue convertCharacterKind(fir::FirOpBuilder &builder, fir::CharBoxValue srcBoxChar, int toKind); +/// Given a symbol `sym` and a mlir::Value `val`, emit a memset to +/// set `sym` to the value `val`. +mlir::LLVM::MemsetOp emitMemset(fir::FirOpBuilder &builder, mlir::Location loc, + Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::Symbol &sym, + mlir::Value val); + } // namespace fir::factory #endif // FORTRAN_OPTIMIZER_BUILDER_CHARACTER_H diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 8278340f3b7d2..69f9b69710c1f 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -1232,60 +1232,24 @@ getSafeRepackAttrs(Fortran::lower::AbstractConverter &converter) { // of one or more flagsets (like -finit-* family of flags). // General purpose usage of this function outside the // scope detailed here is discouraged, and is probably wrong. -static void emitImplicitAssignment(Fortran::lower::AbstractConverter &converter, - mlir::Location loc, - const Fortran::semantics::Symbol &sym, - Fortran::lower::SymMap &symMap) { - if (converter.getLoweringOptions().getInitLocalZeroDef()) { - mlir::Type eleTy = hlfir::getFortranElementType(converter.genType(sym)); - auto *builder = &converter.getFirOpBuilder(); - - if (mlir::isa<fir::CharacterType>(eleTy)) { - fir::ExtendedValue ext = converter.getSymbolExtendedValue(sym); - const auto *charBox = ext.getCharBox(); - mlir::Value buffer = charBox->getBuffer(); - assert(buffer && "CharBox buffer is null"); - auto eleTy = fir::unwrapRefType(buffer.getType()); - auto charTy = - mlir::cast<fir::CharacterType>(fir::unwrapSequenceType(eleTy)); - unsigned kindBytes = - builder->getKindMap().getCharacterBitsize(charTy.getFKind()) / 8; - auto lenVal = charBox->getLen(); - mlir::Value byteLen; - if (lenVal) { - - mlir::Value lenI64 = - builder->createConvert(loc, builder->getI64Type(), lenVal); - mlir::Value kind = builder->createIntegerConstant( - loc, builder->getI64Type(), kindBytes); - byteLen = mlir::arith::MulIOp::create(*builder, loc, lenI64, kind); - byteLen = builder->createConvert(loc, builder->getI64Type(), byteLen); - } else { - - assert(charTy.hasConstantLen() && "expected constant character length"); - byteLen = builder->createIntegerConstant(loc, builder->getI64Type(), - charTy.getLen() * kindBytes); - } - - auto ptrTy = mlir::LLVM::LLVMPointerType::get(builder->getContext()); - mlir::Value ptr = builder->createConvert(loc, ptrTy, buffer); - mlir::Value zero = - builder->createIntegerConstant(loc, builder->getI8Type(), 0); - mlir::ModuleOp mod = builder->getModule(); - mlir::OpBuilder modBuilder(mod.getBodyRegion()); - modBuilder.setInsertionPointToEnd(zero.getParentBlock()); - mlir::LLVM::MemsetOp::create( - modBuilder, loc, ptr, zero, byteLen, - fir::isa_volatile_type(converter.genType(sym))); - } +static void emitForcedAssignment(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, + const Fortran::semantics::Symbol &sym, + Fortran::lower::SymMap &symMap) { + mlir::Type eleTy = hlfir::getFortranElementType(converter.genType(sym)); + auto *builder = &converter.getFirOpBuilder(); + if (mlir::isa<fir::CharacterType>(eleTy)) { + mlir::Value zero = + builder->createIntegerConstant(loc, builder->getI8Type(), 0); + fir::factory::emitMemset(*builder, loc, converter, sym, zero); + } - else if (fir::isa_integer(eleTy) || fir::isa_real(eleTy) || - fir::isa_complex(eleTy) || mlir::isa<fir::LogicalType>(eleTy)) { - mlir::Value zero = fir::factory::createZeroValue(*builder, loc, eleTy); - hlfir::Entity lhs{symMap.lookupSymbol(sym).getAddr()}; - lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs); - builder->create<hlfir::AssignOp>(loc, zero, lhs); - } + else if (fir::isa_integer(eleTy) || fir::isa_real(eleTy) || + fir::isa_complex(eleTy) || mlir::isa<fir::LogicalType>(eleTy)) { + mlir::Value zero = fir::factory::createZeroValue(*builder, loc, eleTy); + hlfir::Entity lhs{symMap.lookupSymbol(sym).getAddr()}; + lhs = hlfir::derefPointersAndAllocatables(loc, *builder, lhs); + hlfir::AssignOp::create(*builder, loc, zero, lhs); } } @@ -1388,42 +1352,33 @@ static void instantiateLocal(Fortran::lower::AbstractConverter &converter, /// 3) allocatable arrays /// 4) variables that appear in an EQUIVALENCE statement - auto isEligibleForImplicitAssignment = [&var, &converter]() -> bool { + auto isEligibleForForcedAssignment = [&var, &converter]() -> bool { if (!var.hasSymbol()) return false; const Fortran::semantics::Symbol &sym = var.getSymbol(); if (!sym.GetType()) return false; - if (const auto *details = - sym.detailsIf<Fortran::semantics::ObjectEntityDetails>()) { - if (details->init()) - return false; - } - if (sym.attrs().test(Fortran::semantics::Attr::POINTER)) + if (var.isGlobal() || Fortran::semantics::IsDummy(sym)) return false; - if (sym.Rank() > 0 && - sym.attrs().test(Fortran::semantics::Attr::ALLOCATABLE)) + if (sym.attrs().test(Fortran::semantics::Attr::POINTER)) return false; - if (Fortran::lower::pft::getDependentVariableList(sym).size() > 1) + if (sym.attrs().test(Fortran::semantics::Attr::ALLOCATABLE)) return false; - if (auto ty = converter.genType(sym)) { - auto charTy = - mlir::dyn_cast<fir::CharacterType>(hlfir::getFortranElementType(ty)); - if (charTy && !charTy.hasConstantLen()) - return false; - } + if (Fortran::semantics::FindEquivalenceSet(sym) != nullptr) + return false; return true; }; - if (isEligibleForImplicitAssignment()) { - emitImplicitAssignment(converter, converter.getCurrentLocation(), - var.getSymbol(), symMap); + if (converter.getLoweringOptions().getInitLocalZeroDef() && + isEligibleForForcedAssignment()) { + emitForcedAssignment(converter, converter.getCurrentLocation(), + var.getSymbol(), symMap); } } diff --git a/flang/lib/Optimizer/Builder/Character.cpp b/flang/lib/Optimizer/Builder/Character.cpp index 155bc0fbd19ce..bed34fd0a3431 100644 --- a/flang/lib/Optimizer/Builder/Character.cpp +++ b/flang/lib/Optimizer/Builder/Character.cpp @@ -897,3 +897,34 @@ fir::factory::convertCharacterKind(fir::FirOpBuilder &builder, dest); return fir::CharBoxValue{dest, srcBoxChar.getLen()}; } + +mlir::LLVM::MemsetOp +fir::factory::emitMemset(fir::FirOpBuilder &builder, mlir::Location loc, + Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::Symbol &sym, + mlir::Value val) { + fir::ExtendedValue ext = converter.getSymbolExtendedValue(sym); + const auto *charBox = ext.getCharBox(); + mlir::Value buffer = charBox->getBuffer(); + assert(buffer && "CharBox buffer is null"); + auto eleTy = fir::unwrapRefType(buffer.getType()); + auto charTy = mlir::cast<fir::CharacterType>(fir::unwrapSequenceType(eleTy)); + unsigned kindBytes = + builder.getKindMap().getCharacterBitsize(charTy.getFKind()) / 8; + auto lenVal = charBox->getLen(); + mlir::Value lenI64 = builder.createConvert(loc, builder.getI64Type(), lenVal); + mlir::Value kind = + builder.createIntegerConstant(loc, builder.getI64Type(), kindBytes); + auto mulOp = mlir::arith::MulIOp::create(builder, loc, lenI64, kind); + auto byteLen = builder.createConvert(loc, builder.getI64Type(), mulOp); + + auto ptrTy = mlir::LLVM::LLVMPointerType::get(builder.getContext()); + mlir::Value ptr = builder.createConvert(loc, ptrTy, buffer); + + mlir::ModuleOp mod = builder.getModule(); + mlir::OpBuilder modBuilder(mod.getBodyRegion()); + modBuilder.setInsertionPointToEnd(val.getParentBlock()); + return mlir::LLVM::MemsetOp::create( + modBuilder, loc, ptr, val, byteLen, + fir::isa_volatile_type(converter.genType(sym))); +} diff --git a/flang/test/Lower/init-local-zero.f90 b/flang/test/Lower/init-local-zero.f90 index 2ed8ca2f615dd..804169c7e4f8d 100644 --- a/flang/test/Lower/init-local-zero.f90 +++ b/flang/test/Lower/init-local-zero.f90 @@ -45,25 +45,12 @@ subroutine uninitialized_complex !CHECK: %[[ONE:.*]] = arith.constant 1 : index !CHECK: %[[X_ALLOCA:.*]] = fir.alloca !fir.char<1> {bindc_name = "x", uniq_name = "_QFuninitialized_characterEx"} !CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] typeparams %[[ONE]] {uniq_name = "_QFuninitialized_characterEx"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>) +!CHECK: %[[ZERO:.*]] = arith.constant 0 : i8 !CHECK: %[[CVT:.*]] = fir.convert %[[ONE]] : (index) -> i64 !CHECK: %[[CONST:.*]] = arith.constant 1 : i64 !CHECK: %[[COUNT:.*]] = arith.muli %[[CVT]], %[[CONST]] : i64 !CHECK: %[[CVT:.*]] = fir.convert %[[X]]#0 : (!fir.ref<!fir.char<1>>) -> !llvm.ptr -!CHECK: %[[ZERO:.*]] = arith.constant 0 : i8 !CHECK: "llvm.intr.memset"(%[[CVT]], %[[ZERO]], %[[COUNT]]) <{isVolatile = false}> : (!llvm.ptr, i8, i64) -> () subroutine uninitialized_character character :: x end subroutine - -!CHECK: %[[X_ALLOCA:.*]] = fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "x", uniq_name = "_QFallocatable_scalarEx"} -!CHECK: %[[ZERO_BITS:.*]] = fir.zero_bits !fir.heap<i32> -!CHECK: %[[EMBOX:.*]] = fir.embox %[[ZERO_BITS]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>> -!CHECK: fir.store %[[EMBOX]] to %[[X_ALLOCA]] : !fir.ref<!fir.box<!fir.heap<i32>>> -!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFallocatable_scalarEx"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>) -!CHECK: %[[ZERO:.*]] = arith.constant 0 : i32 -!CHECK: %[[LOAD:.*]] = fir.load %[[X]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>> -!CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32> -!CHECK: hlfir.assign %[[ZERO]] to %[[ADDR]] : i32, !fir.heap<i32> -subroutine allocatable_scalar - integer, allocatable :: x -end subroutine _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
