[flang-commits] [flang] f3c3f63 - [flang][hlfir] Generate temporary storage in Forall/Where [2/2]

Jean Perier via flang-commits flang-commits at lists.llvm.org
Thu May 25 02:57:22 PDT 2023


Author: Jean Perier
Date: 2023-05-25T11:56:29+02:00
New Revision: f3c3f63672a0a58c46d7cde00979bfdb3a83038b

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

LOG: [flang][hlfir] Generate temporary storage in Forall/Where [2/2]

Generate temporary storage inside WHERE and FORALL using the temporary
stack runtime. This covers all cases outside of LHS temporary, where the
descriptor stack will have to be used.

Reviewed By: vzakhari

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

Added: 
    flang/include/flang/Optimizer/Builder/Runtime/TemporaryStack.h
    flang/lib/Optimizer/Builder/Runtime/TemporaryStack.cpp
    flang/test/HLFIR/order_assignments/runtime-stack-temp.fir

Modified: 
    flang/include/flang/Optimizer/Builder/HLFIRTools.h
    flang/include/flang/Optimizer/Builder/TemporaryStorage.h
    flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
    flang/lib/Optimizer/Builder/CMakeLists.txt
    flang/lib/Optimizer/Builder/TemporaryStorage.cpp
    flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
index fc03a1e06e886..d20cdf76a1e73 100644
--- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h
+++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
@@ -112,11 +112,7 @@ class Entity : public mlir::Value {
   }
   bool isScalar() const { return !isArray(); }
 
-  bool isPolymorphic() const {
-    if (auto exprType = getType().dyn_cast<hlfir::ExprType>())
-      return exprType.isPolymorphic();
-    return fir::isPolymorphicType(getType());
-  }
+  bool isPolymorphic() const { return hlfir::isPolymorphicType(getType()); }
 
   mlir::Type getFortranElementType() const {
     return hlfir::getFortranElementType(getType());

diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/TemporaryStack.h b/flang/include/flang/Optimizer/Builder/Runtime/TemporaryStack.h
new file mode 100644
index 0000000000000..b35d6d6d66ec4
--- /dev/null
+++ b/flang/include/flang/Optimizer/Builder/Runtime/TemporaryStack.h
@@ -0,0 +1,34 @@
+//===- TemporaryStack.h --- temporary stack 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_TEMPORARYSTACK_H
+#define FORTRAN_OPTIMIZER_BUILDER_RUNTIME_TEMPORARYSTACK_H
+
+namespace mlir {
+class Value;
+class Location;
+} // namespace mlir
+
+namespace fir {
+class FirOpBuilder;
+}
+
+namespace fir::runtime {
+
+mlir::Value genCreateValueStack(mlir::Location loc, fir::FirOpBuilder &builder);
+
+void genPushValue(mlir::Location loc, fir::FirOpBuilder &builder,
+                  mlir::Value opaquePtr, mlir::Value boxValue);
+void genValueAt(mlir::Location loc, fir::FirOpBuilder &builder,
+                mlir::Value opaquePtr, mlir::Value i, mlir::Value retValueBox);
+
+void genDestroyValueStack(mlir::Location loc, fir::FirOpBuilder &builder,
+                          mlir::Value opaquePtr);
+
+} // namespace fir::runtime
+#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_TEMPORARYSTACK_H

diff  --git a/flang/include/flang/Optimizer/Builder/TemporaryStorage.h b/flang/include/flang/Optimizer/Builder/TemporaryStorage.h
index 88bf4af382724..b9e3f0ec9591e 100644
--- a/flang/include/flang/Optimizer/Builder/TemporaryStorage.h
+++ b/flang/include/flang/Optimizer/Builder/TemporaryStorage.h
@@ -115,6 +115,35 @@ class SimpleCopy {
   hlfir::AssociateOp copy;
 };
 
+/// Data structure to stack any kind of values with the same static type and
+/// rank. Each value may have 
diff erent type parameters, bounds, and dynamic
+/// type. Fetching value N will return a value with the same dynamic type,
+/// bounds, and type parameters as the Nth value that was pushed. It is
+/// implemented using runtime.
+class AnyValueStack {
+public:
+  AnyValueStack(mlir::Location loc, fir::FirOpBuilder &builder,
+                mlir::Type valueStaticType);
+
+  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);
+
+private:
+  /// Keep the original value type. Values may be stored by the runtime
+  /// with a 
diff erent type (i1 cannot be passed by descriptor).
+  mlir::Type valueStaticType;
+  /// Runtime cookie created by the runtime. It is a pointer to an opaque
+  /// runtime data structure that manages the stack.
+  mlir::Value opaquePtr;
+  /// Counter to keep track of the fetching position.
+  Counter counter;
+  /// Allocatable box passed to the runtime when fetching the values.
+  mlir::Value retValueBox;
+};
+
 /// Generic wrapper over the 
