[flang-commits] [flang] 9683a9c - [flang][hlfir] Array constructor lowering [part 3/4]

Jean Perier via flang-commits flang-commits at lists.llvm.org
Fri Feb 24 00:11:41 PST 2023


Author: Jean Perier
Date: 2023-02-24T09:11:28+01:00
New Revision: 9683a9c9989a3ab40fde9afdcdc5ba7e203e3728

URL: https://github.com/llvm/llvm-project/commit/9683a9c9989a3ab40fde9afdcdc5ba7e203e3728
DIFF: https://github.com/llvm/llvm-project/commit/9683a9c9989a3ab40fde9afdcdc5ba7e203e3728.diff

LOG: [flang][hlfir] Array constructor lowering [part 3/4]

Lower the cases that require runtime support to deal
with the allocation, reallocation, or copy of ac-values to
the array constructor storage.

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

Added: 
    flang/include/flang/Optimizer/Builder/Runtime/ArrayConstructor.h
    flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp
    flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90

Modified: 
    flang/include/flang/Optimizer/Builder/FIRBuilder.h
    flang/lib/Lower/ConvertArrayConstructor.cpp
    flang/lib/Optimizer/Builder/CMakeLists.txt
    flang/lib/Optimizer/Builder/FIRBuilder.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index 3dd499e6e10f9..6882da731b652 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -338,6 +338,10 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
   mlir::Value createBox(mlir::Location loc, const fir::ExtendedValue &exv,
                         bool isPolymorphic = false);
 
+  mlir::Value createBox(mlir::Location loc, mlir::Type boxType,
+                        mlir::Value addr, mlir::Value shape, mlir::Value slice,
+                        llvm::ArrayRef<mlir::Value> lengths, mlir::Value tdesc);
+
   /// Create constant i1 with value 1. if \p b is true or 0. otherwise
   mlir::Value createBool(mlir::Location loc, bool b) {
     return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0);

diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/ArrayConstructor.h b/flang/include/flang/Optimizer/Builder/Runtime/ArrayConstructor.h
new file mode 100644
index 0000000000000..25c904a50c03a
--- /dev/null
+++ b/flang/include/flang/Optimizer/Builder/Runtime/ArrayConstructor.h
@@ -0,0 +1,39 @@
+//===- ArrayConstructor.h - array constructor runtime API calls -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ARRAYCONSTRUCTOR_H
+#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ARRAYCONSTRUCTOR_H
+
+namespace mlir {
+class Value;
+class Location;
+} // namespace mlir
+
+namespace fir {
+class FirOpBuilder;
+}
+
+namespace fir::runtime {
+
+mlir::Value genInitArrayConstructorVector(mlir::Location loc,
+                                          fir::FirOpBuilder &builder,
+                                          mlir::Value toBox,
+                                          mlir::Value useValueLengthParameters);
+
+void genPushArrayConstructorValue(mlir::Location loc,
+                                  fir::FirOpBuilder &builder,
+                                  mlir::Value arrayConstructorVector,
+                                  mlir::Value fromBox);
+
+void genPushArrayConstructorSimpleScalar(mlir::Location loc,
+                                         fir::FirOpBuilder &builder,
+                                         mlir::Value arrayConstructorVector,
+                                         mlir::Value fromAddress);
+
+} // namespace fir::runtime
+#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ARRAYCONSTRUCTOR_H

diff  --git a/flang/lib/Lower/ConvertArrayConstructor.cpp b/flang/lib/Lower/ConvertArrayConstructor.cpp
index 9b5723d2e88d3..e9afec8b4c8b2 100644
--- a/flang/lib/Lower/ConvertArrayConstructor.cpp
+++ b/flang/lib/Lower/ConvertArrayConstructor.cpp
@@ -14,10 +14,10 @@
 #include "flang/Lower/StatementContext.h"
 #include "flang/Lower/SymbolMap.h"
 #include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Builder/Runtime/ArrayConstructor.h"
 #include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Optimizer/HLFIR/HLFIROps.h"
-#include "flang/Runtime/array-constructor.h"
 
 // Array constructors are lowered with three 
diff erent strategies.
 // All strategies are not possible with all array constructors.
@@ -287,7 +287,150 @@ class AsElementalStrategy {
   hlfir::ElementalOp elementalOp{};
 };
 
