[flang-commits] [flang] 9ac452b - [flang][NFC] Move Array constructor inlined temp management into a utility

Jean Perier via flang-commits flang-commits at lists.llvm.org
Tue May 23 08:01:17 PDT 2023


Author: Jean Perier
Date: 2023-05-23T17:00:31+02:00
New Revision: 9ac452b2864e2a4c5dbcba3c6c8ad66cb28476ec

URL: https://github.com/llvm/llvm-project/commit/9ac452b2864e2a4c5dbcba3c6c8ad66cb28476ec
DIFF: https://github.com/llvm/llvm-project/commit/9ac452b2864e2a4c5dbcba3c6c8ad66cb28476ec.diff

LOG: [flang][NFC] Move Array constructor inlined temp management into a utility

This patch moves the counter and storage management part of the array
constructor inlined temporary strategy into its own utility so that it
can be reused for the simple cases of temporary creations inside WHERE
and FORALL.

It actually fixes a bug where the counter first value  used for addressing
was "2" leading to read/write after the allocated storage... It seems
I ran the tests end-to-end without the HLFIR flag when previously testing
this. So this may clear some segfaults.

Differential Revision: https://reviews.llvm.org/D151106

Added: 
    flang/include/flang/Optimizer/Builder/TemporaryStorage.h
    flang/lib/Optimizer/Builder/TemporaryStorage.cpp

Modified: 
    flang/include/flang/Optimizer/Builder/HLFIRTools.h
    flang/lib/Lower/ConvertArrayConstructor.cpp
    flang/lib/Optimizer/Builder/CMakeLists.txt
    flang/test/Lower/HLFIR/array-ctor-as-inlined-temp.f90
    flang/test/Lower/HLFIR/array-ctor-character.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
index 06bd4d8ccd2d3..5a3ab33d7496a 100644
--- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h
+++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
@@ -135,6 +135,11 @@ class Entity : public mlir::Value {
     return getFortranElementType().isa<fir::CharacterType>();
   }
 
+  bool hasIntrinsicType() const {
+    mlir::Type eleTy = getFortranElementType();
+    return fir::isa_trivial(eleTy) || eleTy.isa<fir::CharacterType>();
+  }
+
   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
index 0000000000000..4a96b11d44804
--- /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 
diff erent 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<mlir::Value> 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<?xT>). 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
index 24f49c241c57d..ed78a712b68b3 100644
--- 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 StrategyBase {
 };
 
 /// 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 <typename CounterType>