diff erent sorts of temporary storages.
 class TemporaryStorage {
 public:
@@ -138,7 +167,7 @@ class TemporaryStorage {
   }
 
 private:
-  std::variant<HomogeneousScalarStack, SimpleCopy> impl;
+  std::variant<HomogeneousScalarStack, SimpleCopy, AnyValueStack> impl;
 };
 } // namespace fir::factory
 #endif // FORTRAN_OPTIMIZER_BUILDER_TEMPORARYSTORAGE_H

diff  --git a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
index 0ccab339fa958..8e3a5dd9c24b3 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
@@ -69,6 +69,12 @@ inline bool isBoxAddressOrValueType(mlir::Type type) {
   return fir::unwrapRefType(type).isa<fir::BaseBoxType>();
 }
 
+inline bool isPolymorphicType(mlir::Type type) {
+  if (auto exprType = type.dyn_cast<hlfir::ExprType>())
+    return exprType.isPolymorphic();
+  return fir::isPolymorphicType(type);
+}
+
 bool isFortranScalarNumericalType(mlir::Type);
 bool isFortranNumericalArrayObject(mlir::Type);
 bool isFortranNumericalOrLogicalArrayObject(mlir::Type);

diff  --git a/flang/lib/Optimizer/Builder/CMakeLists.txt b/flang/lib/Optimizer/Builder/CMakeLists.txt
index 66e9499b3c05a..683aeef540d65 100644
--- a/flang/lib/Optimizer/Builder/CMakeLists.txt
+++ b/flang/lib/Optimizer/Builder/CMakeLists.txt
@@ -23,6 +23,7 @@ add_flang_library(FIRBuilder
   Runtime/Ragged.cpp
   Runtime/Reduction.cpp
   Runtime/Stop.cpp
+  Runtime/TemporaryStack.cpp
   Runtime/Transformational.cpp
   TemporaryStorage.cpp
 

diff  --git a/flang/lib/Optimizer/Builder/Runtime/TemporaryStack.cpp b/flang/lib/Optimizer/Builder/Runtime/TemporaryStack.cpp
new file mode 100644
index 0000000000000..f184e4040b1d3
--- /dev/null
+++ b/flang/lib/Optimizer/Builder/Runtime/TemporaryStack.cpp
@@ -0,0 +1,58 @@
+//===- TemporaryStack.cpp ---- temporary stack 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/TemporaryStack.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
+#include "flang/Optimizer/Builder/Runtime/RTBuilder.h"
+#include "flang/Runtime/temporary-stack.h"
+
+using namespace Fortran::runtime;
+
+mlir::Value fir::runtime::genCreateValueStack(mlir::Location loc,
+                                              fir::FirOpBuilder &builder) {
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(CreateValueStack)>(loc, builder);
+  mlir::FunctionType funcType = func.getFunctionType();
+  mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
+  mlir::Value sourceLine =
+      fir::factory::locationToLineNo(builder, loc, funcType.getInput(1));
+  auto args = fir::runtime::createArguments(builder, loc, funcType, sourceFile,
+                                            sourceLine);
+  return builder.create<fir::CallOp>(loc, func, args).getResult(0);
+}
+
+void fir::runtime::genPushValue(mlir::Location loc, fir::FirOpBuilder &builder,
+                                mlir::Value opaquePtr, mlir::Value boxValue) {
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(PushValue)>(loc, builder);
+  mlir::FunctionType funcType = func.getFunctionType();
+  auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr,
+                                            boxValue);
+  builder.create<fir::CallOp>(loc, func, args);
+}
+
+void fir::runtime::genValueAt(mlir::Location loc, fir::FirOpBuilder &builder,
+                              mlir::Value opaquePtr, mlir::Value i,
+                              mlir::Value retValueBox) {
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(ValueAt)>(loc, builder);
+  mlir::FunctionType funcType = func.getFunctionType();
+  auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr,
+                                            i, retValueBox);
+  builder.create<fir::CallOp>(loc, func, args);
+}
+
+void fir::runtime::genDestroyValueStack(mlir::Location loc,
+                                        fir::FirOpBuilder &builder,
+                                        mlir::Value opaquePtr) {
+  mlir::func::FuncOp func =
+      fir::runtime::getRuntimeFunc<mkRTKey(DestroyValueStack)>(loc, builder);
+  mlir::FunctionType funcType = func.getFunctionType();
+  auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr);
+  builder.create<fir::CallOp>(loc, func, args);
+}