-// TODO: add and implement RuntimeTempStrategy.
+/// Class that implements the "runtime temp strategy" to lower array
+/// constructors.
+class RuntimeTempStrategy {
+  /// Name that will be given to the temporary allocation and hlfir.declare in
+  /// the IR.
+  static constexpr char tempName[] = ".tmp.arrayctor";
+
+public:
+  /// Start lowering an array constructor according to the runtime strategy.
+  /// The temporary is only created if the extents and length parameters are
+  /// already known. Otherwise, the handling of the allocation (and
+  /// reallocation) is left up to the runtime.
+  /// \p extent is the pre-computed extent of the array constructor, if it could
+  /// be pre-computed. It is std::nullopt otherwise.
+  /// \p lengths are the pre-computed length parameters of the array
+  /// constructor, if they could be precomputed. \p missingLengthParameters is
+  /// set to true if the length parameters could not be precomputed.
+  RuntimeTempStrategy(mlir::Location loc, fir::FirOpBuilder &builder,
+                      fir::SequenceType declaredType,
+                      std::optional<mlir::Value> extent,
+                      llvm::ArrayRef<mlir::Value> lengths,
+                      bool missingLengthParameters)
+      : arrayConstructorElementType{declaredType.getEleTy()} {
+    mlir::Type heapType = fir::HeapType::get(declaredType);
+    mlir::Type boxType = fir::BoxType::get(heapType);
+    allocatableTemp = builder.createTemporary(loc, boxType, tempName);
+    mlir::Value initialBoxValue;
+    if (extent && !missingLengthParameters) {
+      llvm::SmallVector<mlir::Value, 1> extents{*extent};
+      mlir::Value tempStorage = builder.createHeapTemporary(
+          loc, declaredType, tempName, extents, lengths);
+      mlir::Value shape = builder.genShape(loc, extents);
+      declare = builder.create<hlfir::DeclareOp>(
+          loc, tempStorage, tempName, shape, lengths,
+          fir::FortranVariableFlagsAttr{});
+      initialBoxValue =
+          builder.createBox(loc, boxType, declare->getOriginalBase(), shape,
+                            /*slice=*/mlir::Value{}, lengths, /*tdesc=*/{});
+    } else {
+      // The runtime will have to do the initial allocation.
+      // The declare operation cannot be emitted in this case since the final
+      // array constructor has not yet been allocated. Instead, the resulting
+      // temporary variable will be extracted from the allocatable descriptor
+      // after all the API calls.
+      // Prepare the initial state of the allocatable descriptor with a
+      // deallocated status and all the available knowledge about the extent
+      // and length parameters.
+      llvm::SmallVector<mlir::Value> emboxLengths(lengths.begin(),
+                                                  lengths.end());
+      if (!extent)
+        extent = builder.createIntegerConstant(loc, builder.getIndexType(), 0);
+      if (missingLengthParameters) {
+        if (declaredType.getEleTy().isa<fir::CharacterType>())
+          emboxLengths.push_back(builder.createIntegerConstant(
+              loc, builder.getCharacterLengthType(), 0));
+        else
+          TODO(loc,
+               "parametrized derived type array constructor without type-spec");
+      }
+      mlir::Value nullAddr = builder.createNullConstant(loc, heapType);
+      mlir::Value shape = builder.genShape(loc, {*extent});
+      initialBoxValue = builder.createBox(loc, boxType, nullAddr, shape,
+                                          /*slice=*/mlir::Value{}, emboxLengths,
+                                          /*tdesc=*/{});
+    }
+    builder.create<fir::StoreOp>(loc, initialBoxValue, allocatableTemp);
+    arrayConstructorVector = fir::runtime::genInitArrayConstructorVector(
+        loc, builder, allocatableTemp,
+        builder.createBool(loc, missingLengthParameters));
+  }
+
+  bool useSimplePushRuntime(hlfir::Entity value) {
+    return value.isScalar() &&
+           !arrayConstructorElementType.isa<fir::CharacterType>() &&
+           !fir::isRecordWithAllocatableMember(arrayConstructorElementType) &&
+           !fir::isRecordWithTypeParameters(arrayConstructorElementType);
+  }
+
+  /// Push a lowered ac-value into the array constructor vector using
+  /// the runtime API.
+  void pushValue(mlir::Location loc, fir::FirOpBuilder &builder,
+                 hlfir::Entity value) {
+    if (useSimplePushRuntime(value)) {
+      auto [addrExv, cleanUp] = hlfir::convertToAddress(
+          loc, builder, value, arrayConstructorElementType);
+      mlir::Value addr = fir::getBase(addrExv);
+      if (addr.getType().isa<fir::BaseBoxType>())
+        addr = builder.create<fir::BoxAddrOp>(loc, addr);
+      fir::runtime::genPushArrayConstructorSimpleScalar(
+          loc, builder, arrayConstructorVector, addr);
+      if (cleanUp)
+        (*cleanUp)();
+      return;
+    }
+    auto [boxExv, cleanUp] =
+        hlfir::convertToBox(loc, builder, value, arrayConstructorElementType);
+    fir::runtime::genPushArrayConstructorValue(
+        loc, builder, arrayConstructorVector, fir::getBase(boxExv));
+    if (cleanUp)
+      (*cleanUp)();
+  }
+
+  /// 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.
+  mlir::Value startImpliedDo(mlir::Location loc, fir::FirOpBuilder &builder,
+                             mlir::Value lower, mlir::Value upper,
+                             mlir::Value stride) {
+    auto loop = builder.create<fir::DoLoopOp>(loc, lower, upper, stride,
+                                              /*unordered=*/false,
+                                              /*finalCount=*/false);
+    builder.setInsertionPointToStart(loop.getBody());
+    return loop.getInductionVar();
+  }
+
+  /// Move the temporary to an hlfir.expr value (array constructors are not
+  /// variables and cannot be further modified).
+  hlfir::Entity finishArrayCtorLowering(mlir::Location loc,
+                                        fir::FirOpBuilder &builder) {
+    // Temp is created using createHeapTemporary, or allocated on the heap
+    // by the runtime.
+    mlir::Value mustFree = builder.createBool(loc, true);
+    mlir::Value temp;
+    if (declare)
+      temp = declare->getBase();
+    else
+      temp = hlfir::derefPointersAndAllocatables(
+          loc, builder, hlfir::Entity{allocatableTemp});
+    auto hlfirExpr = builder.create<hlfir::AsExprOp>(loc, temp, mustFree);
+    return hlfir::Entity{hlfirExpr};
+  }
+
+private:
+  /// Element type of the array constructor being built.
+  mlir::Type arrayConstructorElementType;
+  /// Allocatable descriptor for the storage of the array constructor being
+  /// built.
+  mlir::Value allocatableTemp;
+  /// Structure that allows the runtime API to maintain the status of
+  /// of the array constructor being built between two API calls.
+  mlir::Value arrayConstructorVector;
+  /// DeclareOp for the array constructor storage, if it was possible to
+  /// allocate it before any API calls.
+  std::optional<hlfir::DeclareOp> declare;
+};
 
 /// Wrapper class that dispatch to the selected array constructor lowering
 /// strategy and does nothing else.
