diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -135,6 +135,11 @@ return getFortranElementType().isa(); } + bool hasIntrinsicType() const { + mlir::Type eleTy = getFortranElementType(); + return fir::isa_trivial(eleTy) || eleTy.isa(); + } + bool isDerivedWithLengthParameters() const { return fir::isRecordWithTypeParameters(getFortranElementType()); } diff --git a/flang/include/flang/Optimizer/Builder/TemporaryStorage.h b/flang/include/flang/Optimizer/Builder/TemporaryStorage.h new file mode 100644 --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/TemporaryStorage.h @@ -0,0 +1,97 @@ +//===-- Optimizer/Builder/TemporaryStorage.h --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utility to create an manipulate vector like temporary storages holding +// Fortran values or descriptors in HLFIR. +// +// This is useful to deal with array constructors, and temporary storage +// inside forall and where constructs where it is not known prior to the +// construct execution how many values will be stored, or where the values +// at each iteration may have different shapes or type parameters. +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_OPTIMIZER_BUILDER_TEMPORARYSTORAGE_H +#define FORTRAN_OPTIMIZER_BUILDER_TEMPORARYSTORAGE_H + +#include "flang/Optimizer/HLFIR/HLFIROps.h" + +namespace fir { +class FirOpBuilder; +} + +namespace hlfir { +class Entity; +} + +namespace fir::factory { + +/// Structure to create and manipulate counters in generated code. +/// They are used to keep track of the insertion of fetching position in the +/// temporary storages. +/// By default, this counter is implemented with a value in memory and can be +/// incremented inside generated loops or branches. +/// The option canCountThroughLoops can be set to false to get a counter that +/// is a simple SSA value that is swap by its incremented value (hence, the +/// counter cannot count through loops since the SSA value in the loop becomes +/// inaccessible after the loop). This form helps reducing compile times for +/// huge array constructors without implied-do-loops. +struct Counter { + /// Create a counter set to the initial value. + Counter(mlir::Location loc, fir::FirOpBuilder &builder, + mlir::Value initialValue, bool canCountThroughLoops = true); + /// Return "counter++". + mlir::Value getAndIncrementIndex(mlir::Location loc, + fir::FirOpBuilder &builder); + /// Set the counter to the initial value. + void reset(mlir::Location loc, fir::FirOpBuilder &builder); + const bool canCountThroughLoops; + +private: + /// Zero for the init/reset. + mlir::Value initialValue; + /// One for the increment. + mlir::Value one; + /// Index variable or value holding the counter current value. + mlir::Value index; +}; + +/// Data structure to stack simple scalars that all have the same type and +/// type parameters, and where the total number of elements that will be pushed +/// is known or can be maximized. It is implemented inlined and does not require +/// runtime. +class HomogeneousScalarStack { +public: + HomogeneousScalarStack(mlir::Location loc, fir::FirOpBuilder &builder, + fir::SequenceType declaredType, mlir::Value extent, + llvm::ArrayRef lengths, + bool allocateOnHeap, bool stackThroughLoops, + llvm::StringRef name); + + void pushValue(mlir::Location loc, fir::FirOpBuilder &builder, + mlir::Value value); + void resetFetchPosition(mlir::Location loc, fir::FirOpBuilder &builder); + mlir::Value fetch(mlir::Location loc, fir::FirOpBuilder &builder); + void destroy(mlir::Location loc, fir::FirOpBuilder &builder); + + /// Move the temporary storage into a rank one array expression value + /// (hlfir.expr). The temporary should not be used anymore after this + /// call. + hlfir::Entity moveStackAsArrayExpr(mlir::Location loc, + fir::FirOpBuilder &builder); + +private: + /// Allocate the temporary on the heap. + const bool allocateOnHeap; + /// Counter to keep track of the insertion or fetching position. + Counter counter; + /// Temporary storage. + mlir::Value temp; +}; +} // namespace fir::factory +#endif // FORTRAN_OPTIMIZER_BUILDER_TEMPORARYSTORAGE_H diff --git a/flang/lib/Lower/ConvertArrayConstructor.cpp b/flang/lib/Lower/ConvertArrayConstructor.cpp --- a/flang/lib/Lower/ConvertArrayConstructor.cpp +++ b/flang/lib/Lower/ConvertArrayConstructor.cpp @@ -16,6 +16,7 @@ #include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Builder/Runtime/ArrayConstructor.h" #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" +#include "flang/Optimizer/Builder/TemporaryStorage.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/HLFIR/HLFIROps.h" @@ -101,10 +102,11 @@ }; /// Class that implements the "inlined temp strategy" to lower array -/// constructors. It must be further provided a CounterType class to specify how -/// the current ac-value insertion position is tracked. -template -class InlinedTempStrategyImpl : public StrategyBase { +/// constructors. It must be provided a boolean to indicate if the array +/// constructor has any implied-do-loop. +template +class InlinedTempStrategyImpl : public StrategyBase, + public fir::factory::HomogeneousScalarStack { /// Name that will be given to the temporary allocation and hlfir.declare in /// the IR. static constexpr char tempName[] = ".tmp.arrayctor"; @@ -118,34 +120,14 @@ fir::SequenceType declaredType, mlir::Value extent, llvm::ArrayRef lengths) : StrategyBase{stmtCtx, symMap}, - one{builder.createIntegerConstant(loc, builder.getIndexType(), 1)}, - counter{loc, builder, one} { - // Allocate the temporary storage. - llvm::SmallVector extents{extent}; - mlir::Value tempStorage = builder.createHeapTemporary( - loc, declaredType, tempName, extents, lengths); - mlir::Value shape = builder.genShape(loc, extents); - temp = - builder - .create(loc, tempStorage, tempName, shape, - lengths, fir::FortranVariableFlagsAttr{}) - .getBase(); - } + fir::factory::HomogeneousScalarStack{ + loc, builder, declaredType, + extent, lengths, /*allocateOnHeap=*/true, + hasLoops, tempName} {} /// Push a lowered ac-value into the current insertion point and /// increment the insertion point. - void pushValue(mlir::Location loc, fir::FirOpBuilder &builder, - hlfir::Entity value) { - assert(value.isScalar() && "cannot use inlined temp with array values"); - mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder, one); - hlfir::Entity tempElement = hlfir::getElementAt( - loc, builder, hlfir::Entity{temp}, mlir::ValueRange{indexValue}); - // TODO: "copy" would probably be better than assign to ensure there are no - // side effects (user assignments, temp, lhs finalization)? - // This only makes a difference for derived types, so for now derived types - // will use the runtime strategy to avoid any bad behaviors. - builder.create(loc, value, tempElement); - } + using fir::factory::HomogeneousScalarStack::pushValue; /// Start a fir.do_loop with the control from an implied-do and return /// the loop induction variable that is the ac-do-variable value. @@ -153,7 +135,7 @@ mlir::Value startImpliedDo(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value lower, mlir::Value upper, mlir::Value stride) { - if constexpr (!CounterType::canCountThroughLoops) + if constexpr (!hasLoops) fir::emitFatalError(loc, "array constructor lowering is inconsistent"); auto loop = builder.create(loc, lower, upper, stride, /*unordered=*/false, @@ -166,77 +148,21 @@ /// variables and cannot be further modified). hlfir::Entity finishArrayCtorLowering(mlir::Location loc, fir::FirOpBuilder &builder) { - // Temp is created using createHeapTemporary. - mlir::Value mustFree = builder.createBool(loc, true); - auto hlfirExpr = builder.create(loc, temp, mustFree); - return hlfir::Entity{hlfirExpr}; + return moveStackAsArrayExpr(loc, builder); } - -private: - mlir::Value one; - CounterType counter; - mlir::Value temp; }; -/// A simple SSA value counter to lower array constructors without any -/// implied-do in the "inlined temp strategy". -/// The SSA value being tracked by the counter (hence, this -/// cannot count through loops since the SSA value in the loop becomes -/// inaccessible after the loop). /// Semantic analysis expression rewrites unroll implied do loop with -/// compile time constant bounds (even if huge). So this minimalistic +/// compile time constant bounds (even if huge). So using a minimalistic /// counter greatly reduces the generated IR for simple but big array /// constructors [(i,i=1,constant-expr)] that are expected to be quite /// common. -class ValueCounter { -public: - static constexpr bool canCountThroughLoops = false; - ValueCounter(mlir::Location loc, fir::FirOpBuilder &builder, - mlir::Value initialValue) { - indexValue = initialValue; - } - - mlir::Value getAndIncrementIndex(mlir::Location loc, - fir::FirOpBuilder &builder, - mlir::Value increment) { - mlir::Value currentValue = indexValue; - indexValue = - builder.create(loc, indexValue, increment); - return currentValue; - } - -private: - mlir::Value indexValue; -}; -using LooplessInlinedTempStrategy = InlinedTempStrategyImpl; - +using LooplessInlinedTempStrategy = InlinedTempStrategyImpl; /// A generic memory based counter that can deal with all cases of /// "inlined temp strategy". The counter value is stored in a temp /// from which it is loaded, incremented, and stored every time an /// ac-value is pushed. -class InMemoryCounter { -public: - static constexpr bool canCountThroughLoops = true; - InMemoryCounter(mlir::Location loc, fir::FirOpBuilder &builder, - mlir::Value initialValue) { - indexVar = builder.createTemporary(loc, initialValue.getType()); - builder.create(loc, initialValue, indexVar); - } - - mlir::Value getAndIncrementIndex(mlir::Location loc, - fir::FirOpBuilder &builder, - mlir::Value increment) const { - mlir::Value indexValue = builder.create(loc, indexVar); - indexValue = - builder.create(loc, indexValue, increment); - builder.create(loc, indexValue, indexVar); - return indexValue; - } - -private: - mlir::Value indexVar; -}; -using InlinedTempStrategy = InlinedTempStrategyImpl; +using InlinedTempStrategy = InlinedTempStrategyImpl; /// Class that implements the "as function of the indices" lowering strategy. /// It will lower [(scalar_expr(i), i=l,u,s)] to: diff --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt --- a/flang/lib/Optimizer/Builder/CMakeLists.txt +++ b/flang/lib/Optimizer/Builder/CMakeLists.txt @@ -24,6 +24,7 @@ Runtime/Reduction.cpp Runtime/Stop.cpp Runtime/Transformational.cpp + TemporaryStorage.cpp DEPENDS FIRDialect diff --git a/flang/lib/Optimizer/Builder/TemporaryStorage.cpp b/flang/lib/Optimizer/Builder/TemporaryStorage.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Optimizer/Builder/TemporaryStorage.cpp @@ -0,0 +1,135 @@ +//===-- Optimizer/Builder/TemporaryStorage.cpp ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// Implementation of utility data structures to create and manipulate temporary +// storages to stack Fortran values or pointers in HLFIR. +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/Builder/TemporaryStorage.h" +#include "flang/Optimizer/Builder/HLFIRTools.h" +#include "flang/Optimizer/Builder/Runtime/RTBuilder.h" +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" + +//===----------------------------------------------------------------------===// +// fir::factory::Counter implementation. +//===----------------------------------------------------------------------===// + +fir::factory::Counter::Counter(mlir::Location loc, fir::FirOpBuilder &builder, + mlir::Value initialValue, + bool canCountThroughLoops) + : canCountThroughLoops{canCountThroughLoops}, initialValue{initialValue} { + mlir::Type type = initialValue.getType(); + one = builder.createIntegerConstant(loc, type, 1); + if (canCountThroughLoops) { + index = builder.createTemporary(loc, type); + builder.create(loc, initialValue, index); + } else { + index = initialValue; + } +} + +mlir::Value +fir::factory::Counter::getAndIncrementIndex(mlir::Location loc, + fir::FirOpBuilder &builder) { + if (canCountThroughLoops) { + mlir::Value indexValue = builder.create(loc, index); + mlir::Value newValue = + builder.create(loc, indexValue, one); + builder.create(loc, newValue, index); + return indexValue; + } + mlir::Value indexValue = index; + index = builder.create(loc, indexValue, one); + return indexValue; +} + +void fir::factory::Counter::reset(mlir::Location loc, + fir::FirOpBuilder &builder) { + if (canCountThroughLoops) + builder.create(loc, initialValue, index); + else + index = initialValue; +} + +//===----------------------------------------------------------------------===// +// fir::factory::HomogeneousScalarStack implementation. +//===----------------------------------------------------------------------===// + +fir::factory::HomogeneousScalarStack::HomogeneousScalarStack( + mlir::Location loc, fir::FirOpBuilder &builder, + fir::SequenceType declaredType, mlir::Value extent, + llvm::ArrayRef lengths, bool allocateOnHeap, + bool stackThroughLoops, llvm::StringRef tempName) + : allocateOnHeap{allocateOnHeap}, + counter{loc, builder, + builder.createIntegerConstant(loc, builder.getIndexType(), 1), + stackThroughLoops} { + // Allocate the temporary storage. + llvm::SmallVector extents{extent}; + mlir::Value tempStorage; + if (allocateOnHeap) + tempStorage = builder.createHeapTemporary(loc, declaredType, tempName, + extents, lengths); + else + tempStorage = + builder.createTemporary(loc, declaredType, tempName, extents, lengths); + + mlir::Value shape = builder.genShape(loc, extents); + temp = builder + .create(loc, tempStorage, tempName, shape, + lengths, fir::FortranVariableFlagsAttr{}) + .getBase(); +} + +void fir::factory::HomogeneousScalarStack::pushValue(mlir::Location loc, + fir::FirOpBuilder &builder, + mlir::Value value) { + hlfir::Entity entity{value}; + assert(entity.isScalar() && "cannot use inlined temp with array"); + mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder); + hlfir::Entity tempElement = hlfir::getElementAt( + loc, builder, hlfir::Entity{temp}, mlir::ValueRange{indexValue}); + // TODO: "copy" would probably be better than assign to ensure there are no + // side effects (user assignments, temp, lhs finalization)? + // This only makes a difference for derived types, and for now derived types + // will use the runtime strategy to avoid any bad behaviors. So the todo + // below should not get hit but is added as a remainder/safety. + if (!entity.hasIntrinsicType()) + TODO(loc, "creating inlined temporary stack for derived types"); + builder.create(loc, value, tempElement); +} + +void fir::factory::HomogeneousScalarStack::resetFetchPosition( + mlir::Location loc, fir::FirOpBuilder &builder) { + counter.reset(loc, builder); +} + +mlir::Value +fir::factory::HomogeneousScalarStack::fetch(mlir::Location loc, + fir::FirOpBuilder &builder) { + mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder); + hlfir::Entity tempElement = hlfir::getElementAt( + loc, builder, hlfir::Entity{temp}, mlir::ValueRange{indexValue}); + return hlfir::loadTrivialScalar(loc, builder, tempElement); +} + +void fir::factory::HomogeneousScalarStack::destroy(mlir::Location loc, + fir::FirOpBuilder &builder) { + if (allocateOnHeap) { + auto declare = temp.getDefiningOp(); + assert(declare && "temp must have been declared"); + builder.create(loc, declare.getMemref()); + } +} + +hlfir::Entity fir::factory::HomogeneousScalarStack::moveStackAsArrayExpr( + mlir::Location loc, fir::FirOpBuilder &builder) { + mlir::Value mustFree = builder.createBool(loc, allocateOnHeap); + auto hlfirExpr = builder.create(loc, temp, mustFree); + return hlfir::Entity{hlfirExpr}; +} diff --git a/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 b/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 --- a/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90 @@ -8,11 +8,12 @@ ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ei ! CHECK: %[[VAL_2:.*]] = arith.constant 2 : index ! CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_3B:.*]] = arith.constant 1 : index ! CHECK: %[[VAL_4:.*]] = fir.allocmem !fir.array<2xi32> {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_5]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.heap>, !fir.heap>) ! CHECK: %[[VAL_7:.*]] = arith.constant 42 : i32 -! CHECK: %[[VAL_8:.*]] = arith.addi %[[VAL_3]], %[[VAL_3]] : index +! CHECK: %[[VAL_8:.*]] = arith.addi %[[VAL_3]], %[[VAL_3B]] : index ! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_3]]) : (!fir.heap>, index) -> !fir.ref ! CHECK: hlfir.assign %[[VAL_7]] to %[[VAL_9]] : i32, !fir.ref ! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref @@ -31,11 +32,12 @@ ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ex ! CHECK: %[[VAL_2:.*]] = arith.constant 2 : index ! CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_3B:.*]] = arith.constant 1 : index ! CHECK: %[[VAL_4:.*]] = fir.allocmem !fir.array<2xf16> {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_5]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>, !fir.shape<1>) -> (!fir.heap>, !fir.heap>) ! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref -! CHECK: %[[VAL_8:.*]] = arith.addi %[[VAL_3]], %[[VAL_3]] : index +! CHECK: %[[VAL_8:.*]] = arith.addi %[[VAL_3]], %[[VAL_3B]] : index ! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_3]]) : (!fir.heap>, index) -> !fir.ref ! CHECK: hlfir.assign %[[VAL_7]] to %[[VAL_9]] : f16, !fir.ref ! CHECK: %[[VAL_10:.*]] = arith.constant 0.000000e+00 : f16 @@ -54,6 +56,7 @@ ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ez ! CHECK: %[[VAL_2:.*]] = arith.constant 2 : index ! CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_3B:.*]] = arith.constant 1 : index ! CHECK: %[[VAL_4:.*]] = fir.allocmem !fir.array<2x!fir.complex<8>> {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_5]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>>, !fir.shape<1>) -> (!fir.heap>>, !fir.heap>>) @@ -63,7 +66,7 @@ ! CHECK: %[[VAL_10:.*]] = fir.undefined !fir.complex<8> ! CHECK: %[[VAL_11:.*]] = fir.insert_value %[[VAL_10]], %[[VAL_8]], [0 : index] : (!fir.complex<8>, f64) -> !fir.complex<8> ! CHECK: %[[VAL_12:.*]] = fir.insert_value %[[VAL_11]], %[[VAL_9]], [1 : index] : (!fir.complex<8>, f64) -> !fir.complex<8> -! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_3]], %[[VAL_3]] : index +! CHECK: %[[VAL_13:.*]] = arith.addi %[[VAL_3]], %[[VAL_3B]] : index ! CHECK: %[[VAL_14:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_3]]) : (!fir.heap>>, index) -> !fir.ref> ! CHECK: hlfir.assign %[[VAL_12]] to %[[VAL_14]] : !fir.complex<8>, !fir.ref> ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref> @@ -84,11 +87,12 @@ ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Eb ! CHECK: %[[VAL_4:.*]] = arith.constant 2 : index ! CHECK: %[[VAL_5:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_5B:.*]] = arith.constant 1 : index ! CHECK: %[[VAL_6:.*]] = fir.allocmem !fir.array<2x!fir.logical<4>> {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_7]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap>>, !fir.shape<1>) -> (!fir.heap>>, !fir.heap>>) ! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref> -! CHECK: %[[VAL_10:.*]] = arith.addi %[[VAL_5]], %[[VAL_5]] : index +! CHECK: %[[VAL_10:.*]] = arith.addi %[[VAL_5]], %[[VAL_5B]] : index ! CHECK: %[[VAL_11:.*]] = hlfir.designate %[[VAL_8]]#0 (%[[VAL_5]]) : (!fir.heap>>, index) -> !fir.ref> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_11]] : !fir.logical<4>, !fir.ref> ! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref> @@ -129,6 +133,7 @@ ! CHECK: %[[VAL_16:.*]] = arith.addi %[[VAL_3]], %[[VAL_15]] : i64 ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i64) -> index ! CHECK: %[[VAL_18:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_18B:.*]] = arith.constant 1 : index ! CHECK: fir.store %[[VAL_18]] to %[[VAL_1]] : !fir.ref ! CHECK: %[[VAL_19:.*]] = fir.allocmem !fir.array, %[[VAL_17]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_17]] : (index) -> !fir.shape<1> @@ -142,16 +147,16 @@ ! CHECK: fir.do_loop %[[VAL_28:.*]] = %[[VAL_23]] to %[[VAL_25]] step %[[VAL_27]] { ! CHECK: %[[VAL_29:.*]] = arith.constant 42 : i32 ! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_31:.*]] = arith.addi %[[VAL_30]], %[[VAL_18]] : index +! CHECK: %[[VAL_31:.*]] = arith.addi %[[VAL_30]], %[[VAL_18B]] : index ! CHECK: fir.store %[[VAL_31]] to %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_32:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_31]]) : (!fir.box>, index) -> !fir.ref +! CHECK: %[[VAL_32:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_30]]) : (!fir.box>, index) -> !fir.ref ! CHECK: hlfir.assign %[[VAL_29]] to %[[VAL_32]] : i32, !fir.ref ! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_28]] : (index) -> i64 ! CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_33]] : (i64) -> i32 ! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_36:.*]] = arith.addi %[[VAL_35]], %[[VAL_18]] : index +! CHECK: %[[VAL_36:.*]] = arith.addi %[[VAL_35]], %[[VAL_18B]] : index ! CHECK: fir.store %[[VAL_36]] to %[[VAL_1]] : !fir.ref -! CHECK: %[[VAL_37:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_36]]) : (!fir.box>, index) -> !fir.ref +! CHECK: %[[VAL_37:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_35]]) : (!fir.box>, index) -> !fir.ref ! CHECK: hlfir.assign %[[VAL_34]] to %[[VAL_37]] : i32, !fir.ref ! CHECK: } ! CHECK: %[[VAL_38:.*]] = arith.constant true @@ -192,6 +197,7 @@ ! CHECK: %[[VAL_20:.*]] = arith.addi %[[VAL_7]], %[[VAL_19]] : i64 ! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_22B:.*]] = arith.constant 1 : index ! CHECK: fir.store %[[VAL_22]] to %[[VAL_3]] : !fir.ref ! CHECK: %[[VAL_23:.*]] = fir.allocmem !fir.array, %[[VAL_21]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_24:.*]] = fir.shape %[[VAL_21]] : (index) -> !fir.shape<1> @@ -205,16 +211,16 @@ ! CHECK: fir.do_loop %[[VAL_32:.*]] = %[[VAL_27]] to %[[VAL_29]] step %[[VAL_31]] { ! CHECK: %[[VAL_33:.*]] = arith.constant 42 : i32 ! CHECK: %[[VAL_34:.*]] = fir.load %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_35:.*]] = arith.addi %[[VAL_34]], %[[VAL_22]] : index +! CHECK: %[[VAL_35:.*]] = arith.addi %[[VAL_34]], %[[VAL_22B]] : index ! CHECK: fir.store %[[VAL_35]] to %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_36:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_35]]) : (!fir.box>, index) -> !fir.ref +! CHECK: %[[VAL_36:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_34]]) : (!fir.box>, index) -> !fir.ref ! CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_36]] : i32, !fir.ref ! CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_32]] : (index) -> i64 ! CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (i64) -> i32 ! CHECK: %[[VAL_39:.*]] = fir.load %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_40:.*]] = arith.addi %[[VAL_39]], %[[VAL_22]] : index +! CHECK: %[[VAL_40:.*]] = arith.addi %[[VAL_39]], %[[VAL_22B]] : index ! CHECK: fir.store %[[VAL_40]] to %[[VAL_3]] : !fir.ref -! CHECK: %[[VAL_41:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_40]]) : (!fir.box>, index) -> !fir.ref +! CHECK: %[[VAL_41:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_39]]) : (!fir.box>, index) -> !fir.ref ! CHECK: hlfir.assign %[[VAL_38]] to %[[VAL_41]] : i32, !fir.ref ! CHECK: } ! CHECK: %[[VAL_42:.*]] = arith.constant true @@ -264,6 +270,7 @@ ! CHECK: %[[VAL_29:.*]] = arith.addi %[[VAL_5]], %[[VAL_28]] : i64 ! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (i64) -> index ! CHECK: %[[VAL_31:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_31B:.*]] = arith.constant 1 : index ! CHECK: fir.store %[[VAL_31]] to %[[VAL_2]] : !fir.ref ! CHECK: %[[VAL_32:.*]] = fir.allocmem !fir.array, %[[VAL_30]] {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_33:.*]] = fir.shape %[[VAL_30]] : (index) -> !fir.shape<1> @@ -288,9 +295,9 @@ ! CHECK: %[[VAL_52:.*]] = fir.convert %[[VAL_51]] : (i64) -> i32 ! CHECK: %[[VAL_53:.*]] = arith.addi %[[VAL_50]], %[[VAL_52]] : i32 ! CHECK: %[[VAL_54:.*]] = fir.load %[[VAL_2]] : !fir.ref -! CHECK: %[[VAL_55:.*]] = arith.addi %[[VAL_54]], %[[VAL_31]] : index +! CHECK: %[[VAL_55:.*]] = arith.addi %[[VAL_54]], %[[VAL_31B]] : index ! CHECK: fir.store %[[VAL_55]] to %[[VAL_2]] : !fir.ref -! CHECK: %[[VAL_56:.*]] = hlfir.designate %[[VAL_34]]#0 (%[[VAL_55]]) : (!fir.box>, index) -> !fir.ref +! CHECK: %[[VAL_56:.*]] = hlfir.designate %[[VAL_34]]#0 (%[[VAL_54]]) : (!fir.box>, index) -> !fir.ref ! CHECK: hlfir.assign %[[VAL_53]] to %[[VAL_56]] : i32, !fir.ref ! CHECK: } ! CHECK: } diff --git a/flang/test/Lower/HLFIR/array-ctor-character.f90 b/flang/test/Lower/HLFIR/array-ctor-character.f90 --- a/flang/test/Lower/HLFIR/array-ctor-character.f90 +++ b/flang/test/Lower/HLFIR/array-ctor-character.f90 @@ -17,12 +17,13 @@ ! CHECK: %[[VAL_13:.*]] = arith.constant 3 : i64 ! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i64) -> index ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_15B:.*]] = arith.constant 1 : index ! CHECK: %[[VAL_16:.*]] = fir.allocmem !fir.array<2x!fir.char<1,3>> {bindc_name = ".tmp.arrayctor", uniq_name = ""} ! CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_16]](%[[VAL_17]]) typeparams %[[VAL_14]] {uniq_name = ".tmp.arrayctor"} : (!fir.heap>>, !fir.shape<1>, index) -> (!fir.heap>>, !fir.heap>>) ! CHECK: %[[VAL_19:.*]] = arith.constant 3 : i64 ! CHECK: %[[VAL_20:.*]] = hlfir.set_length %[[VAL_9]]#0 len %[[VAL_19]] : (!fir.boxchar<1>, i64) -> !hlfir.expr> -! CHECK: %[[VAL_21:.*]] = arith.addi %[[VAL_15]], %[[VAL_15]] : index +! CHECK: %[[VAL_21:.*]] = arith.addi %[[VAL_15]], %[[VAL_15B]] : index ! CHECK: %[[VAL_22:.*]] = hlfir.designate %[[VAL_18]]#0 (%[[VAL_15]]) typeparams %[[VAL_14]] : (!fir.heap>>, index, index) -> !fir.ref> ! CHECK: hlfir.assign %[[VAL_20]] to %[[VAL_22]] : !hlfir.expr>, !fir.ref> ! CHECK: %[[VAL_23:.*]] = arith.constant 3 : i64