diff  --git a/flang/lib/Optimizer/Builder/TemporaryStorage.cpp b/flang/lib/Optimizer/Builder/TemporaryStorage.cpp
index b4e01556af086..362344a34980a 100644
--- a/flang/lib/Optimizer/Builder/TemporaryStorage.cpp
+++ b/flang/lib/Optimizer/Builder/TemporaryStorage.cpp
@@ -12,6 +12,7 @@
 #include "flang/Optimizer/Builder/TemporaryStorage.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/HLFIRTools.h"
+#include "flang/Optimizer/Builder/Runtime/TemporaryStack.h"
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Optimizer/HLFIR/HLFIROps.h"
 
@@ -154,3 +155,69 @@ void fir::factory::SimpleCopy::destroy(mlir::Location loc,
                                        fir::FirOpBuilder &builder) {
   builder.create<hlfir::EndAssociateOp>(loc, copy);
 }
+
+//===----------------------------------------------------------------------===//
+// fir::factory::AnyValueStack implementation.
+//===----------------------------------------------------------------------===//
+
+fir::factory::AnyValueStack::AnyValueStack(mlir::Location loc,
+                                           fir::FirOpBuilder &builder,
+                                           mlir::Type valueStaticType)
+    : valueStaticType{valueStaticType},
+      counter{loc, builder,
+              builder.createIntegerConstant(loc, builder.getI64Type(), 0),
+              /*stackThroughLoops=*/true} {
+  opaquePtr = fir::runtime::genCreateValueStack(loc, builder);
+  // Compute the storage type. I1 are stored as fir.logical<1>. This is required
+  // to use descriptor.
+  mlir::Type storageType =
+      hlfir::getFortranElementOrSequenceType(valueStaticType);
+  mlir::Type i1Type = builder.getI1Type();
+  if (storageType == i1Type)
+    storageType = fir::LogicalType::get(builder.getContext(), 1);
+  assert(hlfir::getFortranElementType(storageType) != i1Type &&
+         "array of i1 should not be used");
+  mlir::Type heapType = fir::HeapType::get(storageType);
+  mlir::Type boxType;
+  if (hlfir::isPolymorphicType(valueStaticType))
+    boxType = fir::ClassType::get(heapType);
+  else
+    boxType = fir::BoxType::get(heapType);
+  retValueBox = builder.createTemporary(loc, boxType);
+}
+
+void fir::factory::AnyValueStack::pushValue(mlir::Location loc,
+                                            fir::FirOpBuilder &builder,
+                                            mlir::Value value) {
+  hlfir::Entity entity{value};
+  mlir::Type storageElementType =
+      hlfir::getFortranElementType(retValueBox.getType());
+  auto [box, maybeCleanUp] =
+      hlfir::convertToBox(loc, builder, entity, storageElementType);
+  fir::runtime::genPushValue(loc, builder, opaquePtr, fir::getBase(box));
+  if (maybeCleanUp)
+    (*maybeCleanUp)();
+}
+
+void fir::factory::AnyValueStack::resetFetchPosition(
+    mlir::Location loc, fir::FirOpBuilder &builder) {
+  counter.reset(loc, builder);
+}
+
+mlir::Value fir::factory::AnyValueStack::fetch(mlir::Location loc,
+                                               fir::FirOpBuilder &builder) {
+  mlir::Value indexValue = counter.getAndIncrementIndex(loc, builder);
+  fir::runtime::genValueAt(loc, builder, opaquePtr, indexValue, retValueBox);
+  /// Dereference the allocatable "retValueBox", and load if trivial scalar
+  /// value.
+  mlir::Value result =
+      hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{retValueBox});
+  if (valueStaticType == builder.getI1Type())
+    return builder.createConvert(loc, valueStaticType, result);
+  return result;
+}
+
+void fir::factory::AnyValueStack::destroy(mlir::Location loc,
+                                          fir::FirOpBuilder &builder) {
+  fir::runtime::genDestroyValueStack(loc, builder, opaquePtr);
+}

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp
index 1ec3aca640cb4..2c86f3499b957 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIROrderedAssignments.cpp
@@ -895,7 +895,8 @@ void OrderedAssignmentRewriter::generateSaveEntity(
         // iterations are values that may have 
diff erent shape, type parameters
         // or dynamic type, use the runtime to create and manage a stack-like
         // temporary.
-        TODO(loc, "use runtime to create temporary storage in FORALL or WHERE");
+        temp = insertSavedEntity(
+            region, fir::factory::AnyValueStack{loc, builder, entityType});
       }
     });
     // Inside the loop nest (and any fir.if if there are active masks), copy

