From: Jean Perier Date: Thu, 25 May 2023 09:55:55 +0000 (+0200) Subject: [flang][hlfir] Generate temporary storage in Forall/Where [2/2] X-Git-Tag: upstream/17.0.6~7248 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f3c3f63672a0a58c46d7cde00979bfdb3a83038b;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h index fc03a1e..d20cdf7 100644 --- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h +++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h @@ -112,11 +112,7 @@ public: } bool isScalar() const { return !isArray(); } - bool isPolymorphic() const { - if (auto exprType = getType().dyn_cast()) - 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 0000000..b35d6d6 --- /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 88bf4af..b9e3f0e 100644 --- a/flang/include/flang/Optimizer/Builder/TemporaryStorage.h +++ b/flang/include/flang/Optimizer/Builder/TemporaryStorage.h @@ -115,6 +115,35 @@ public: hlfir::AssociateOp copy; }; +/// Data structure to stack any kind of values with the same static type and +/// rank. Each value may have different 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 different 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 different sorts of temporary storages. class TemporaryStorage { public: @@ -138,7 +167,7 @@ public: } private: - std::variant impl; + std::variant 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 0ccab33..8e3a5dd 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(); } +inline bool isPolymorphicType(mlir::Type type) { + if (auto exprType = type.dyn_cast()) + 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 66e9499..683aeef 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 0000000..f184e40 --- /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(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(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(loc, builder); + mlir::FunctionType funcType = func.getFunctionType(); + auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr, + boxValue); + builder.create(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(loc, builder); + mlir::FunctionType funcType = func.getFunctionType(); + auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr, + i, retValueBox); + builder.create(loc, func, args); +} + +void fir::runtime::genDestroyValueStack(mlir::Location loc, + fir::FirOpBuilder &builder, + mlir::Value opaquePtr) { + mlir::func::FuncOp func = + fir::runtime::getRuntimeFunc(loc, builder); + mlir::FunctionType funcType = func.getFunctionType(); + auto args = fir::runtime::createArguments(builder, loc, funcType, opaquePtr); + builder.create(loc, func, args); +} diff --git a/flang/lib/Optimizer/Builder/TemporaryStorage.cpp b/flang/lib/Optimizer/Builder/TemporaryStorage.cpp index b4e01556..362344a 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(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 1ec3aca..2c86f34 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 different 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 0000000..aa334c5 --- /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>, %n: !fir.ref) { + %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) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %3 = fir.load %1#1 : !fir.ref + 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 + %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>, index, index, index, !fir.shape<1>) -> !fir.box> + hlfir.yield %16 : !fir.box> + } to { + %4 = fir.load %1#0 : !fir.ref + %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>, index, index, index, !fir.shape<1>) -> !fir.box> + hlfir.yield %14 : !fir.box> + } + } + return +} + +// CHECK-LABEL: func.func @test_runtime_stack( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref) { +// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box>> +// 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) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.box>) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_10]]#1 : !fir.ref +// 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 +// CHECK: %[[VAL_22:.*]] = fir.call @_FortranACreateValueStack(%{{.*}}, %{{.*}}) : (!fir.ref, i32) -> !fir.llvm_ptr +// 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 +// 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>, index, index, index, !fir.shape<1>) -> !fir.box> +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_39:.*]] = fir.call @_FortranAPushValue(%[[VAL_22]], %[[VAL_38]]) : (!fir.llvm_ptr, !fir.box) -> 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 +// 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 +// CHECK: %[[VAL_46:.*]] = arith.addi %[[VAL_45]], %[[VAL_17]] : i64 +// CHECK: fir.store %[[VAL_46]] to %[[VAL_3]] : !fir.ref +// CHECK: %[[VAL_47:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_48:.*]] = fir.call @_FortranAValueAt(%[[VAL_22]], %[[VAL_45]], %[[VAL_47]]) : (!fir.llvm_ptr, i64, !fir.ref>) -> none +// CHECK: %[[VAL_49:.*]] = fir.load %[[VAL_2]] : !fir.ref>>> +// CHECK: %[[VAL_50:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref +// 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>, index, index, index, !fir.shape<1>) -> !fir.box> +// CHECK: hlfir.assign %[[VAL_49]] to %[[VAL_60]] : !fir.box>>, !fir.box> +// CHECK: } +// CHECK: %[[VAL_61:.*]] = fir.call @_FortranADestroyValueStack(%[[VAL_22]]) : (!fir.llvm_ptr) -> 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>) { + %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>, i64, i64) -> !fir.ref + %2 = fir.load %1 : !fir.ref + %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>, i64, i64) -> !fir.ref + hlfir.yield %1 : !fir.ref + } + } + } + } + return +} +// CHECK-LABEL: func.func @_QPdealing_with_i1( +// CHECK: %[[VAL_1:.*]] = fir.alloca !fir.logical<1> +// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box>> +// 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> +// CHECK: %[[VAL_28:.*]] = fir.embox %[[VAL_1]] : (!fir.ref>) -> !fir.box> +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_30:.*]] = fir.call @_FortranAPushValue(%{{.*}}, %[[VAL_29]]) : (!fir.llvm_ptr, !fir.box) -> none +// CHECK: } +// CHECK: } +// CHECK: fir.do_loop +// CHECK: fir.do_loop +// CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_44:.*]] = fir.call @_FortranAValueAt(%{{.*}}, %{{.*}}, %[[VAL_43]]) +// CHECK: %[[VAL_45:.*]] = fir.load %[[VAL_2]] : !fir.ref>>> +// CHECK: %[[VAL_46:.*]] = fir.box_addr %[[VAL_45]] : (!fir.box>>) -> !fir.heap> +// CHECK: %[[VAL_47:.*]] = fir.load %[[VAL_46]] : !fir.heap> +// CHECK: %[[VAL_48:.*]] = fir.convert %[[VAL_47]] : (!fir.logical<1>) -> i1 +// CHECK: } +// CHECK: }