-class InlinedTempStrategyImpl : public StrategyBase {
+/// constructors. It must be provided a boolean to indicate if the array
+/// constructor has any implied-do-loop.
+template <bool hasLoops>
+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 @@ class InlinedTempStrategyImpl : public StrategyBase {
                           fir::SequenceType declaredType, mlir::Value extent,
                           llvm::ArrayRef<mlir::Value> lengths)
       : StrategyBase{stmtCtx, symMap},
-        one{builder.createIntegerConstant(loc, builder.getIndexType(), 1)},
-        counter{loc, builder, one} {
-    // Allocate the temporary storage.
-    llvm::SmallVector<mlir::Value, 1> extents{extent};
-    mlir::Value tempStorage = builder.createHeapTemporary(
-        loc, declaredType, tempName, extents, lengths);
-    mlir::Value shape = builder.genShape(loc, extents);
-    temp =
-        builder
-            .create<hlfir::DeclareOp>(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 
diff erence for derived types, so for now derived types
-    // will use the runtime strategy to avoid any bad behaviors.
-    builder.create<hlfir::AssignOp>(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 @@ class InlinedTempStrategyImpl : public StrategyBase {
   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<fir::DoLoopOp>(loc, lower, upper, stride,
                                               /*unordered=*/false,
@@ -166,77 +148,21 @@ class InlinedTempStrategyImpl : public StrategyBase {
   /// 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<hlfir::AsExprOp>(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<mlir::arith::AddIOp>(loc, indexValue, increment);
-    return currentValue;
-  }
-
-private:
-  mlir::Value indexValue;
-};
-using LooplessInlinedTempStrategy = InlinedTempStrategyImpl<ValueCounter>;
-
+using LooplessInlinedTempStrategy = InlinedTempStrategyImpl</*hasLoops=*/false>;
 /// 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<fir::StoreOp>(loc, initialValue, indexVar);
-  }
-
-  mlir::Value getAndIncrementIndex(mlir::Location loc,
-                                   fir::FirOpBuilder &builder,
-                                   mlir::Value increment) const {
-    mlir::Value indexValue = builder.create<fir::LoadOp>(loc, indexVar);
-    indexValue =
-        builder.create<mlir::arith::AddIOp>(loc, indexValue, increment);
-    builder.create<fir::StoreOp>(loc, indexValue, indexVar);
-    return indexValue;
-  }
-
-private:
-  mlir::Value indexVar;
-};
-using InlinedTempStrategy = InlinedTempStrategyImpl<InMemoryCounter>;
+using InlinedTempStrategy = InlinedTempStrategyImpl</*hasLoops=*/true>;
 
 /// 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
index c93d4b9465148..66e9499b3c05a 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -24,6 +24,7 @@ add_flang_library(FIRBuilder
   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
index 0000000000000..d707d623bc9c8
--- /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<fir::StoreOp>(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<fir::LoadOp>(loc, index);
+    mlir::Value newValue =
+        builder.create<mlir::arith::AddIOp>(loc, indexValue, one);
+    builder.create<fir::StoreOp>(loc, newValue, index);
+    return indexValue;
+  }
+  mlir::Value indexValue = index;
+  index = builder.create<mlir::arith::AddIOp>(loc, indexValue, one);
+  return indexValue;
+}
+
+void fir::factory::Counter::reset(mlir::Location loc,
+                                  fir::FirOpBuilder &builder) {
+  if (canCountThroughLoops)
+    builder.create<fir::StoreOp>(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<mlir::Value> 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<mlir::Value, 1> 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<hlfir::DeclareOp>(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 
diff erence 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<hlfir::AssignOp>(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<hlfir::DeclareOp>();
+    assert(declare && "temp must have been declared");
+    builder.create<fir::FreeMemOp>(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<hlfir::AsExprOp>(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
index bd9d9ffcadc41..b3d8f80d75b39 100644
--- 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 @@ subroutine test_simple(i)
 ! 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.array<2xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2xi32>>, !fir.heap<!fir.array<2xi32>>)
 ! 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<!fir.array<2xi32>>, index) -> !fir.ref<i32>
 ! CHECK:  hlfir.assign %[[VAL_7]] to %[[VAL_9]] : i32, !fir.ref<i32>
 ! CHECK:  %[[VAL_10:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<i32>
@@ -31,11 +32,12 @@ subroutine test_simple_real(x)
 ! 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.array<2xf16>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2xf16>>, !fir.heap<!fir.array<2xf16>>)
 ! CHECK:  %[[VAL_7:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<f16>
-! 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<!fir.array<2xf16>>, index) -> !fir.ref<f16>
 ! CHECK:  hlfir.assign %[[VAL_7]] to %[[VAL_9]] : f16, !fir.ref<f16>
 ! CHECK:  %[[VAL_10:.*]] = arith.constant 0.000000e+00 : f16
@@ -54,6 +56,7 @@ subroutine test_simple_complex(z)
 ! 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.array<2x!fir.complex<8>>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2x!fir.complex<8>>>, !fir.heap<!fir.array<2x!fir.complex<8>>>)
@@ -63,7 +66,7 @@ subroutine test_simple_complex(z)
 ! 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<!fir.array<2x!fir.complex<8>>>, index) -> !fir.ref<!fir.complex<8>>
 ! CHECK:  hlfir.assign %[[VAL_12]] to %[[VAL_14]] : !fir.complex<8>, !fir.ref<!fir.complex<8>>
 ! CHECK:  %[[VAL_15:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref<!fir.complex<4>>
@@ -84,11 +87,12 @@ subroutine test_simple_logical(a, b)
 ! 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.array<2x!fir.logical<4>>>, !fir.shape<1>) -> (!fir.heap<!fir.array<2x!fir.logical<4>>>, !fir.heap<!fir.array<2x!fir.logical<4>>>)
 ! CHECK:  %[[VAL_9:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.logical<4>>
-! 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<!fir.array<2x!fir.logical<4>>>, index) -> !fir.ref<!fir.logical<4>>
 ! CHECK:  hlfir.assign %[[VAL_9]] to %[[VAL_11]] : !fir.logical<4>, !fir.ref<!fir.logical<4>>
 ! CHECK:  %[[VAL_12:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<!fir.logical<4>>
@@ -129,6 +133,7 @@ subroutine test_implied_do(n)
 ! 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<index>
 ! CHECK:           %[[VAL_19:.*]] = fir.allocmem !fir.array<?xi32>, %[[VAL_17]] {bindc_name = ".tmp.arrayctor", uniq_name = ""}
 ! CHECK:           %[[VAL_20:.*]] = fir.shape %[[VAL_17]] : (index) -> !fir.shape<1>
@@ -142,16 +147,16 @@ subroutine test_implied_do(n)
 ! 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<index>
-! 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<index>
-! CHECK:             %[[VAL_32:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_31]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+! CHECK:             %[[VAL_32:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_30]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
 ! CHECK:             hlfir.assign %[[VAL_29]] to %[[VAL_32]] : i32, !fir.ref<i32>
 ! 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<index>
-! 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<index>
-! CHECK:             %[[VAL_37:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_36]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+! CHECK:             %[[VAL_37:.*]] = hlfir.designate %[[VAL_21]]#0 (%[[VAL_35]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
 ! CHECK:             hlfir.assign %[[VAL_34]] to %[[VAL_37]] : i32, !fir.ref<i32>
 ! CHECK:           }
 ! CHECK:           %[[VAL_38:.*]] = arith.constant true
@@ -192,6 +197,7 @@ subroutine test_strided_implied_do(lb, ub, stride)
 ! 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<index>
 ! CHECK:           %[[VAL_23:.*]] = fir.allocmem !fir.array<?xi32>, %[[VAL_21]] {bindc_name = ".tmp.arrayctor", uniq_name = ""}
 ! CHECK:           %[[VAL_24:.*]] = fir.shape %[[VAL_21]] : (index) -> !fir.shape<1>
@@ -205,16 +211,16 @@ subroutine test_strided_implied_do(lb, ub, stride)
 ! 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<index>
-! 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<index>
-! CHECK:             %[[VAL_36:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_35]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+! CHECK:             %[[VAL_36:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_34]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
 ! CHECK:             hlfir.assign %[[VAL_33]] to %[[VAL_36]] : i32, !fir.ref<i32>
 ! 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<index>
-! 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<index>
-! CHECK:             %[[VAL_41:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_40]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+! CHECK:             %[[VAL_41:.*]] = hlfir.designate %[[VAL_25]]#0 (%[[VAL_39]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
 ! CHECK:             hlfir.assign %[[VAL_38]] to %[[VAL_41]] : i32, !fir.ref<i32>
 ! CHECK:           }
 ! CHECK:           %[[VAL_42:.*]] = arith.constant true
@@ -264,6 +270,7 @@ subroutine test_nested_implied_do(n, m)
 ! 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<index>
 ! CHECK:           %[[VAL_32:.*]] = fir.allocmem !fir.array<?xi32>, %[[VAL_30]] {bindc_name = ".tmp.arrayctor", uniq_name = ""}
 ! CHECK:           %[[VAL_33:.*]] = fir.shape %[[VAL_30]] : (index) -> !fir.shape<1>
@@ -288,9 +295,9 @@ subroutine test_nested_implied_do(n, m)
 ! 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<index>
-! 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<index>
-! CHECK:               %[[VAL_56:.*]] = hlfir.designate %[[VAL_34]]#0 (%[[VAL_55]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+! CHECK:               %[[VAL_56:.*]] = hlfir.designate %[[VAL_34]]#0 (%[[VAL_54]])  : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
 ! CHECK:               hlfir.assign %[[VAL_53]] to %[[VAL_56]] : i32, !fir.ref<i32>
 ! CHECK:             }
 ! CHECK:           }

diff  --git a/flang/test/Lower/HLFIR/array-ctor-character.f90 b/flang/test/Lower/HLFIR/array-ctor-character.f90
index d4c38bda3ecc0..92312dc7328a8 100644
--- a/flang/test/Lower/HLFIR/array-ctor-character.f90
+++ b/flang/test/Lower/HLFIR/array-ctor-character.f90
@@ -17,12 +17,13 @@ subroutine test_pre_computed_length(c1, c2)
 ! 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.array<2x!fir.char<1,3>>>, !fir.shape<1>, index) -> (!fir.heap<!fir.array<2x!fir.char<1,3>>>, !fir.heap<!fir.array<2x!fir.char<1,3>>>)
 ! 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<!fir.char<1,3>>
-! 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<!fir.array<2x!fir.char<1,3>>>, index, index) -> !fir.ref<!fir.char<1,3>>
 ! CHECK:  hlfir.assign %[[VAL_20]] to %[[VAL_22]] : !hlfir.expr<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>
 ! CHECK:  %[[VAL_23:.*]] = arith.constant 3 : i64


        


More information about the flang-commits mailing list