diff  --git a/flang/test/HLFIR/order_assignments/runtime-stack-temp.fir b/flang/test/HLFIR/order_assignments/runtime-stack-temp.fir
new file mode 100644
index 0000000000000..aa334c5ac56cf
--- /dev/null
+++ b/flang/test/HLFIR/order_assignments/runtime-stack-temp.fir
@@ -0,0 +1,179 @@
+// Test code generation of hlfir.forall and hlfir.where when temporary
+// storage is needed and requires a runtime managed stack.
+// RUN: fir-opt %s --lower-hlfir-ordered-assignments | FileCheck %s
+
+func.func @test_runtime_stack(%arg0: !fir.box<!fir.array<?xi32>>, %n: !fir.ref<i32>) {
+  %c1 = arith.constant 1 : index
+  %c0 = arith.constant 0 : index
+  %c-1 = arith.constant -1 : index
+  %c99_i32 = arith.constant 99 : i32
+  %c100_i32 = arith.constant 100 : i32
+  %c1_i32 = arith.constant 1 : i32
+  %1:2 = hlfir.declare %n {uniq_name = "n"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+  %2:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+  %3 = fir.load %1#1 : !fir.ref<i32>
+  hlfir.forall lb {
+    hlfir.yield %c1_i32 : i32
+  } ub {
+    hlfir.yield %c100_i32 : i32
+  } step {
+    hlfir.yield %3 : i32
+  }  (%arg1: i32) {
+    hlfir.region_assign {
+      %4 = arith.subi %c100_i32, %arg1 : i32
+      %5 = arith.subi %c99_i32, %arg1 : i32
+      %6 = fir.load %1#0 : !fir.ref<i32>
+      %7 = arith.subi %5, %6 : i32
+      %8 = fir.convert %4 : (i32) -> index
+      %9 = fir.convert %7 : (i32) -> index
+      %10 = arith.subi %9, %8 : index
+      %11 = arith.addi %10, %c-1 : index
+      %12 = arith.divsi %11, %c-1 : index
+      %13 = arith.cmpi sgt, %12, %c0 : index
+      %14 = arith.select %13, %12, %c0 : index
+      %15 = fir.shape %14 : (index) -> !fir.shape<1>
+      %16 = hlfir.designate %2#0 (%8:%9:%c-1)  shape %15 : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
+      hlfir.yield %16 : !fir.box<!fir.array<?xi32>>
+    } to {
+      %4 = fir.load %1#0 : !fir.ref<i32>
+      %5 = arith.addi %arg1, %4 : i32
+      %6 = arith.subi %5, %c1_i32 : i32
+      %7 = fir.convert %arg1 : (i32) -> index
+      %8 = fir.convert %6 : (i32) -> index
+      %9 = arith.subi %8, %7 : index
+      %10 = arith.addi %9, %c1 : index
+      %11 = arith.cmpi sgt, %10, %c0 : index
+      %12 = arith.select %11, %10, %c0 : index
+      %13 = fir.shape %12 : (index) -> !fir.shape<1>
+      %14 = hlfir.designate %2#0 (%7:%8:%c1)  shape %13 : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
+      hlfir.yield %14 : !fir.box<!fir.array<?xi32>>
+    }
+  }
+  return
+}
+
+// CHECK-LABEL:   func.func @test_runtime_stack(
+// CHECK-SAME:                                  %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>,
+// CHECK-SAME:                                  %[[VAL_1:.*]]: !fir.ref<i32>) {
+// CHECK:           %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>>
+// CHECK:           %[[VAL_3:.*]] = fir.alloca i64
+// CHECK:           %[[VAL_4:.*]] = arith.constant 1 : index
+// CHECK:           %[[VAL_5:.*]] = arith.constant 0 : index
+// CHECK:           %[[VAL_6:.*]] = arith.constant -1 : index
+// CHECK:           %[[VAL_7:.*]] = arith.constant 99 : i32
+// CHECK:           %[[VAL_8:.*]] = arith.constant 100 : i32
+// CHECK:           %[[VAL_9:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "n"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+// CHECK:           %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+// CHECK:           %[[VAL_12:.*]] = fir.load %[[VAL_10]]#1 : !fir.ref<i32>
+// CHECK:           %[[VAL_13:.*]] = fir.convert %[[VAL_9]] : (i32) -> index
+// CHECK:           %[[VAL_14:.*]] = fir.convert %[[VAL_8]] : (i32) -> index
+// CHECK:           %[[VAL_15:.*]] = fir.convert %[[VAL_12]] : (i32) -> index
+// CHECK:           %[[VAL_16:.*]] = arith.constant 0 : i64
+// CHECK:           %[[VAL_17:.*]] = arith.constant 1 : i64
+// CHECK:           fir.store %[[VAL_16]] to %[[VAL_3]] : !fir.ref<i64>
+// CHECK:           %[[VAL_22:.*]] = fir.call @_FortranACreateValueStack(%{{.*}}, %{{.*}}) : (!fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
+// CHECK:           fir.do_loop %[[VAL_23:.*]] = %[[VAL_13]] to %[[VAL_14]] step %[[VAL_15]] {
+// CHECK:             %[[VAL_24:.*]] = fir.convert %[[VAL_23]] : (index) -> i32
+// CHECK:             %[[VAL_25:.*]] = arith.subi %[[VAL_8]], %[[VAL_24]] : i32
+// CHECK:             %[[VAL_26:.*]] = arith.subi %[[VAL_7]], %[[VAL_24]] : i32
+// CHECK:             %[[VAL_27:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref<i32>
+// CHECK:             %[[VAL_28:.*]] = arith.subi %[[VAL_26]], %[[VAL_27]] : i32
+// CHECK:             %[[VAL_29:.*]] = fir.convert %[[VAL_25]] : (i32) -> index
+// CHECK:             %[[VAL_30:.*]] = fir.convert %[[VAL_28]] : (i32) -> index
+// CHECK:             %[[VAL_31:.*]] = arith.subi %[[VAL_30]], %[[VAL_29]] : index
+// CHECK:             %[[VAL_32:.*]] = arith.addi %[[VAL_31]], %[[VAL_6]] : index
+// CHECK:             %[[VAL_33:.*]] = arith.divsi %[[VAL_32]], %[[VAL_6]] : index
+// CHECK:             %[[VAL_34:.*]] = arith.cmpi sgt, %[[VAL_33]], %[[VAL_5]] : index
+// CHECK:             %[[VAL_35:.*]] = arith.select %[[VAL_34]], %[[VAL_33]], %[[VAL_5]] : index
+// CHECK:             %[[VAL_36:.*]] = fir.shape %[[VAL_35]] : (index) -> !fir.shape<1>
+// CHECK:             %[[VAL_37:.*]] = hlfir.designate %[[VAL_11]]#0 (%[[VAL_29]]:%[[VAL_30]]:%[[VAL_6]])  shape %[[VAL_36]] : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
+// CHECK:             %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
+// CHECK:             %[[VAL_39:.*]] = fir.call @_FortranAPushValue(%[[VAL_22]], %[[VAL_38]]) : (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
+// CHECK:           }
+// CHECK:           %[[VAL_40:.*]] = fir.convert %[[VAL_9]] : (i32) -> index
+// CHECK:           %[[VAL_41:.*]] = fir.convert %[[VAL_8]] : (i32) -> index
+// CHECK:           %[[VAL_42:.*]] = fir.convert %[[VAL_12]] : (i32) -> index
+// CHECK:           fir.store %[[VAL_16]] to %[[VAL_3]] : !fir.ref<i64>
+// CHECK:           fir.do_loop %[[VAL_43:.*]] = %[[VAL_40]] to %[[VAL_41]] step %[[VAL_42]] {
+// CHECK:             %[[VAL_44:.*]] = fir.convert %[[VAL_43]] : (index) -> i32
+// CHECK:             %[[VAL_45:.*]] = fir.load %[[VAL_3]] : !fir.ref<i64>
+// CHECK:             %[[VAL_46:.*]] = arith.addi %[[VAL_45]], %[[VAL_17]] : i64
+// CHECK:             fir.store %[[VAL_46]] to %[[VAL_3]] : !fir.ref<i64>
+// CHECK:             %[[VAL_47:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+// CHECK:             %[[VAL_48:.*]] = fir.call @_FortranAValueAt(%[[VAL_22]], %[[VAL_45]], %[[VAL_47]]) : (!fir.llvm_ptr<i8>, i64, !fir.ref<!fir.box<none>>) -> none
+// CHECK:             %[[VAL_49:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+// CHECK:             %[[VAL_50:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref<i32>
+// CHECK:             %[[VAL_51:.*]] = arith.addi %[[VAL_44]], %[[VAL_50]] : i32
+// CHECK:             %[[VAL_52:.*]] = arith.subi %[[VAL_51]], %[[VAL_9]] : i32
+// CHECK:             %[[VAL_53:.*]] = fir.convert %[[VAL_44]] : (i32) -> index
+// CHECK:             %[[VAL_54:.*]] = fir.convert %[[VAL_52]] : (i32) -> index
+// CHECK:             %[[VAL_55:.*]] = arith.subi %[[VAL_54]], %[[VAL_53]] : index
+// CHECK:             %[[VAL_56:.*]] = arith.addi %[[VAL_55]], %[[VAL_4]] : index
+// CHECK:             %[[VAL_57:.*]] = arith.cmpi sgt, %[[VAL_56]], %[[VAL_5]] : index
+// CHECK:             %[[VAL_58:.*]] = arith.select %[[VAL_57]], %[[VAL_56]], %[[VAL_5]] : index
+// CHECK:             %[[VAL_59:.*]] = fir.shape %[[VAL_58]] : (index) -> !fir.shape<1>
+// CHECK:             %[[VAL_60:.*]] = hlfir.designate %[[VAL_11]]#0 (%[[VAL_53]]:%[[VAL_54]]:%[[VAL_4]])  shape %[[VAL_59]] : (!fir.box<!fir.array<?xi32>>, index, index, index, !fir.shape<1>) -> !fir.box<!fir.array<?xi32>>
+// CHECK:             hlfir.assign %[[VAL_49]] to %[[VAL_60]] : !fir.box<!fir.heap<!fir.array<?xi32>>>, !fir.box<!fir.array<?xi32>>
+// CHECK:           }
+// CHECK:           %[[VAL_61:.*]] = fir.call @_FortranADestroyValueStack(%[[VAL_22]]) : (!fir.llvm_ptr<i8>) -> none
+// CHECK:           return
+// CHECK:         }
+
+
+// i1 needs to be passed as logical<> to be stored. Check converts are
+// introduced as expected.
+func.func @_QPdealing_with_i1(%x: !fir.ref<!fir.array<10x20xi32>>) {
+  %c42_i32 = arith.constant 42 : i32
+  %c10_i64 = arith.constant 10 : i64
+  %c1_i64 = arith.constant 1 : i64
+  hlfir.forall lb {
+    hlfir.yield %c1_i64 : i64
+  } ub {
+    hlfir.yield %c10_i64 : i64
+  }  (%arg1: i64) {
+    hlfir.forall lb {
+      hlfir.yield %c1_i64 : i64
+    } ub {
+      hlfir.yield %arg1 : i64
+    }  (%arg2: i64) {
+      hlfir.forall_mask {
+        %1 = hlfir.designate %x (%arg2, %arg1)  : (!fir.ref<!fir.array<10x20xi32>>, i64, i64) -> !fir.ref<i32>
+        %2 = fir.load %1 : !fir.ref<i32>
+        %3 = arith.cmpi sgt, %2, %c42_i32 : i32
+        hlfir.yield %3 : i1
+      } do {
+        hlfir.region_assign {
+          hlfir.yield %c42_i32 : i32
+        } to {
+          %1 = hlfir.designate %x (%arg1, %arg2)  : (!fir.ref<!fir.array<10x20xi32>>, i64, i64) -> !fir.ref<i32>
+          hlfir.yield %1 : !fir.ref<i32>
+        }
+      }
+    }
+  }
+  return
+}
+// CHECK-LABEL:   func.func @_QPdealing_with_i1(
+// CHECK:           %[[VAL_1:.*]] = fir.alloca !fir.logical<1>
+// CHECK:           %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.heap<!fir.logical<1>>>
+// CHECK:           fir.do_loop
+// CHECK:             fir.do_loop
+// CHECK:               %[[VAL_26:.*]] = arith.cmpi sgt
+// CHECK:               %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (i1) -> !fir.logical<1>
+// CHECK:               fir.store %[[VAL_27]] to %[[VAL_1]] : !fir.ref<!fir.logical<1>>
+// CHECK:               %[[VAL_28:.*]] = fir.embox %[[VAL_1]] : (!fir.ref<!fir.logical<1>>) -> !fir.box<!fir.logical<1>>
+// CHECK:               %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (!fir.box<!fir.logical<1>>) -> !fir.box<none>
+// CHECK:               %[[VAL_30:.*]] = fir.call @_FortranAPushValue(%{{.*}}, %[[VAL_29]]) : (!fir.llvm_ptr<i8>, !fir.box<none>) -> none
+// CHECK:             }
+// CHECK:           }
+// CHECK:           fir.do_loop
+// CHECK:             fir.do_loop
+// CHECK:               %[[VAL_43:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.heap<!fir.logical<1>>>>) -> !fir.ref<!fir.box<none>>
+// CHECK:               %[[VAL_44:.*]] = fir.call @_FortranAValueAt(%{{.*}}, %{{.*}}, %[[VAL_43]])
+// CHECK:               %[[VAL_45:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.logical<1>>>>
+// CHECK:               %[[VAL_46:.*]] = fir.box_addr %[[VAL_45]] : (!fir.box<!fir.heap<!fir.logical<1>>>) -> !fir.heap<!fir.logical<1>>
+// CHECK:               %[[VAL_47:.*]] = fir.load %[[VAL_46]] : !fir.heap<!fir.logical<1>>
+// CHECK:               %[[VAL_48:.*]] = fir.convert %[[VAL_47]] : (!fir.logical<1>) -> i1
+// CHECK:             }
+// CHECK:           }


        


More information about the flang-commits mailing list