@@ -322,7 +465,7 @@ class ArrayCtorLoweringStrategy {
 
 private:
   std::variant<InlinedTempStrategy, LooplessInlinedTempStrategy,
-               AsElementalStrategy>
+               AsElementalStrategy, RuntimeTempStrategy>
       implVariant;
 };
 } // namespace
@@ -382,9 +525,8 @@ struct LengthAndTypeCollector<Character<Kind>> {
 /// Does the array constructor have length parameters that
 /// LengthAndTypeCollector::collect could not lower because this requires
 /// lowering an ac-value and must be delayed?
-static bool
-failedToGatherLengthParameters(mlir::Type elementType,
-                               llvm::ArrayRef<mlir::Value> lengths) {
+static bool missingLengthParameters(mlir::Type elementType,
+                                    llvm::ArrayRef<mlir::Value> lengths) {
   return (elementType.isa<fir::CharacterType>() ||
           fir::isRecordWithTypeParameters(elementType)) &&
          lengths.empty();
@@ -505,8 +647,8 @@ static ArrayCtorLoweringStrategy selectArrayCtorLoweringStrategy(
   // Try to gather the array constructor extent.
   mlir::Value extent;
   fir::SequenceType::Extent typeExtent = fir::SequenceType::getUnknownExtent();
-  auto shapeExpr =
-      Fortran::evaluate::GetShape(converter.getFoldingContext(), arrayCtorExpr);
+  auto shapeExpr = Fortran::evaluate::GetContextFreeShape(
+      converter.getFoldingContext(), arrayCtorExpr);
   if (shapeExpr && shapeExpr->size() == 1 && (*shapeExpr)[0]) {
     const Fortran::evaluate::ExtentExpr &extentExpr = *(*shapeExpr)[0];
     if (auto constantExtent = Fortran::evaluate::ToInt64(extentExpr)) {
@@ -531,15 +673,17 @@ static ArrayCtorLoweringStrategy selectArrayCtorLoweringStrategy(
   // Run an analysis of the array constructor ac-value.
   ArrayCtorAnalysis analysis(converter.getFoldingContext(), arrayCtorExpr);
   bool needToEvaluateOneExprToGetLengthParameters =
-      failedToGatherLengthParameters(elementType, lengths);
+      missingLengthParameters(elementType, lengths);
+  auto declaredType = fir::SequenceType::get({typeExtent}, elementType);
 
   // Based on what was gathered and the result of the analysis, select and
   // instantiate the right lowering strategy for the array constructor.
   if (!extent || needToEvaluateOneExprToGetLengthParameters ||
       analysis.anyArrayExpr)
-    TODO(loc, "Lowering of array constructor requiring the runtime");
-
-  auto declaredType = fir::SequenceType::get({typeExtent}, elementType);
+    return RuntimeTempStrategy(
+        loc, builder, declaredType,
+        extent ? std::optional<mlir::Value>(extent) : std::nullopt, lengths,
+        needToEvaluateOneExprToGetLengthParameters);
   // Note: array constructors containing impure ac-value expr are currently not
   // rewritten to hlfir.elemental because impure expressions should be evaluated
   // in order, and hlfir.elemental currently misses a way to indicate that.
@@ -562,8 +706,6 @@ static void genAcValue(mlir::Location loc,
                        Fortran::lower::SymMap &symMap,
                        Fortran::lower::StatementContext &stmtCtx,
                        ArrayCtorLoweringStrategy &arrayBuilder) {
-  if (expr.Rank() != 0)
-    TODO(loc, "array constructor with array ac-value in HLFIR");
   // TODO: get rid of the toEvExpr indirection.
   fir::FirOpBuilder &builder = converter.getFirOpBuilder();
   hlfir::Entity value = Fortran::lower::convertExprToHLFIR(

diff  --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt
index a682b7d783c43..5457a9e3f636a 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -11,6 +11,7 @@ add_flang_library(FIRBuilder
   LowLevelIntrinsics.cpp
   MutableBox.cpp
   Runtime/Allocatable.cpp
+  Runtime/ArrayConstructor.cpp
   Runtime/Assign.cpp
   Runtime/Character.cpp
   Runtime/Command.cpp

diff  --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
index 3cc8f6d723065..21f36a7e152cd 100644
--- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp
+++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
@@ -562,6 +562,17 @@ mlir::Value fir::FirOpBuilder::createBox(mlir::Location loc,
       });
 }
 
+mlir::Value fir::FirOpBuilder::createBox(mlir::Location loc, mlir::Type boxType,
+                                         mlir::Value addr, mlir::Value shape,
+                                         mlir::Value slice,
+                                         llvm::ArrayRef<mlir::Value> lengths,
+                                         mlir::Value tdesc) {
+  mlir::Type valueOrSequenceType = fir::unwrapPassByRefType(boxType);
+  return create<fir::EmboxOp>(
+      loc, boxType, addr, shape, slice,
+      elideLengthsAlreadyInType(valueOrSequenceType, lengths), tdesc);
+}
+
 void fir::FirOpBuilder::dumpFunc() { getFunction().dump(); }
 
 static mlir::Value

diff  --git a/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp b/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp
new file mode 100644
index 0000000000000..c786bef5cb1c4
--- /dev/null
+++ b/flang/lib/Optimizer/Builder/Runtime/ArrayConstructor.cpp
@@ -0,0 +1,80 @@
+//===- ArrayConstructor.cpp - array constructor runtime API calls ---------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Builder/Runtime/ArrayConstructor.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Runtime/array-constructor.h"
+
+using namespace Fortran::runtime;
+
+namespace fir::runtime {
+template <>
+constexpr TypeBuilderFunc
+getModel<Fortran::runtime::ArrayConstructorVector &>() {
+  return getModel<void *>();
+}
+} // namespace fir::runtime
+
+mlir::Value fir::runtime::genInitArrayConstructorVector(
+    mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value toBox,
+    mlir::Value useValueLengthParameters) {
+  // Allocate storage for the runtime cookie for the array constructor vector.
+  // Use the "host" size and alignment, but double them to be safe regardless of
+  // the target. The "cookieSize" argument is used to validate this wild
+  // assumption until runtime interfaces are improved.
+  std::size_t arrayVectorStructBitSize =
+      2 * sizeof(Fortran::runtime::ArrayConstructorVector) * 8;
+  std::size_t alignLike = alignof(Fortran::runtime::ArrayConstructorVector) * 8;
+  fir::SequenceType::Extent numElem =
+      (arrayVectorStructBitSize + alignLike - 1) / alignLike;
+  mlir::Type intType = builder.getIntegerType(alignLike);
+  mlir::Type seqType = fir::SequenceType::get({numElem}, intType);
+  mlir::Value cookie =
+      builder.createTemporary(loc, seqType, ".rt.arrayctor.vector");
+
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(InitArrayConstructorVector)>(
+          loc, builder);
+  mlir::FunctionType funcType = func.getFunctionType();
+  cookie = builder.createConvert(loc, funcType.getInput(0), cookie);
+  mlir::Value cookieSize = builder.createIntegerConstant(
+      loc, funcType.getInput(3), numElem * alignLike / 8);
+  mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
+  mlir::Value sourceLine =
+      fir::factory::locationToLineNo(builder, loc, funcType.getInput(5));
+  auto args = fir::runtime::createArguments(builder, loc, funcType, cookie,
+                                            toBox, useValueLengthParameters,
+                                            cookieSize, sourceFile, sourceLine);
+  builder.create<fir::CallOp>(loc, func, args);
+  return cookie;
+}
+
+void fir::runtime::genPushArrayConstructorValue(
+    mlir::Location loc, fir::FirOpBuilder &builder,
+    mlir::Value arrayConstructorVector, mlir::Value fromBox) {
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(PushArrayConstructorValue)>(loc,
+                                                                       builder);
+  mlir::FunctionType funcType = func.getFunctionType();
+  auto args = fir::runtime::createArguments(builder, loc, funcType,
+                                            arrayConstructorVector, fromBox);
+  builder.create<fir::CallOp>(loc, func, args);
+}
+
+void fir::runtime::genPushArrayConstructorSimpleScalar(
+    mlir::Location loc, fir::FirOpBuilder &builder,
+    mlir::Value arrayConstructorVector, mlir::Value fromAddress) {
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(PushArrayConstructorSimpleScalar)>(
+          loc, builder);
+  mlir::FunctionType funcType = func.getFunctionType();
+  auto args = fir::runtime::createArguments(
+      builder, loc, funcType, arrayConstructorVector, fromAddress);
+  builder.create<fir::CallOp>(loc, func, args);
+}

diff  --git a/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90 b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90
new file mode 100644
index 0000000000000..81b29e37a08d8
--- /dev/null
+++ b/flang/test/Lower/HLFIR/array-ctor-as-runtime-temp.f90
@@ -0,0 +1,158 @@
+! Test lowering of array constructors requiring runtime library help to HLFIR.
+! RUN: bbc -emit-fir -hlfir -o - %s | FileCheck %s
+module arrayctor
+contains
+
+subroutine test_loops()
+  call takes_int([((i, i=1,ifoo()), j=1,ibar())])
+end subroutine
+! CHECK-LABEL: func.func @_QMarrayctorPtest_loops() {
+! CHECK:  %[[VAL_0:.*]] = fir.alloca i32
+! CHECK:  %[[VAL_1:.*]] = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"}
+! CHECK:  %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = ".tmp.arrayctor"}
+! CHECK:  %[[VAL_3:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_4:.*]] = fir.zero_bits !fir.heap<!fir.array<?xi32>>
+! CHECK:  %[[VAL_5:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_6:.*]] = fir.embox %[[VAL_4]](%[[VAL_5]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+! CHECK:  fir.store %[[VAL_6]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK:  %[[VAL_7:.*]] = arith.constant false
+! CHECK:  %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
+! CHECK:  %[[VAL_12:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK:  %[[VAL_14:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_8]], %[[VAL_12]], %[[VAL_7]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
+! CHECK:  %[[VAL_15:.*]] = arith.constant 1 : i64
+! CHECK:  %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (i64) -> index
+! CHECK:  %[[VAL_17:.*]] = fir.call @_QMarrayctorPibar() {{.*}}: () -> i32
+! CHECK:  %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i32) -> i64
+! CHECK:  %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (i64) -> index
+! CHECK:  %[[VAL_20:.*]] = arith.constant 1 : i64
+! CHECK:  %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index
+! CHECK:  fir.do_loop %[[VAL_22:.*]] = %[[VAL_16]] to %[[VAL_19]] step %[[VAL_21]] {
+! CHECK:    %[[VAL_23:.*]] = arith.constant 1 : i64
+! CHECK:    %[[VAL_24:.*]] = fir.convert %[[VAL_23]] : (i64) -> index
+! CHECK:    %[[VAL_25:.*]] = fir.call @_QMarrayctorPifoo() {{.*}}: () -> i32
+! CHECK:    %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (i32) -> i64
+! CHECK:    %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i64) -> index
+! CHECK:    %[[VAL_28:.*]] = arith.constant 1 : i64
+! CHECK:    %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (i64) -> index
+! CHECK:    fir.do_loop %[[VAL_30:.*]] = %[[VAL_24]] to %[[VAL_27]] step %[[VAL_29]] {
+! CHECK:      %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (index) -> i32
+! CHECK:      fir.store %[[VAL_31]] to %[[VAL_0]] : !fir.ref<i32>
+! CHECK:      %[[VAL_32:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<i32>) -> !fir.llvm_ptr<i8>
+! CHECK:      %[[VAL_33:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_8]], %[[VAL_32]]) {{.*}}: (!fir.llvm_ptr<i8>, !fir.llvm_ptr<i8>) -> none
+! CHECK:    }
+! CHECK:  }
+! CHECK:  %[[VAL_34:.*]] = arith.constant true
+! CHECK:  %[[VAL_35:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK:  hlfir.as_expr %[[VAL_35]] move %[[VAL_34]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, i1) -> !hlfir.expr<?xi32>
+
+subroutine test_arrays(a)
+  integer :: a(:, :)
+  call takes_int([a, a])
+end subroutine
+! CHECK-LABEL: func.func @_QMarrayctorPtest_arrays(
+! CHECK:  %[[VAL_1:.*]] = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"}
+! CHECK:  %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = ".tmp.arrayctor"}
+! CHECK:  %[[VAL_3:.*]]:2 = hlfir.declare {{.*}}Ea"
+! CHECK:  %[[VAL_4:.*]] = arith.constant 0 : i64
+! CHECK:  %[[VAL_5:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_5]] : (!fir.box<!fir.array<?x?xi32>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#1 : (index) -> i64
+! CHECK:  %[[VAL_8:.*]] = arith.constant 1 : index
+! CHECK:  %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_8]] : (!fir.box<!fir.array<?x?xi32>>, index) -> (index, index, index)
+! CHECK:  %[[VAL_10:.*]] = fir.convert %[[VAL_9]]#1 : (index) -> i64
+! CHECK:  %[[VAL_11:.*]] = arith.muli %[[VAL_7]], %[[VAL_10]] : i64
+! CHECK:  %[[VAL_12:.*]] = arith.addi %[[VAL_4]], %[[VAL_11]] : i64
+! CHECK:  %[[VAL_20:.*]] = arith.addi %[[VAL_12]], %{{.*}} : i64
+! CHECK:  %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (i64) -> index
+! CHECK:  %[[VAL_22:.*]] = fir.allocmem !fir.array<?xi32>, %[[VAL_21]] {bindc_name = ".tmp.arrayctor", uniq_name = ""}
+! CHECK:  %[[VAL_23:.*]] = fir.shape %[[VAL_21]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_22]](%[[VAL_23]]) {uniq_name = ".tmp.arrayctor"} : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xi32>>, !fir.heap<!fir.array<?xi32>>)
+! CHECK:  %[[VAL_25:.*]] = fir.embox %[[VAL_24]]#1(%[[VAL_23]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+! CHECK:  fir.store %[[VAL_25]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK:  %[[VAL_26:.*]] = arith.constant false
+! CHECK:  %[[VAL_27:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
+! CHECK:  %[[VAL_31:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK:  %[[VAL_33:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_27]], %[[VAL_31]], %[[VAL_26]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
+! CHECK:  %[[VAL_34:.*]] = fir.convert %[[VAL_3]]#1 : (!fir.box<!fir.array<?x?xi32>>) -> !fir.box<none>
+! CHECK:  %[[VAL_35:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_27]], %[[VAL_34]]) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
+! CHECK:  %[[VAL_36:.*]] = fir.convert %[[VAL_3]]#1 : (!fir.box<!fir.array<?x?xi32>>) -> !fir.box<none>
+! CHECK:  %[[VAL_37:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_27]], %[[VAL_36]]) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
+! CHECK:  %[[VAL_38:.*]] = arith.constant true
+! CHECK:  hlfir.as_expr %[[VAL_24]]#0 move %[[VAL_38]] : (!fir.box<!fir.array<?xi32>>, i1) -> !hlfir.expr<?xi32>
+
+subroutine test_arrays_unpredictable_size()
+  call takes_int([rank1(), rank3(), rank1()])
+! CHECK-LABEL: func.func @_QMarrayctorPtest_arrays_unpredictable_size() {
+! CHECK:  %[[VAL_3:.*]] = fir.alloca !fir.array<10xi64> {bindc_name = ".rt.arrayctor.vector"}
+! CHECK:  %[[VAL_4:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = ".tmp.arrayctor"}
+! CHECK:  %[[VAL_5:.*]] = arith.constant 0 : index
+! CHECK:  %[[VAL_6:.*]] = fir.zero_bits !fir.heap<!fir.array<?xi32>>
+! CHECK:  %[[VAL_7:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1>
+! CHECK:  %[[VAL_8:.*]] = fir.embox %[[VAL_6]](%[[VAL_7]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+! CHECK:  fir.store %[[VAL_8]] to %[[VAL_4]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK:  %[[VAL_9:.*]] = arith.constant false
+! CHECK:  %[[VAL_10:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.array<10xi64>>) -> !fir.llvm_ptr<i8>
+! CHECK:  %[[VAL_14:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK:  %[[VAL_16:.*]] = fir.call @_FortranAInitArrayConstructorVector(%[[VAL_10]], %[[VAL_14]], %[[VAL_9]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.ref<!fir.box<none>>, i1, i32, !fir.ref<i8>, i32) -> none
+! CHECK:  fir.call @_QMarrayctorPrank1() {{.*}}: () -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+! CHECK:  %[[VAL_21:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_10]], %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
+! CHECK:  fir.call @_QMarrayctorPrank3() {{.*}}: () -> !fir.box<!fir.heap<!fir.array<?x?x?xi32>>>
+! CHECK:  %[[VAL_26:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_10]], %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
+! CHECK:  fir.call @_QMarrayctorPrank1() {{.*}}: () -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+! CHECK:  %[[VAL_31:.*]] = fir.call @_FortranAPushArrayConstructorValue(%[[VAL_10]], %{{.*}}) {{.*}}: (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
+! CHECK:  %[[VAL_32:.*]] = arith.constant true
+! CHECK:  %[[VAL_33:.*]] = fir.load %[[VAL_4]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+! CHECK:  hlfir.as_expr %[[VAL_33]] move %[[VAL_32]] : (!fir.box<!fir.heap<!fir.array<?xi32>>>, i1) -> !hlfir.expr<?xi32>
+end subroutine
+
+
+! End to to end test implementation
+function rank1()
+  integer, save :: counter = 2
+  integer, allocatable :: rank1(:)
+  allocate(rank1(counter))
+  do i=1,counter
+    rank1(i)=i
+  end do
+  counter = counter +1
+end function
+function rank3()
+  integer, save :: counter = 1
+  integer, allocatable :: rank3(:, :, :)
+  allocate(rank3(counter, counter+1, counter+2))
+  do k=1,counter+2
+    do j=1,counter+1
+      do i=1,counter
+        rank3(i, j, k)=i+(j-1)*counter+(k-1)*counter*(counter+1)
+      end do
+    end do
+  end do
+  counter = counter+1
+end function
+
+function ifoo()
+  integer, save :: counter = 0
+  ifoo = counter
+  counter = counter +1
+end function
+
+function ibar()
+  ibar = 6
+end function
+
+
+subroutine takes_int(a)
+  integer :: a(:)
+  print *, "got   :", a
+end subroutine
+end module
+
+  use arrayctor
+  integer :: a(2,3) = reshape([1,2,3,4,5,6], shape=[2,3])
+  print *, "expect: 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5"
+  call test_loops()
+  print *, "expect: 1 2 3 4 5 6 1 2 3 4 5 6"
+  call test_arrays(a)
+  print *, "expect: 1 2 1 2 3 4 5 6 1 2 3"
+  call test_arrays_unpredictable_size()
+end


        


More information about the flang-commits mailing list