diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index 003b4358572c1..1583cfb3f5b51 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -268,6 +268,40 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { mlir::ValueRange lenParams = {}, llvm::ArrayRef attrs = {}); + /// Sample genDeclare callback for createArrayTemp() below. + /// It creates fir.declare operation using the given operands. + /// \p memref is the base of the allocated temporary, + /// which may be !fir.ref> or !fir.ref>. + static mlir::Value genTempDeclareOp(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value memref, + llvm::StringRef name, mlir::Value shape, + llvm::ArrayRef typeParams, + fir::FortranVariableFlagsAttr attrs); + + /// Create a temporary array with the given \p arrayType, + /// \p shape, \p extents and \p typeParams. An optional + /// \p polymorphicMold specifies the entity which dynamic type + /// has to be used for the allocation. + /// \p genDeclare callback generates a declare operation + /// for the created temporary. FIR passes may use genTempDeclareOp() + /// function above that creates fir.declare. + /// HLFIR passes may provide their own callback that generates + /// hlfir.declare. Some passes may provide a callback that + /// just passes through the base of the temporary. + /// If \p useStack is true, the function will try to do the allocation + /// in stack memory (which is not always possible currently). + /// The first return value is the base of the temporary object, + /// which may be !fir.ref> or !fir.ref>. + /// The second return value is true, if the actual allocation + /// was done in heap memory. + std::pair + createArrayTemp(mlir::Location loc, fir::SequenceType arrayType, + mlir::Value shape, llvm::ArrayRef extents, + llvm::ArrayRef typeParams, + const std::function &genDeclare, + mlir::Value polymorphicMold, bool useStack = false, + llvm::StringRef tmpName = ".tmp.array"); + /// Create an LLVM stack save intrinsic op. Returns the saved stack pointer. /// The stack address space is fetched from the data layout of the current /// module. @@ -596,6 +630,15 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener { return result; } + /// Compare two pointer-like values using the given predicate. + mlir::Value genPtrCompare(mlir::Location loc, + mlir::arith::CmpIPredicate predicate, + mlir::Value ptr1, mlir::Value ptr2) { + ptr1 = createConvert(loc, getIndexType(), ptr1); + ptr2 = createConvert(loc, getIndexType(), ptr2); + return create(loc, predicate, ptr1, ptr2); + } + private: /// Set attributes (e.g. FastMathAttr) to \p op operation /// based on the current attributes setting. @@ -850,6 +893,17 @@ llvm::SmallVector deduceOptimalExtents(mlir::ValueRange extents1, /// %result1 = arith.select %p4, %c0, %e1 : index llvm::SmallVector updateRuntimeExtentsForEmptyArrays( fir::FirOpBuilder &builder, mlir::Location loc, mlir::ValueRange extents); + +/// Given \p box of type fir::BaseBoxType representing an array, +/// the function generates code to fetch the lower bounds, +/// the extents and the strides from the box. The values are returned via +/// \p lbounds, \p extents and \p strides. +void genDimInfoFromBox(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value box, + llvm::SmallVectorImpl *lbounds, + llvm::SmallVectorImpl *extents, + llvm::SmallVectorImpl *strides); + } // namespace fir::factory #endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H diff --git a/flang/include/flang/Optimizer/CodeGen/CGPasses.td b/flang/include/flang/Optimizer/CodeGen/CGPasses.td index 2e097faec5403..df0ecf5540776 100644 --- a/flang/include/flang/Optimizer/CodeGen/CGPasses.td +++ b/flang/include/flang/Optimizer/CodeGen/CGPasses.td @@ -99,4 +99,15 @@ def BoxedProcedurePass : Pass<"boxed-procedure", "mlir::ModuleOp"> { ]; } +def LowerRepackArraysPass : Pass<"lower-repack-arrays", "mlir::ModuleOp"> { + let summary = "Convert fir.pack/unpack_array to other FIR operations"; + let description = [{ + Convert fir.pack/unpack_array operations to other FIR operations + and Fortran runtime calls that implement the semantics + of packing/unpacking. + }]; + let dependentDialects = ["fir::FIROpsDialect", "mlir::arith::ArithDialect", + "mlir::func::FuncDialect"]; +} + #endif // FORTRAN_OPTIMIZER_CODEGEN_FIR_PASSES diff --git a/flang/include/flang/Optimizer/CodeGen/CodeGen.h b/flang/include/flang/Optimizer/CodeGen/CodeGen.h index 255b1950c8425..0398d0f248e08 100644 --- a/flang/include/flang/Optimizer/CodeGen/CodeGen.h +++ b/flang/include/flang/Optimizer/CodeGen/CodeGen.h @@ -26,6 +26,7 @@ struct NameUniquer; #define GEN_PASS_DECL_CODEGENREWRITE #define GEN_PASS_DECL_TARGETREWRITEPASS #define GEN_PASS_DECL_BOXEDPROCEDUREPASS +#define GEN_PASS_DECL_LOWERREPACKARRAYSPASS #include "flang/Optimizer/CodeGen/CGPasses.h.inc" /// FIR to LLVM translation pass options. diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index b7f8a8d3a9d56..fdc155ef2ef18 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -11,6 +11,7 @@ #include "flang/Optimizer/Builder/Character.h" #include "flang/Optimizer/Builder/Complex.h" #include "flang/Optimizer/Builder/MutableBox.h" +#include "flang/Optimizer/Builder/Runtime/Allocatable.h" #include "flang/Optimizer/Builder/Runtime/Assign.h" #include "flang/Optimizer/Builder/Runtime/Derived.h" #include "flang/Optimizer/Builder/Todo.h" @@ -362,6 +363,72 @@ mlir::Value fir::FirOpBuilder::createHeapTemporary( name, dynamicLength, dynamicShape, attrs); } +std::pair fir::FirOpBuilder::createArrayTemp( + mlir::Location loc, fir::SequenceType arrayType, mlir::Value shape, + llvm::ArrayRef extents, llvm::ArrayRef typeParams, + const std::function &genDeclare, + mlir::Value polymorphicMold, bool useStack, llvm::StringRef tmpName) { + if (polymorphicMold) { + // Create *allocated* polymorphic temporary using the dynamic type + // of the mold and the provided shape/extents. The created temporary + // array will be written element per element, that is why it has to be + // allocated. + mlir::Type boxHeapType = fir::HeapType::get(arrayType); + mlir::Value alloc = fir::factory::genNullBoxStorage( + *this, loc, fir::ClassType::get(boxHeapType)); + fir::FortranVariableFlagsAttr declAttrs = + fir::FortranVariableFlagsAttr::get( + getContext(), fir::FortranVariableFlagsEnum::allocatable); + + mlir::Value base = genDeclare(*this, loc, alloc, tmpName, + /*shape=*/nullptr, typeParams, declAttrs); + + int rank = extents.size(); + fir::runtime::genAllocatableApplyMold(*this, loc, alloc, polymorphicMold, + rank); + if (!extents.empty()) { + mlir::Type idxTy = getIndexType(); + mlir::Value one = createIntegerConstant(loc, idxTy, 1); + unsigned dim = 0; + for (mlir::Value extent : extents) { + mlir::Value dimIndex = createIntegerConstant(loc, idxTy, dim++); + fir::runtime::genAllocatableSetBounds(*this, loc, alloc, dimIndex, one, + extent); + } + } + if (!typeParams.empty()) { + // We should call AllocatableSetDerivedLength() here. + // TODO: does the mold provide the length parameters or + // the operation itself or should they be in sync? + TODO(loc, "polymorphic type with length parameters"); + } + fir::runtime::genAllocatableAllocate(*this, loc, alloc); + + return {base, /*isHeapAllocation=*/true}; + } + mlir::Value allocmem; + if (useStack) + allocmem = createTemporary(loc, arrayType, tmpName, extents, typeParams); + else + allocmem = + createHeapTemporary(loc, arrayType, tmpName, extents, typeParams); + mlir::Value base = genDeclare(*this, loc, allocmem, tmpName, shape, + typeParams, fir::FortranVariableFlagsAttr{}); + return {base, !useStack}; +} + +mlir::Value fir::FirOpBuilder::genTempDeclareOp( + fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value memref, + llvm::StringRef name, mlir::Value shape, + llvm::ArrayRef typeParams, + fir::FortranVariableFlagsAttr fortranAttrs) { + auto nameAttr = mlir::StringAttr::get(builder.getContext(), name); + return builder.create(loc, memref.getType(), memref, shape, + typeParams, + /*dummy_scope=*/nullptr, nameAttr, + fortranAttrs, cuf::DataAttributeAttr{}); +} + mlir::Value fir::FirOpBuilder::genStackSave(mlir::Location loc) { mlir::Type voidPtr = mlir::LLVM::LLVMPointerType::get( getContext(), fir::factory::getAllocaAddressSpace(&getDataLayout())); @@ -1825,3 +1892,29 @@ llvm::SmallVector fir::factory::updateRuntimeExtentsForEmptyArrays( } return newExtents; } + +void fir::factory::genDimInfoFromBox( + fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value box, + llvm::SmallVectorImpl *lbounds, + llvm::SmallVectorImpl *extents, + llvm::SmallVectorImpl *strides) { + auto boxType = mlir::dyn_cast(box.getType()); + assert(boxType && "must be a box"); + if (!lbounds && !extents && !strides) + return; + + unsigned rank = fir::getBoxRank(boxType); + assert(rank != 0 && "must be an array of known rank"); + mlir::Type idxTy = builder.getIndexType(); + for (unsigned i = 0; i < rank; ++i) { + mlir::Value dim = builder.createIntegerConstant(loc, idxTy, i); + auto dimInfo = + builder.create(loc, idxTy, idxTy, idxTy, box, dim); + if (lbounds) + lbounds->push_back(dimInfo.getLowerBound()); + if (extents) + extents->push_back(dimInfo.getExtent()); + if (strides) + strides->push_back(dimInfo.getByteStride()); + } +} diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index 85fd742db6beb..06a3e177da1d0 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -95,24 +95,6 @@ getExplicitLbounds(fir::FortranVariableOpInterface var) { return {}; } -static void -genLboundsAndExtentsFromBox(mlir::Location loc, fir::FirOpBuilder &builder, - hlfir::Entity boxEntity, - llvm::SmallVectorImpl &lbounds, - llvm::SmallVectorImpl *extents) { - assert(mlir::isa(boxEntity.getType()) && "must be a box"); - mlir::Type idxTy = builder.getIndexType(); - const int rank = boxEntity.getRank(); - for (int i = 0; i < rank; ++i) { - mlir::Value dim = builder.createIntegerConstant(loc, idxTy, i); - auto dimInfo = builder.create(loc, idxTy, idxTy, idxTy, - boxEntity, dim); - lbounds.push_back(dimInfo.getLowerBound()); - if (extents) - extents->push_back(dimInfo.getExtent()); - } -} - static llvm::SmallVector getNonDefaultLowerBounds(mlir::Location loc, fir::FirOpBuilder &builder, hlfir::Entity entity) { @@ -128,8 +110,8 @@ getNonDefaultLowerBounds(mlir::Location loc, fir::FirOpBuilder &builder, if (entity.isMutableBox()) entity = hlfir::derefPointersAndAllocatables(loc, builder, entity); llvm::SmallVector lowerBounds; - genLboundsAndExtentsFromBox(loc, builder, entity, lowerBounds, - /*extents=*/nullptr); + fir::factory::genDimInfoFromBox(builder, loc, entity, &lowerBounds, + /*extents=*/nullptr, /*strides=*/nullptr); return lowerBounds; } @@ -1149,8 +1131,8 @@ static fir::ExtendedValue translateVariableToExtendedValue( variable.mayHaveNonDefaultLowerBounds()) { // This special case avoids generating two sets of identical // fir.box_dim to get both the lower bounds and extents. - genLboundsAndExtentsFromBox(loc, builder, variable, nonDefaultLbounds, - &extents); + fir::factory::genDimInfoFromBox(builder, loc, variable, &nonDefaultLbounds, + &extents, /*strides=*/nullptr); } else { extents = getVariableExtents(loc, builder, variable); nonDefaultLbounds = getNonDefaultLowerBounds(loc, builder, variable); diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt index 553c20bb85d38..f730c7fd03948 100644 --- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt +++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt @@ -4,6 +4,7 @@ add_flang_library(FIRCodeGen CodeGen.cpp CodeGenOpenMP.cpp FIROpPatterns.cpp + LowerRepackArrays.cpp PreCGRewrite.cpp TBAABuilder.cpp Target.cpp diff --git a/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp b/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp new file mode 100644 index 0000000000000..0acc034c47152 --- /dev/null +++ b/flang/lib/Optimizer/CodeGen/LowerRepackArrays.cpp @@ -0,0 +1,330 @@ +//===-- LowerRepackArrays.cpp ---------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// \file +/// This pass expands fir.pack_array and fir.unpack_array operations +/// into sequences of other FIR operations and Fortran runtime calls. +/// This pass is using structured control flow FIR operations such +/// as fir.if, so its placement in the pipeline should guarantee +/// further lowering of these operations. +/// +/// A fir.pack_array operation is converted into a sequence of checks +/// identifying whether an array needs to be copied into a contiguous +/// temporary. When the checks pass, a new memory allocation is done +/// for the temporary array (in either stack or heap memory). +/// If `fir.pack_array` does not have no_copy attribute, then +/// the original array is shallow-copied into the temporary. +/// +/// A fir.unpack_array operations is converted into a check +/// of whether the original and the temporary arrays are different +/// memory. When the check passes, the temporary array might be +/// shallow-copied into the original array, and then the temporary +/// array is deallocated (if it was allocated in stack memory, +/// then there is no explicit deallocation). +//===----------------------------------------------------------------------===// + +#include "flang/Optimizer/CodeGen/CodeGen.h" + +#include "flang/Optimizer/Builder/Character.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/MutableBox.h" +#include "flang/Optimizer/Builder/Runtime/Allocatable.h" +#include "flang/Optimizer/Builder/Runtime/Transformational.h" +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/Dialect/FIRDialect.h" +#include "flang/Optimizer/Dialect/FIROps.h" +#include "flang/Optimizer/Dialect/FIRType.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/GreedyPatternRewriteDriver.h" + +namespace fir { +#define GEN_PASS_DEF_LOWERREPACKARRAYSPASS +#include "flang/Optimizer/CodeGen/CGPasses.h.inc" +} // namespace fir + +#define DEBUG_TYPE "lower-repack-arrays" + +namespace { +class PackArrayConversion : public mlir::OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + mlir::LogicalResult + matchAndRewrite(fir::PackArrayOp op, + mlir::PatternRewriter &rewriter) const override; + +private: + static constexpr llvm::StringRef bufferName = ".repacked"; + + // Return value of fir::BaseBoxType that represents a temporary + // array created for the original box with given extents and + // type parameters. The new box has the default lower bounds. + // If useStack is true, then the temporary will be allocated + // in stack memory (when possible). + static mlir::Value allocateTempBuffer(fir::FirOpBuilder &builder, + mlir::Location loc, bool useStack, + mlir::Value origBox, + llvm::ArrayRef extents, + llvm::ArrayRef typeParams); + + // Generate value of fir::BaseBoxType that represents the result + // of the given fir.pack_array operation. The original box + // is assumed to be present (though, it may represent an empty array). + static mlir::FailureOr genRepackedBox(fir::FirOpBuilder &builder, + mlir::Location loc, + fir::PackArrayOp packOp); +}; + +class UnpackArrayConversion + : public mlir::OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + mlir::LogicalResult + matchAndRewrite(fir::UnpackArrayOp op, + mlir::PatternRewriter &rewriter) const override; +}; +} // anonymous namespace + +// Return true iff for the given original boxed array we can +// allocate temporary memory in stack memory. +// This function is used to synchronize allocation/deallocation +// implied by fir.pack_array and fir.unpack_array, because +// the presence of the stack attribute does not automatically +// mean that the allocation is actually done in stack memory. +// For example, we always do the heap allocation for polymorphic +// types using Fortran runtime. +// Adding the polymorpic mold to fir.alloca and then using +// Fortran runtime to compute the allocation size could probably +// resolve this limitation. +static bool canAllocateTempOnStack(mlir::Value box) { + return !fir::isPolymorphicType(box.getType()); +} + +mlir::LogicalResult +PackArrayConversion::matchAndRewrite(fir::PackArrayOp op, + mlir::PatternRewriter &rewriter) const { + mlir::Location loc = op.getLoc(); + fir::FirOpBuilder builder(rewriter, op.getOperation()); + if (op.getMaxSize() || op.getMaxElementSize() || op.getMinStride()) + TODO(loc, "fir.pack_array with constraints"); + if (op.getHeuristics() != fir::PackArrayHeuristics::None) + TODO(loc, "fir.pack_array with heuristics"); + + mlir::Value box = op.getArray(); + auto boxType = mlir::cast(box.getType()); + + // For now we have to always check if the box is present. + auto isPresent = + builder.create(loc, builder.getI1Type(), box); + + fir::IfOp ifOp = builder.create(loc, boxType, isPresent, + /*withElseRegion=*/true); + builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); + // The box is present. + auto newBox = genRepackedBox(builder, loc, op); + if (mlir::failed(newBox)) + return newBox; + builder.create(loc, *newBox); + + // The box is not present. Return original box. + builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); + builder.create(loc, box); + + rewriter.replaceOp(op, ifOp.getResult(0)); + return mlir::success(); +} + +mlir::Value PackArrayConversion::allocateTempBuffer( + fir::FirOpBuilder &builder, mlir::Location loc, bool useStack, + mlir::Value origBox, llvm::ArrayRef extents, + llvm::ArrayRef typeParams) { + auto tempType = mlir::cast( + fir::extractSequenceType(origBox.getType())); + assert(tempType.getDimension() == extents.size() && + "number of extents does not match the rank"); + + mlir::Value shape = builder.genShape(loc, extents); + auto [base, isHeapAllocation] = builder.createArrayTemp( + loc, tempType, shape, extents, typeParams, + fir::FirOpBuilder::genTempDeclareOp, + fir::isPolymorphicType(origBox.getType()) ? origBox : nullptr, useStack, + bufferName); + // Make sure canAllocateTempOnStack() can recognize when + // the temporary is actually allocated on the stack + // by createArrayTemp(). Otherwise, we may miss dynamic + // deallocation when lowering fir.unpack_array. + if (useStack && canAllocateTempOnStack(origBox)) + assert(!isHeapAllocation && "temp must have been allocated on the stack"); + + if (isHeapAllocation) + if (auto baseType = mlir::dyn_cast(base.getType())) + if (mlir::isa(baseType.getEleTy())) + return builder.create(loc, base); + + mlir::Type ptrType = base.getType(); + mlir::Type tempBoxType = fir::BoxType::get(mlir::isa(ptrType) + ? ptrType + : fir::unwrapRefType(ptrType)); + mlir::Value newBox = + builder.createBox(loc, tempBoxType, base, shape, /*slice=*/nullptr, + typeParams, /*tdesc=*/nullptr); + return newBox; +} + +mlir::FailureOr +PackArrayConversion::genRepackedBox(fir::FirOpBuilder &builder, + mlir::Location loc, fir::PackArrayOp op) { + mlir::OpBuilder::InsertionGuard guard(builder); + mlir::Value box = op.getArray(); + llvm::SmallVector typeParams(op.getTypeparams().begin(), + op.getTypeparams().end()); + auto boxType = mlir::cast(box.getType()); + mlir::Type indexType = builder.getIndexType(); + + // If type parameters are not specified by fir.pack_array, + // figure out how many of them we need to read from the box. + unsigned numTypeParams = 0; + if (typeParams.size() == 0) { + if (auto recordType = + mlir::dyn_cast(boxType.unwrapInnerType())) + if (recordType.getNumLenParams() != 0) + TODO(loc, + "allocating temporary for a parameterized derived type array"); + + if (auto charType = + mlir::dyn_cast(boxType.unwrapInnerType())) { + if (charType.hasDynamicLen()) { + // Read one length parameter from the box. + numTypeParams = 1; + } else { + // Place the constant length into typeParams. + mlir::Value length = + builder.createIntegerConstant(loc, indexType, charType.getLen()); + typeParams.push_back(length); + } + } + } + + // Create a temporay iff the original is not contigous and is not empty. + auto isNotContiguous = builder.genNot( + loc, builder.create(loc, box, op.getInnermost())); + auto dataAddr = + builder.create(loc, fir::boxMemRefType(boxType), box); + auto isNotEmpty = + builder.create(loc, builder.getI1Type(), dataAddr); + auto doPack = + builder.create(loc, isNotContiguous, isNotEmpty); + + fir::IfOp ifOp = + builder.create(loc, boxType, doPack, /*withElseRegion=*/true); + + // Return original box. + builder.setInsertionPointToStart(&ifOp.getElseRegion().front()); + builder.create(loc, box); + + // Create a new box. + builder.setInsertionPointToStart(&ifOp.getThenRegion().front()); + + // Get lower bounds and extents from the box. + llvm::SmallVector lbounds, extents; + fir::factory::genDimInfoFromBox(builder, loc, box, &lbounds, &extents, + /*strides=*/nullptr); + // Get the type parameters from the box, if needed. + llvm::SmallVector assumedTypeParams; + if (numTypeParams != 0) { + if (auto charType = + mlir::dyn_cast(boxType.unwrapInnerType())) + if (charType.hasDynamicLen()) { + fir::factory::CharacterExprHelper charHelper(builder, loc); + mlir::Value len = charHelper.readLengthFromBox(box, charType); + typeParams.push_back(builder.createConvert(loc, indexType, len)); + } + + if (numTypeParams != typeParams.size()) + return emitError(loc) << "failed to compute the type parameters for " + << op.getOperation() << '\n'; + } + + mlir::Value tempBox = + allocateTempBuffer(builder, loc, op.getStack(), box, extents, typeParams); + if (!op.getNoCopy()) + fir::runtime::genShallowCopy(builder, loc, tempBox, box, + /*resultIsAllocated=*/true); + + // Set lower bounds after the original box. + mlir::Value shift = builder.genShift(loc, lbounds); + tempBox = builder.create(loc, boxType, tempBox, shift, + /*slice=*/nullptr); + builder.create(loc, tempBox); + + return ifOp.getResult(0); +} + +mlir::LogicalResult +UnpackArrayConversion::matchAndRewrite(fir::UnpackArrayOp op, + mlir::PatternRewriter &rewriter) const { + mlir::Location loc = op.getLoc(); + fir::FirOpBuilder builder(rewriter, op.getOperation()); + mlir::Type predicateType = builder.getI1Type(); + mlir::Value tempBox = op.getTemp(); + mlir::Value originalBox = op.getOriginal(); + + // For now we have to always check if the box is present. + auto isPresent = + builder.create(loc, predicateType, originalBox); + + builder.genIfThen(loc, isPresent).genThen([&]() { + mlir::Type addrType = + fir::HeapType::get(fir::extractSequenceType(tempBox.getType())); + mlir::Value tempAddr = + builder.create(loc, addrType, tempBox); + mlir::Value originalAddr = + builder.create(loc, addrType, originalBox); + + auto isNotSame = builder.genPtrCompare(loc, mlir::arith::CmpIPredicate::ne, + tempAddr, originalAddr); + builder.genIfThen(loc, isNotSame).genThen([&]() {}); + // Copy from temporary to the original. + if (!op.getNoCopy()) + fir::runtime::genShallowCopy(builder, loc, originalBox, tempBox, + /*resultIsAllocated=*/true); + + // Deallocate, if it was allocated in heap. + // Note that the stack attribute does not always mean + // that the allocation was actually done in stack memory. + // There are currently cases where we delegate the allocation + // to the runtime that uses heap memory, even when the stack + // attribute is set on fir.pack_array. + if (!op.getStack() || !canAllocateTempOnStack(originalBox)) + builder.create(loc, tempAddr); + }); + rewriter.eraseOp(op); + return mlir::success(); +} + +namespace { +class LowerRepackArraysPass + : public fir::impl::LowerRepackArraysPassBase { +public: + using LowerRepackArraysPassBase< + LowerRepackArraysPass>::LowerRepackArraysPassBase; + + void runOnOperation() override final { + auto *context = &getContext(); + mlir::ModuleOp module = getOperation(); + mlir::RewritePatternSet patterns(context); + patterns.insert(context); + patterns.insert(context); + mlir::GreedyRewriteConfig config; + config.enableRegionSimplification = + mlir::GreedySimplifyRegionLevel::Disabled; + (void)applyPatternsGreedily(module, std::move(patterns), config); + } +}; + +} // anonymous namespace diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp index 30e7ef7890953..8a36214def167 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp @@ -105,60 +105,27 @@ static mlir::Value getBufferizedExprMustFreeFlag(mlir::Value bufferizedExpr) { static std::pair createArrayTemp(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Type exprType, mlir::Value shape, - mlir::ValueRange extents, mlir::ValueRange lenParams, + llvm::ArrayRef extents, + llvm::ArrayRef lenParams, std::optional polymorphicMold) { - mlir::Type sequenceType = hlfir::getFortranElementOrSequenceType(exprType); - llvm::StringRef tmpName{".tmp.array"}; - - if (polymorphicMold) { - // Create *allocated* polymorphic temporary using the dynamic type - // of the mold and the provided shape/extents. The created temporary - // array will be written element per element, that is why it has to be - // allocated. - mlir::Type boxHeapType = fir::HeapType::get(sequenceType); - mlir::Value alloc = fir::factory::genNullBoxStorage( - builder, loc, fir::ClassType::get(boxHeapType)); - mlir::Value isHeapAlloc = builder.createBool(loc, true); - fir::FortranVariableFlagsAttr declAttrs = - fir::FortranVariableFlagsAttr::get( - builder.getContext(), fir::FortranVariableFlagsEnum::allocatable); - + auto sequenceType = mlir::cast( + hlfir::getFortranElementOrSequenceType(exprType)); + + auto genTempDeclareOp = + [](fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value memref, + llvm::StringRef name, mlir::Value shape, + llvm::ArrayRef typeParams, + fir::FortranVariableFlagsAttr attrs) -> mlir::Value { auto declareOp = - builder.create(loc, alloc, tmpName, - /*shape=*/nullptr, lenParams, - /*dummy_scope=*/nullptr, declAttrs); - - int rank = extents.size(); - fir::runtime::genAllocatableApplyMold(builder, loc, alloc, - polymorphicMold->getFirBase(), rank); - if (!extents.empty()) { - mlir::Type idxTy = builder.getIndexType(); - mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); - unsigned dim = 0; - for (mlir::Value extent : extents) { - mlir::Value dimIndex = builder.createIntegerConstant(loc, idxTy, dim++); - fir::runtime::genAllocatableSetBounds(builder, loc, alloc, dimIndex, - one, extent); - } - } - if (!lenParams.empty()) { - // We should call AllocatableSetDerivedLength() here. - // TODO: does the mold provide the length parameters or - // the operation itself or should they be in sync? - TODO(loc, "polymorphic type with length parameters in HLFIR"); - } - fir::runtime::genAllocatableAllocate(builder, loc, alloc); - - return {hlfir::Entity{declareOp.getBase()}, isHeapAlloc}; - } + builder.create(loc, memref, name, shape, typeParams, + /*dummy_scope=*/nullptr, attrs); + return declareOp.getBase(); + }; - mlir::Value allocmem = builder.createHeapTemporary(loc, sequenceType, tmpName, - extents, lenParams); - auto declareOp = builder.create( - loc, allocmem, tmpName, shape, lenParams, - /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{}); - mlir::Value trueVal = builder.createBool(loc, true); - return {hlfir::Entity{declareOp.getBase()}, trueVal}; + auto [base, isHeapAlloc] = builder.createArrayTemp( + loc, sequenceType, shape, extents, lenParams, genTempDeclareOp, + polymorphicMold ? polymorphicMold->getFirBase() : nullptr); + return {hlfir::Entity{base}, builder.createBool(loc, isHeapAlloc)}; } /// Copy \p source into a new temporary and package the temporary into a @@ -786,9 +753,10 @@ struct ElementalOpConversion if (adaptor.getMold()) mold = getBufferizedExprStorage(adaptor.getMold()); auto extents = hlfir::getIndexExtents(loc, builder, shape); - auto [temp, cleanup] = - createArrayTemp(loc, builder, elemental.getType(), shape, extents, - adaptor.getTypeparams(), mold); + llvm::SmallVector typeParams(adaptor.getTypeparams().begin(), + adaptor.getTypeparams().end()); + auto [temp, cleanup] = createArrayTemp(loc, builder, elemental.getType(), + shape, extents, typeParams, mold); // If the box load is needed, we'd better place it outside // of the loop nest. temp = derefPointersAndAllocatables(loc, builder, temp); diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp index 3aea021e596f6..6ec19556625bc 100644 --- a/flang/lib/Optimizer/Passes/Pipelines.cpp +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -198,6 +198,7 @@ void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm, pm.addPass(fir::createPolymorphicOpConversion()); pm.addPass(fir::createAssumedRankOpConversion()); + pm.addPass(fir::createLowerRepackArraysPass()); // Expand FIR operations that may use SCF dialect for their // implementation. This is a mandatory pass. pm.addPass(fir::createSimplifyFIROperations( diff --git a/flang/test/Driver/bbc-mlir-pass-pipeline.f90 b/flang/test/Driver/bbc-mlir-pass-pipeline.f90 index 276ef818622a1..137c19608c38f 100644 --- a/flang/test/Driver/bbc-mlir-pass-pipeline.f90 +++ b/flang/test/Driver/bbc-mlir-pass-pipeline.f90 @@ -47,6 +47,7 @@ ! CHECK-NEXT: PolymorphicOpConversion ! CHECK-NEXT: AssumedRankOpConversion +! CHECK-NEXT: LowerRepackArraysPass ! CHECK-NEXT: SimplifyFIROperations ! CHECK-NEXT: Pipeline Collection : ['fir.global', 'func.func', 'omp.declare_reduction', 'omp.private'] diff --git a/flang/test/Driver/mlir-debug-pass-pipeline.f90 b/flang/test/Driver/mlir-debug-pass-pipeline.f90 index 70fa0cf5ae47c..42a71b2d6adc3 100644 --- a/flang/test/Driver/mlir-debug-pass-pipeline.f90 +++ b/flang/test/Driver/mlir-debug-pass-pipeline.f90 @@ -77,6 +77,7 @@ ! ALL-NEXT: PolymorphicOpConversion ! ALL-NEXT: AssumedRankOpConversion +! ALL-NEXT: LowerRepackArraysPass ! ALL-NEXT: SimplifyFIROperations ! ALL-NEXT: Pipeline Collection : ['fir.global', 'func.func', 'omp.declare_reduction', 'omp.private'] diff --git a/flang/test/Driver/mlir-pass-pipeline.f90 b/flang/test/Driver/mlir-pass-pipeline.f90 index 852764be1f136..45370895db397 100644 --- a/flang/test/Driver/mlir-pass-pipeline.f90 +++ b/flang/test/Driver/mlir-pass-pipeline.f90 @@ -101,6 +101,7 @@ ! ALL-NEXT: PolymorphicOpConversion ! ALL-NEXT: AssumedRankOpConversion +! ALL-NEXT: LowerRepackArraysPass ! ALL-NEXT: SimplifyFIROperations ! O2-NEXT: AddAliasTags diff --git a/flang/test/Fir/basic-program.fir b/flang/test/Fir/basic-program.fir index 90bff80da1915..ded42886aad44 100644 --- a/flang/test/Fir/basic-program.fir +++ b/flang/test/Fir/basic-program.fir @@ -99,6 +99,7 @@ func.func @_QQmain() { // PASSES-NEXT: PolymorphicOpConversion // PASSES-NEXT: AssumedRankOpConversion +// PASSES-NEXT: LowerRepackArraysPass // PASSES-NEXT: SimplifyFIROperations // PASSES-NEXT: AddAliasTags diff --git a/flang/test/HLFIR/elemental-codegen.fir b/flang/test/HLFIR/elemental-codegen.fir index 2443217f557f8..c05c05cfa0413 100644 --- a/flang/test/HLFIR/elemental-codegen.fir +++ b/flang/test/HLFIR/elemental-codegen.fir @@ -166,7 +166,6 @@ func.func @test_polymorphic(%arg0: !fir.class> {fir.bindc_ // CHECK: %[[VAL_10:.*]] = fir.shape %[[VAL_9]], %[[VAL_9]] : (index, index) -> !fir.shape<2> // CHECK: %[[VAL_11:.*]] = fir.embox %[[VAL_8]](%[[VAL_10]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.class>>> // CHECK: fir.store %[[VAL_11]] to %[[VAL_4]] : !fir.ref>>>> -// CHECK: %[[VAL_12:.*]] = arith.constant true // CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_4]] {fortran_attrs = #fir.var_attrs, uniq_name = ".tmp.array"} : (!fir.ref>>>>) -> (!fir.ref>>>>, !fir.ref>>>>) // CHECK: %[[RANK:.*]] = arith.constant 2 : i32 // CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_4]] : (!fir.ref>>>>) -> !fir.ref> @@ -193,6 +192,7 @@ func.func @test_polymorphic(%arg0: !fir.class> {fir.bindc_ // CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_4]] : (!fir.ref>>>>) -> !fir.ref> // CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_31]] : (!fir.ref>) -> !fir.ref // CHECK: %[[VAL_38:.*]] = fir.call @_FortranAAllocatableAllocate(%[[VAL_36]], %[[VAL_34]], %[[VAL_35]], %[[VAL_37]], %[[VAL_33]]) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +// CHECK: %[[VAL_12:.*]] = arith.constant true // CHECK: %[[VAL_39:.*]] = fir.load %[[VAL_13]]#0 : !fir.ref>>>> // CHECK: %[[VAL_40:.*]] = arith.constant 1 : index // CHECK: fir.do_loop %[[VAL_41:.*]] = %[[VAL_40]] to %[[EX1]] step %[[VAL_40]] unordered { @@ -250,7 +250,6 @@ func.func @test_polymorphic_expr(%arg0: !fir.class> {fir.b // CHECK: %[[VAL_11:.*]] = fir.shape %[[VAL_10]], %[[VAL_10]] : (index, index) -> !fir.shape<2> // CHECK: %[[VAL_12:.*]] = fir.embox %[[VAL_9]](%[[VAL_11]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.class>>> // CHECK: fir.store %[[VAL_12]] to %[[VAL_5]] : !fir.ref>>>> -// CHECK: %[[VAL_13:.*]] = arith.constant true // CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_5]] {fortran_attrs = #fir.var_attrs, uniq_name = ".tmp.array"} : (!fir.ref>>>>) -> (!fir.ref>>>>, !fir.ref>>>>) // CHECK: %[[VAL_15:.*]] = arith.constant 2 : i32 // CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_5]] : (!fir.ref>>>>) -> !fir.ref> @@ -277,6 +276,7 @@ func.func @test_polymorphic_expr(%arg0: !fir.class> {fir.b // CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_5]] : (!fir.ref>>>>) -> !fir.ref> // CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_32]] : (!fir.ref>) -> !fir.ref // CHECK: %[[VAL_39:.*]] = fir.call @_FortranAAllocatableAllocate(%[[VAL_37]], %[[VAL_35]], %[[VAL_36]], %[[VAL_38]], %[[VAL_34]]) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +// CHECK: %[[VAL_13:.*]] = arith.constant true // CHECK: %[[VAL_40:.*]] = fir.load %[[VAL_14]]#0 : !fir.ref>>>> // CHECK: %[[VAL_41:.*]] = arith.constant 1 : index // CHECK: fir.do_loop %[[VAL_42:.*]] = %[[VAL_41]] to %[[VAL_3]] step %[[VAL_41]] unordered { @@ -303,7 +303,6 @@ func.func @test_polymorphic_expr(%arg0: !fir.class> {fir.b // CHECK: %[[VAL_60:.*]] = fir.shape %[[VAL_59]], %[[VAL_59]] : (index, index) -> !fir.shape<2> // CHECK: %[[VAL_61:.*]] = fir.embox %[[VAL_58]](%[[VAL_60]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.class>>> // CHECK: fir.store %[[VAL_61]] to %[[VAL_4]] : !fir.ref>>>> -// CHECK: %[[VAL_62:.*]] = arith.constant true // CHECK: %[[VAL_63:.*]]:2 = hlfir.declare %[[VAL_4]] {fortran_attrs = #fir.var_attrs, uniq_name = ".tmp.array"} : (!fir.ref>>>>) -> (!fir.ref>>>>, !fir.ref>>>>) // CHECK: %[[VAL_64:.*]] = arith.constant 2 : i32 // CHECK: %[[VAL_65:.*]] = fir.convert %[[VAL_4]] : (!fir.ref>>>>) -> !fir.ref> @@ -330,6 +329,7 @@ func.func @test_polymorphic_expr(%arg0: !fir.class> {fir.b // CHECK: %[[VAL_86:.*]] = fir.convert %[[VAL_4]] : (!fir.ref>>>>) -> !fir.ref> // CHECK: %[[VAL_87:.*]] = fir.convert %[[VAL_81]] : (!fir.ref>) -> !fir.ref // CHECK: %[[VAL_88:.*]] = fir.call @_FortranAAllocatableAllocate(%[[VAL_86]], %[[VAL_84]], %[[VAL_85]], %[[VAL_87]], %[[VAL_83]]) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +// CHECK: %[[VAL_62:.*]] = arith.constant true // CHECK: %[[VAL_89:.*]] = fir.load %[[VAL_63]]#0 : !fir.ref>>>> // CHECK: %[[VAL_90:.*]] = arith.constant 1 : index // CHECK: fir.do_loop %[[VAL_91:.*]] = %[[VAL_90]] to %[[VAL_3]] step %[[VAL_90]] unordered { diff --git a/flang/test/Transforms/lower-repack-arrays.fir b/flang/test/Transforms/lower-repack-arrays.fir new file mode 100644 index 0000000000000..7317d8f49f074 --- /dev/null +++ b/flang/test/Transforms/lower-repack-arrays.fir @@ -0,0 +1,1141 @@ +// RUN: fir-opt --lower-repack-arrays %s | FileCheck %s +// Test trivial type array repacking. +func.func @_QPtest1(%arg0: !fir.box> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost : (!fir.box>) -> !fir.box> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest1Ex"} : (!fir.box>, !fir.dscope) -> !fir.box> + fir.unpack_array %1 to %arg0 heap : !fir.box> + return +} +// CHECK-LABEL: func.func @_QPtest1( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_7]] -> (!fir.box>) { +// CHECK: %[[VAL_9:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>) -> i1 +// CHECK: %[[VAL_10:.*]] = arith.cmpi eq, %[[VAL_9]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> +// CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>) -> i1 +// CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>) { +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_18:.*]] = fir.allocmem !fir.array, %[[VAL_15]]#1, %[[VAL_16]]#1 {bindc_name = ".repacked", uniq_name = ""} +// CHECK: %[[VAL_19:.*]] = fir.declare %[[VAL_18]](%[[VAL_17]]) {uniq_name = ".repacked"} : (!fir.heap>, !fir.shape<2>) -> !fir.heap> +// CHECK: %[[VAL_20:.*]] = fir.embox %[[VAL_19]](%[[VAL_17]]) : (!fir.heap>, !fir.shape<2>) -> !fir.box>> +// CHECK: %[[VAL_21:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_20]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_21]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_22]], %[[VAL_23]], %[[VAL_24]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.shift %[[VAL_15]]#0, %[[VAL_16]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_26:.*]] = fir.rebox %[[VAL_20]](%[[VAL_25]]) : (!fir.box>>, !fir.shift<2>) -> !fir.box> +// CHECK: fir.result %[[VAL_26]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: fir.result %[[VAL_14]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: %[[VAL_27:.*]] = fir.declare %[[VAL_8]] dummy_scope %[[VAL_6]] {uniq_name = "_QFtest1Ex"} : (!fir.box>, !fir.dscope) -> !fir.box> +// CHECK: %[[VAL_28:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: fir.if %[[VAL_28]] { +// CHECK: %[[VAL_29:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_31:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>) -> index +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>) -> index +// CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index +// CHECK: fir.if %[[VAL_33]] { +// CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_34]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_35]], %[[VAL_36]], %[[VAL_37]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_29]] : !fir.heap> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test 'stack whole' repacking. +func.func @_QPtest1_whole(%arg0: !fir.box> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 stack whole : (!fir.box>) -> !fir.box> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest1_wholeEx"} : (!fir.box>, !fir.dscope) -> !fir.box> + fir.unpack_array %1 to %arg0 stack : !fir.box> + return +} +// CHECK-LABEL: func.func @_QPtest1_whole( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_7]] -> (!fir.box>) { +// CHECK: %[[VAL_9:.*]] = fir.is_contiguous_box %[[VAL_0]] whole : (!fir.box>) -> i1 +// CHECK: %[[VAL_10:.*]] = arith.cmpi eq, %[[VAL_9]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> +// CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>) -> i1 +// CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>) { +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_18:.*]] = fir.alloca !fir.array, %[[VAL_15]]#1, %[[VAL_16]]#1 {bindc_name = ".repacked"} +// CHECK: %[[VAL_19:.*]] = fir.declare %[[VAL_18]](%[[VAL_17]]) {uniq_name = ".repacked"} : (!fir.ref>, !fir.shape<2>) -> !fir.ref> +// CHECK: %[[VAL_20:.*]] = fir.embox %[[VAL_19]](%[[VAL_17]]) : (!fir.ref>, !fir.shape<2>) -> !fir.box> +// CHECK: %[[VAL_21:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_20]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_21]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_22]], %[[VAL_23]], %[[VAL_24]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.shift %[[VAL_15]]#0, %[[VAL_16]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_26:.*]] = fir.rebox %[[VAL_20]](%[[VAL_25]]) : (!fir.box>, !fir.shift<2>) -> !fir.box> +// CHECK: fir.result %[[VAL_26]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: fir.result %[[VAL_14]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: %[[VAL_27:.*]] = fir.declare %[[VAL_8]] dummy_scope %[[VAL_6]] {uniq_name = "_QFtest1_wholeEx"} : (!fir.box>, !fir.dscope) -> !fir.box> +// CHECK: %[[VAL_28:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: fir.if %[[VAL_28]] { +// CHECK: %[[VAL_29:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_31:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>) -> index +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>) -> index +// CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index +// CHECK: fir.if %[[VAL_33]] { +// CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_34]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_35]], %[[VAL_36]], %[[VAL_37]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test unpacking with no_copy. +func.func @_QPtest1_in(%arg0: !fir.box> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost : (!fir.box>) -> !fir.box> + %2 = fir.declare %1 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest1_inEx"} : (!fir.box>, !fir.dscope) -> !fir.box> + fir.unpack_array %1 to %arg0 heap no_copy : !fir.box> + return +} +// CHECK-LABEL: func.func @_QPtest1_in( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = arith.constant false +// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_6:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_7:.*]] = fir.if %[[VAL_6]] -> (!fir.box>) { +// CHECK: %[[VAL_8:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>) -> i1 +// CHECK: %[[VAL_9:.*]] = arith.cmpi eq, %[[VAL_8]], %[[VAL_4]] : i1 +// CHECK: %[[VAL_10:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> +// CHECK: %[[VAL_11:.*]] = fir.is_present %[[VAL_10]] : (!fir.ref>>) -> i1 +// CHECK: %[[VAL_12:.*]] = arith.andi %[[VAL_9]], %[[VAL_11]] : i1 +// CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_12]] -> (!fir.box>) { +// CHECK: %[[VAL_14:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_2]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]] = fir.shape %[[VAL_14]]#1, %[[VAL_15]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_17:.*]] = fir.allocmem !fir.array, %[[VAL_14]]#1, %[[VAL_15]]#1 {bindc_name = ".repacked", uniq_name = ""} +// CHECK: %[[VAL_18:.*]] = fir.declare %[[VAL_17]](%[[VAL_16]]) {uniq_name = ".repacked"} : (!fir.heap>, !fir.shape<2>) -> !fir.heap> +// CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_18]](%[[VAL_16]]) : (!fir.heap>, !fir.shape<2>) -> !fir.box>> +// CHECK: %[[VAL_20:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_19]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_20]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_21]], %[[VAL_22]], %[[VAL_23]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_24:.*]] = fir.shift %[[VAL_14]]#0, %[[VAL_15]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_25:.*]] = fir.rebox %[[VAL_19]](%[[VAL_24]]) : (!fir.box>>, !fir.shift<2>) -> !fir.box> +// CHECK: fir.result %[[VAL_25]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: fir.result %[[VAL_13]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: %[[VAL_26:.*]] = fir.declare %[[VAL_7]] dummy_scope %[[VAL_5]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest1_inEx"} : (!fir.box>, !fir.dscope) -> !fir.box> +// CHECK: %[[VAL_27:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: fir.if %[[VAL_27]] { +// CHECK: %[[VAL_28:.*]] = fir.box_addr %[[VAL_7]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_30:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (!fir.heap>) -> index +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>) -> index +// CHECK: %[[VAL_32:.*]] = arith.cmpi ne, %[[VAL_29]], %[[VAL_31]] : index +// CHECK: fir.if %[[VAL_32]] { +// CHECK: fir.freemem %[[VAL_28]] : !fir.heap> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test packing with no_copy. +func.func @_QPtest1_out(%arg0: !fir.box> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost no_copy : (!fir.box>) -> !fir.box> + %2 = fir.declare %1 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest1_outEx"} : (!fir.box>, !fir.dscope) -> !fir.box> + fir.unpack_array %1 to %arg0 heap : !fir.box> + return +} +// CHECK-LABEL: func.func @_QPtest1_out( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = arith.constant false +// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_6:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_7:.*]] = fir.if %[[VAL_6]] -> (!fir.box>) { +// CHECK: %[[VAL_8:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>) -> i1 +// CHECK: %[[VAL_9:.*]] = arith.cmpi eq, %[[VAL_8]], %[[VAL_4]] : i1 +// CHECK: %[[VAL_10:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.ref>> +// CHECK: %[[VAL_11:.*]] = fir.is_present %[[VAL_10]] : (!fir.ref>>) -> i1 +// CHECK: %[[VAL_12:.*]] = arith.andi %[[VAL_9]], %[[VAL_11]] : i1 +// CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_12]] -> (!fir.box>) { +// CHECK: %[[VAL_14:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_2]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]] = fir.shape %[[VAL_14]]#1, %[[VAL_15]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_17:.*]] = fir.allocmem !fir.array, %[[VAL_14]]#1, %[[VAL_15]]#1 {bindc_name = ".repacked", uniq_name = ""} +// CHECK: %[[VAL_18:.*]] = fir.declare %[[VAL_17]](%[[VAL_16]]) {uniq_name = ".repacked"} : (!fir.heap>, !fir.shape<2>) -> !fir.heap> +// CHECK: %[[VAL_19:.*]] = fir.embox %[[VAL_18]](%[[VAL_16]]) : (!fir.heap>, !fir.shape<2>) -> !fir.box>> +// CHECK: %[[VAL_20:.*]] = fir.shift %[[VAL_14]]#0, %[[VAL_15]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_21:.*]] = fir.rebox %[[VAL_19]](%[[VAL_20]]) : (!fir.box>>, !fir.shift<2>) -> !fir.box> +// CHECK: fir.result %[[VAL_21]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: fir.result %[[VAL_13]] : !fir.box> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box> +// CHECK: } +// CHECK: %[[VAL_22:.*]] = fir.declare %[[VAL_7]] dummy_scope %[[VAL_5]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest1_outEx"} : (!fir.box>, !fir.dscope) -> !fir.box> +// CHECK: %[[VAL_23:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>) -> i1 +// CHECK: fir.if %[[VAL_23]] { +// CHECK: %[[VAL_24:.*]] = fir.box_addr %[[VAL_7]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_26:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.heap> +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (!fir.heap>) -> index +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_26]] : (!fir.heap>) -> index +// CHECK: %[[VAL_28:.*]] = arith.cmpi ne, %[[VAL_25]], %[[VAL_27]] : index +// CHECK: fir.if %[[VAL_28]] { +// CHECK: %[[VAL_29:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_7]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_29]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_30]], %[[VAL_31]], %[[VAL_32]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_24]] : !fir.heap> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test character array with dynamic length and heap allocation +func.func @_QPtest2(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.box>> {fir.bindc_name = "x"}) { + %c0_i32 = arith.constant 0 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtest2En"} : (!fir.ref, !fir.dscope) -> !fir.ref + %2 = fir.load %1 : !fir.ref + %3 = arith.cmpi sgt, %2, %c0_i32 : i32 + %4 = arith.select %3, %2, %c0_i32 : i32 + %5 = fir.pack_array %arg1 heap innermost typeparams %4 : (!fir.box>>, i32) -> !fir.box>> + %6 = fir.declare %5 typeparams %4 dummy_scope %0 {uniq_name = "_QFtest2Ex"} : (!fir.box>>, i32, !fir.dscope) -> !fir.box>> + fir.unpack_array %5 to %arg1 heap : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest2( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant +// CHECK: %[[VAL_4:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant false +// CHECK: %[[VAL_7:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_8:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_9:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest2En"} : (!fir.ref, !fir.dscope) -> !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_9]] : !fir.ref +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_7]] : i32 +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_10]], %[[VAL_7]] : i32 +// CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_1]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]] = fir.is_contiguous_box %[[VAL_1]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_16:.*]] = arith.cmpi eq, %[[VAL_15]], %[[VAL_6]] : i1 +// CHECK: %[[VAL_17:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_18:.*]] = fir.is_present %[[VAL_17]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_19:.*]] = arith.andi %[[VAL_16]], %[[VAL_18]] : i1 +// CHECK: %[[VAL_20:.*]] = fir.if %[[VAL_19]] -> (!fir.box>>) { +// CHECK: %[[VAL_21:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_5]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_22:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_21]]#1, %[[VAL_22]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_24:.*]] = fir.allocmem !fir.array>(%[[VAL_12]] : i32), %[[VAL_21]]#1, %[[VAL_22]]#1 {bindc_name = ".repacked", uniq_name = ""} +// CHECK: %[[VAL_25:.*]] = fir.declare %[[VAL_24]](%[[VAL_23]]) typeparams %[[VAL_12]] {uniq_name = ".repacked"} : (!fir.heap>>, !fir.shape<2>, i32) -> !fir.heap>> +// CHECK: %[[VAL_26:.*]] = fir.embox %[[VAL_25]](%[[VAL_23]]) typeparams %[[VAL_12]] : (!fir.heap>>, !fir.shape<2>, i32) -> !fir.box>>> +// CHECK: %[[VAL_27:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_26]] : (!fir.box>>>) -> !fir.box +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_1]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_27]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_28]], %[[VAL_29]], %[[VAL_30]], %[[VAL_3]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_31:.*]] = fir.shift %[[VAL_21]]#0, %[[VAL_22]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_32:.*]] = fir.rebox %[[VAL_26]](%[[VAL_31]]) : (!fir.box>>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_32]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_1]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_20]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_1]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_33:.*]] = fir.declare %[[VAL_14]] typeparams %[[VAL_12]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest2Ex"} : (!fir.box>>, i32, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_34:.*]] = fir.is_present %[[VAL_1]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_34]] { +// CHECK: %[[VAL_35:.*]] = fir.box_addr %[[VAL_14]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_37:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_35]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_39:.*]] = arith.cmpi ne, %[[VAL_36]], %[[VAL_38]] : index +// CHECK: fir.if %[[VAL_39]] { +// CHECK: %[[VAL_40:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_1]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_14]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_40]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_41]], %[[VAL_42]], %[[VAL_43]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_35]] : !fir.heap>> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test character array with dynamic length and stack allocation +func.func @_QPtest2_stack(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.box>> {fir.bindc_name = "x"}) { + %c0_i32 = arith.constant 0 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QFtest2_stackEn"} : (!fir.ref, !fir.dscope) -> !fir.ref + %2 = fir.load %1 : !fir.ref + %3 = arith.cmpi sgt, %2, %c0_i32 : i32 + %4 = arith.select %3, %2, %c0_i32 : i32 + %5 = fir.pack_array %arg1 stack innermost typeparams %4 : (!fir.box>>, i32) -> !fir.box>> + %6 = fir.declare %5 typeparams %4 dummy_scope %0 {uniq_name = "_QFtest2_stackEx"} : (!fir.box>>, i32, !fir.dscope) -> !fir.box>> + fir.unpack_array %5 to %arg1 stack : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest2_stack( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[VAL_1:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant +// CHECK: %[[VAL_4:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant false +// CHECK: %[[VAL_7:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_8:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_9:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest2_stackEn"} : (!fir.ref, !fir.dscope) -> !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_9]] : !fir.ref +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_7]] : i32 +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_10]], %[[VAL_7]] : i32 +// CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_1]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]] = fir.is_contiguous_box %[[VAL_1]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_16:.*]] = arith.cmpi eq, %[[VAL_15]], %[[VAL_6]] : i1 +// CHECK: %[[VAL_17:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_18:.*]] = fir.is_present %[[VAL_17]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_19:.*]] = arith.andi %[[VAL_16]], %[[VAL_18]] : i1 +// CHECK: %[[VAL_20:.*]] = fir.if %[[VAL_19]] -> (!fir.box>>) { +// CHECK: %[[VAL_21:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_5]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_22:.*]]:3 = fir.box_dims %[[VAL_1]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_21]]#1, %[[VAL_22]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_24:.*]] = fir.alloca !fir.array>(%[[VAL_12]] : i32), %[[VAL_21]]#1, %[[VAL_22]]#1 {bindc_name = ".repacked"} +// CHECK: %[[VAL_25:.*]] = fir.declare %[[VAL_24]](%[[VAL_23]]) typeparams %[[VAL_12]] {uniq_name = ".repacked"} : (!fir.ref>>, !fir.shape<2>, i32) -> !fir.ref>> +// CHECK: %[[VAL_26:.*]] = fir.embox %[[VAL_25]](%[[VAL_23]]) typeparams %[[VAL_12]] : (!fir.ref>>, !fir.shape<2>, i32) -> !fir.box>> +// CHECK: %[[VAL_27:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_26]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_1]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_27]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_28]], %[[VAL_29]], %[[VAL_30]], %[[VAL_3]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_31:.*]] = fir.shift %[[VAL_21]]#0, %[[VAL_22]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_32:.*]] = fir.rebox %[[VAL_26]](%[[VAL_31]]) : (!fir.box>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_32]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_1]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_20]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_1]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_33:.*]] = fir.declare %[[VAL_14]] typeparams %[[VAL_12]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest2_stackEx"} : (!fir.box>>, i32, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_34:.*]] = fir.is_present %[[VAL_1]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_34]] { +// CHECK: %[[VAL_35:.*]] = fir.box_addr %[[VAL_14]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_37:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_35]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_37]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_39:.*]] = arith.cmpi ne, %[[VAL_36]], %[[VAL_38]] : index +// CHECK: fir.if %[[VAL_39]] { +// CHECK: %[[VAL_40:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_1]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_14]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_40]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_41]], %[[VAL_42]], %[[VAL_43]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test character array with assumed length and heap allocation. +func.func @_QPtest3(%arg0: !fir.box>> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost : (!fir.box>>) -> !fir.box>> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest3Ex"} : (!fir.box>>, !fir.dscope) -> !fir.box>> + fir.unpack_array %1 to %arg0 heap : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest3( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_7]] -> (!fir.box>>) { +// CHECK: %[[VAL_9:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_10:.*]] = arith.cmpi eq, %[[VAL_9]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]] = fir.box_elesize %[[VAL_0]] : (!fir.box>>) -> index +// CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_19:.*]] = fir.allocmem !fir.array>(%[[VAL_17]] : index), %[[VAL_15]]#1, %[[VAL_16]]#1 {bindc_name = ".repacked", uniq_name = ""} +// CHECK: %[[VAL_20:.*]] = fir.declare %[[VAL_19]](%[[VAL_18]]) typeparams %[[VAL_17]] {uniq_name = ".repacked"} : (!fir.heap>>, !fir.shape<2>, index) -> !fir.heap>> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_20]](%[[VAL_18]]) typeparams %[[VAL_17]] : (!fir.heap>>, !fir.shape<2>, index) -> !fir.box>>> +// CHECK: %[[VAL_22:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_21]] : (!fir.box>>>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_22]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_26:.*]] = fir.shift %[[VAL_15]]#0, %[[VAL_16]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_27:.*]] = fir.rebox %[[VAL_21]](%[[VAL_26]]) : (!fir.box>>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_27]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_14]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_28:.*]] = fir.declare %[[VAL_8]] dummy_scope %[[VAL_6]] {uniq_name = "_QFtest3Ex"} : (!fir.box>>, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_29:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_29]] { +// CHECK: %[[VAL_30:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_32:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index +// CHECK: fir.if %[[VAL_34]] { +// CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_35]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_36]], %[[VAL_37]], %[[VAL_38]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_30]] : !fir.heap>> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test character array with assumed length and stack allocation. +func.func @_QPtest3_stack(%arg0: !fir.box>> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 stack innermost : (!fir.box>>) -> !fir.box>> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest3_stackEx"} : (!fir.box>>, !fir.dscope) -> !fir.box>> + fir.unpack_array %1 to %arg0 stack : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest3_stack( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_7]] -> (!fir.box>>) { +// CHECK: %[[VAL_9:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_10:.*]] = arith.cmpi eq, %[[VAL_9]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]] = fir.box_elesize %[[VAL_0]] : (!fir.box>>) -> index +// CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_19:.*]] = fir.alloca !fir.array>(%[[VAL_17]] : index), %[[VAL_15]]#1, %[[VAL_16]]#1 {bindc_name = ".repacked"} +// CHECK: %[[VAL_20:.*]] = fir.declare %[[VAL_19]](%[[VAL_18]]) typeparams %[[VAL_17]] {uniq_name = ".repacked"} : (!fir.ref>>, !fir.shape<2>, index) -> !fir.ref>> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_20]](%[[VAL_18]]) typeparams %[[VAL_17]] : (!fir.ref>>, !fir.shape<2>, index) -> !fir.box>> +// CHECK: %[[VAL_22:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_21]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_22]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_26:.*]] = fir.shift %[[VAL_15]]#0, %[[VAL_16]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_27:.*]] = fir.rebox %[[VAL_21]](%[[VAL_26]]) : (!fir.box>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_27]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_14]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_28:.*]] = fir.declare %[[VAL_8]] dummy_scope %[[VAL_6]] {uniq_name = "_QFtest3_stackEx"} : (!fir.box>>, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_29:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_29]] { +// CHECK: %[[VAL_30:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_32:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index +// CHECK: fir.if %[[VAL_34]] { +// CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_35]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_36]], %[[VAL_37]], %[[VAL_38]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test character array with constant length and heap allocation. +func.func @_QPtest4(%arg0: !fir.box>> {fir.bindc_name = "x"}) { + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost : (!fir.box>>) -> !fir.box>> + %2 = fir.declare %1 typeparams %c10 dummy_scope %0 {uniq_name = "_QFtest4Ex"} : (!fir.box>>, index, !fir.dscope) -> !fir.box>> + fir.unpack_array %1 to %arg0 heap : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest4( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_7:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_9:.*]] = fir.if %[[VAL_8]] -> (!fir.box>>) { +// CHECK: %[[VAL_10:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_11:.*]] = arith.cmpi eq, %[[VAL_10]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_12:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_12]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_14:.*]] = arith.andi %[[VAL_11]], %[[VAL_13]] : i1 +// CHECK: %[[VAL_15:.*]] = fir.if %[[VAL_14]] -> (!fir.box>>) { +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_16]]#1, %[[VAL_17]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_19:.*]] = fir.allocmem !fir.array>, %[[VAL_16]]#1, %[[VAL_17]]#1 {bindc_name = ".repacked", uniq_name = ""} +// CHECK: %[[VAL_20:.*]] = fir.declare %[[VAL_19]](%[[VAL_18]]) typeparams %[[VAL_6]] {uniq_name = ".repacked"} : (!fir.heap>>, !fir.shape<2>, index) -> !fir.heap>> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_20]](%[[VAL_18]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.box>>> +// CHECK: %[[VAL_22:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_21]] : (!fir.box>>>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_22]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_26:.*]] = fir.shift %[[VAL_16]]#0, %[[VAL_17]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_27:.*]] = fir.rebox %[[VAL_21]](%[[VAL_26]]) : (!fir.box>>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_27]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_15]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_28:.*]] = fir.declare %[[VAL_9]] typeparams %[[VAL_6]] dummy_scope %[[VAL_7]] {uniq_name = "_QFtest4Ex"} : (!fir.box>>, index, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_29:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_29]] { +// CHECK: %[[VAL_30:.*]] = fir.box_addr %[[VAL_9]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_32:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index +// CHECK: fir.if %[[VAL_34]] { +// CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_9]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_35]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_36]], %[[VAL_37]], %[[VAL_38]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_30]] : !fir.heap>> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test character array with constant length and stack allocation. +func.func @_QPtest4_stack(%arg0: !fir.box>> {fir.bindc_name = "x"}) { + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 stack innermost : (!fir.box>>) -> !fir.box>> + %2 = fir.declare %1 typeparams %c10 dummy_scope %0 {uniq_name = "_QFtest4_stackEx"} : (!fir.box>>, index, !fir.dscope) -> !fir.box>> + fir.unpack_array %1 to %arg0 stack : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest4_stack( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_7:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_9:.*]] = fir.if %[[VAL_8]] -> (!fir.box>>) { +// CHECK: %[[VAL_10:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_11:.*]] = arith.cmpi eq, %[[VAL_10]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_12:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_13:.*]] = fir.is_present %[[VAL_12]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_14:.*]] = arith.andi %[[VAL_11]], %[[VAL_13]] : i1 +// CHECK: %[[VAL_15:.*]] = fir.if %[[VAL_14]] -> (!fir.box>>) { +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_16]]#1, %[[VAL_17]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_19:.*]] = fir.alloca !fir.array>, %[[VAL_16]]#1, %[[VAL_17]]#1 {bindc_name = ".repacked"} +// CHECK: %[[VAL_20:.*]] = fir.declare %[[VAL_19]](%[[VAL_18]]) typeparams %[[VAL_6]] {uniq_name = ".repacked"} : (!fir.ref>>, !fir.shape<2>, index) -> !fir.ref>> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_20]](%[[VAL_18]]) : (!fir.ref>>, !fir.shape<2>) -> !fir.box>> +// CHECK: %[[VAL_22:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_21]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_22]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_26:.*]] = fir.shift %[[VAL_16]]#0, %[[VAL_17]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_27:.*]] = fir.rebox %[[VAL_21]](%[[VAL_26]]) : (!fir.box>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_27]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_15]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_28:.*]] = fir.declare %[[VAL_9]] typeparams %[[VAL_6]] dummy_scope %[[VAL_7]] {uniq_name = "_QFtest4_stackEx"} : (!fir.box>>, index, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_29:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_29]] { +// CHECK: %[[VAL_30:.*]] = fir.box_addr %[[VAL_9]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_32:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_34:.*]] = arith.cmpi ne, %[[VAL_31]], %[[VAL_33]] : index +// CHECK: fir.if %[[VAL_34]] { +// CHECK: %[[VAL_35:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_9]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_35]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_36]], %[[VAL_37]], %[[VAL_38]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test derived type array with heap allocation. +func.func @_QPtest5(%arg0: !fir.box>> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost : (!fir.box>>) -> !fir.box>> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest5Ex"} : (!fir.box>>, !fir.dscope) -> !fir.box>> + fir.unpack_array %1 to %arg0 heap : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest5( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_7]] -> (!fir.box>>) { +// CHECK: %[[VAL_9:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_10:.*]] = arith.cmpi eq, %[[VAL_9]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_18:.*]] = fir.allocmem !fir.array>, %[[VAL_15]]#1, %[[VAL_16]]#1 {bindc_name = ".repacked", uniq_name = ""} +// CHECK: %[[VAL_19:.*]] = fir.declare %[[VAL_18]](%[[VAL_17]]) {uniq_name = ".repacked"} : (!fir.heap>>, !fir.shape<2>) -> !fir.heap>> +// CHECK: %[[VAL_20:.*]] = fir.embox %[[VAL_19]](%[[VAL_17]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.box>>> +// CHECK: %[[VAL_21:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_20]] : (!fir.box>>>) -> !fir.box +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_21]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_22]], %[[VAL_23]], %[[VAL_24]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.shift %[[VAL_15]]#0, %[[VAL_16]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_26:.*]] = fir.rebox %[[VAL_20]](%[[VAL_25]]) : (!fir.box>>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_26]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_14]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_27:.*]] = fir.declare %[[VAL_8]] dummy_scope %[[VAL_6]] {uniq_name = "_QFtest5Ex"} : (!fir.box>>, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_28:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_28]] { +// CHECK: %[[VAL_29:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_31:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index +// CHECK: fir.if %[[VAL_33]] { +// CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_34]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_35]], %[[VAL_36]], %[[VAL_37]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_29]] : !fir.heap>> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test derived type array with stack allocation. +func.func @_QPtest5_stack(%arg0: !fir.box>> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 stack innermost : (!fir.box>>) -> !fir.box>> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest5_stackEx"} : (!fir.box>>, !fir.dscope) -> !fir.box>> + fir.unpack_array %1 to %arg0 stack : !fir.box>> + return +} +// CHECK-LABEL: func.func @_QPtest5_stack( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.box>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = arith.constant false +// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_7]] -> (!fir.box>>) { +// CHECK: %[[VAL_9:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.box>>) -> i1 +// CHECK: %[[VAL_10:.*]] = arith.cmpi eq, %[[VAL_9]], %[[VAL_5]] : i1 +// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.ref>>> +// CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_10]], %[[VAL_12]] : i1 +// CHECK: %[[VAL_14:.*]] = fir.if %[[VAL_13]] -> (!fir.box>>) { +// CHECK: %[[VAL_15:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_16:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_3]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_15]]#1, %[[VAL_16]]#1 : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_18:.*]] = fir.alloca !fir.array>, %[[VAL_15]]#1, %[[VAL_16]]#1 {bindc_name = ".repacked"} +// CHECK: %[[VAL_19:.*]] = fir.declare %[[VAL_18]](%[[VAL_17]]) {uniq_name = ".repacked"} : (!fir.ref>>, !fir.shape<2>) -> !fir.ref>> +// CHECK: %[[VAL_20:.*]] = fir.embox %[[VAL_19]](%[[VAL_17]]) : (!fir.ref>>, !fir.shape<2>) -> !fir.box>> +// CHECK: %[[VAL_21:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_20]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_21]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_22]], %[[VAL_23]], %[[VAL_24]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.shift %[[VAL_15]]#0, %[[VAL_16]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_26:.*]] = fir.rebox %[[VAL_20]](%[[VAL_25]]) : (!fir.box>>, !fir.shift<2>) -> !fir.box>> +// CHECK: fir.result %[[VAL_26]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: fir.result %[[VAL_14]] : !fir.box>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.box>> +// CHECK: } +// CHECK: %[[VAL_27:.*]] = fir.declare %[[VAL_8]] dummy_scope %[[VAL_6]] {uniq_name = "_QFtest5_stackEx"} : (!fir.box>>, !fir.dscope) -> !fir.box>> +// CHECK: %[[VAL_28:.*]] = fir.is_present %[[VAL_0]] : (!fir.box>>) -> i1 +// CHECK: fir.if %[[VAL_28]] { +// CHECK: %[[VAL_29:.*]] = fir.box_addr %[[VAL_8]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_31:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_33:.*]] = arith.cmpi ne, %[[VAL_30]], %[[VAL_32]] : index +// CHECK: fir.if %[[VAL_33]] { +// CHECK: %[[VAL_34:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_8]] : (!fir.box>>) -> !fir.box +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_34]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_35]], %[[VAL_36]], %[[VAL_37]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test polymorphic type array with heap allocation. +func.func @_QPtest6(%arg0: !fir.class>> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost : (!fir.class>>) -> !fir.class>> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest6Ex"} : (!fir.class>>, !fir.dscope) -> !fir.class>> + fir.unpack_array %1 to %arg0 heap : !fir.class>> + return +} +// CHECK-LABEL: func.func @_QPtest6( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.class>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_4:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant false +// CHECK: %[[VAL_7:.*]] = fir.alloca !fir.class>>> +// CHECK: %[[VAL_8:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>>) -> i1 +// CHECK: %[[VAL_10:.*]] = fir.if %[[VAL_9]] -> (!fir.class>>) { +// CHECK: %[[VAL_11:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.class>>) -> i1 +// CHECK: %[[VAL_12:.*]] = arith.cmpi eq, %[[VAL_11]], %[[VAL_6]] : i1 +// CHECK: %[[VAL_13:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>>) -> !fir.ref>>> +// CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_13]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_15:.*]] = arith.andi %[[VAL_12]], %[[VAL_14]] : i1 +// CHECK: %[[VAL_16:.*]] = fir.if %[[VAL_15]] -> (!fir.class>>) { +// CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_5]] : (!fir.class>>, index) -> (index, index, index) +// CHECK: %[[VAL_18:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.class>>, index) -> (index, index, index) +// CHECK: %[[VAL_19:.*]] = fir.zero_bits !fir.heap>> +// CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_5]], %[[VAL_5]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_19]](%[[VAL_20]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.class>>> +// CHECK: fir.store %[[VAL_21]] to %[[VAL_7]] : !fir.ref>>>> +// CHECK: %[[VAL_22:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = ".repacked"} : (!fir.ref>>>>) -> !fir.ref>>>> +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: fir.call @_FortranAAllocatableApplyMold(%[[VAL_23]], %[[VAL_24]], %[[VAL_3]]) : (!fir.ref>, !fir.box, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_5]] : (index) -> i32 +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_17]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_25]], %[[VAL_26]], %[[VAL_27]], %[[VAL_28]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_4]] : (index) -> i32 +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_18]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_29]], %[[VAL_30]], %[[VAL_31]], %[[VAL_32]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_33:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_34:.*]] = fir.absent !fir.box +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_33]] : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_37:.*]] = fir.call @_FortranAAllocatableAllocate(%[[VAL_35]], %[[VAL_6]], %[[VAL_34]], %[[VAL_36]], %[[VAL_2]]) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +// CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_22]] : !fir.ref>>>> +// CHECK: %[[VAL_39:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.class>>>) -> !fir.box +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_39]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_40]], %[[VAL_41]], %[[VAL_42]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_43:.*]] = fir.shift %[[VAL_17]]#0, %[[VAL_18]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_44:.*]] = fir.rebox %[[VAL_38]](%[[VAL_43]]) : (!fir.class>>>, !fir.shift<2>) -> !fir.class>> +// CHECK: fir.result %[[VAL_44]] : !fir.class>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class>> +// CHECK: } +// CHECK: fir.result %[[VAL_16]] : !fir.class>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class>> +// CHECK: } +// CHECK: %[[VAL_45:.*]] = fir.declare %[[VAL_10]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest6Ex"} : (!fir.class>>, !fir.dscope) -> !fir.class>> +// CHECK: %[[VAL_46:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>>) -> i1 +// CHECK: fir.if %[[VAL_46]] { +// CHECK: %[[VAL_47:.*]] = fir.box_addr %[[VAL_10]] : (!fir.class>>) -> !fir.heap>> +// CHECK: %[[VAL_49:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>>) -> !fir.heap>> +// CHECK: %[[VAL_48:.*]] = fir.convert %[[VAL_47]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_50:.*]] = fir.convert %[[VAL_49]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_51:.*]] = arith.cmpi ne, %[[VAL_48]], %[[VAL_50]] : index +// CHECK: fir.if %[[VAL_51]] { +// CHECK: %[[VAL_52:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_53:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_10]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_52]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_53]], %[[VAL_54]], %[[VAL_55]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_47]] : !fir.heap>> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test polymorphic type array with requested stack allocation. +// The actual allocation is done in heap memory. +func.func @_QPtest6_stack(%arg0: !fir.class>> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 stack innermost : (!fir.class>>) -> !fir.class>> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest6_stackEx"} : (!fir.class>>, !fir.dscope) -> !fir.class>> + fir.unpack_array %1 to %arg0 stack : !fir.class>> + return +} +// CHECK-LABEL: func.func @_QPtest6_stack( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.class>> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_4:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant false +// CHECK: %[[VAL_7:.*]] = fir.alloca !fir.class>>> +// CHECK: %[[VAL_8:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>>) -> i1 +// CHECK: %[[VAL_10:.*]] = fir.if %[[VAL_9]] -> (!fir.class>>) { +// CHECK: %[[VAL_11:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.class>>) -> i1 +// CHECK: %[[VAL_12:.*]] = arith.cmpi eq, %[[VAL_11]], %[[VAL_6]] : i1 +// CHECK: %[[VAL_13:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>>) -> !fir.ref>>> +// CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_13]] : (!fir.ref>>>) -> i1 +// CHECK: %[[VAL_15:.*]] = arith.andi %[[VAL_12]], %[[VAL_14]] : i1 +// CHECK: %[[VAL_16:.*]] = fir.if %[[VAL_15]] -> (!fir.class>>) { +// CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_5]] : (!fir.class>>, index) -> (index, index, index) +// CHECK: %[[VAL_18:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.class>>, index) -> (index, index, index) +// CHECK: %[[VAL_19:.*]] = fir.zero_bits !fir.heap>> +// CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_5]], %[[VAL_5]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_19]](%[[VAL_20]]) : (!fir.heap>>, !fir.shape<2>) -> !fir.class>>> +// CHECK: fir.store %[[VAL_21]] to %[[VAL_7]] : !fir.ref>>>> +// CHECK: %[[VAL_22:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = ".repacked"} : (!fir.ref>>>>) -> !fir.ref>>>> +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: fir.call @_FortranAAllocatableApplyMold(%[[VAL_23]], %[[VAL_24]], %[[VAL_3]]) : (!fir.ref>, !fir.box, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_5]] : (index) -> i32 +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_17]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_25]], %[[VAL_26]], %[[VAL_27]], %[[VAL_28]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_4]] : (index) -> i32 +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_18]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_29]], %[[VAL_30]], %[[VAL_31]], %[[VAL_32]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_33:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_34:.*]] = fir.absent !fir.box +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_33]] : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_37:.*]] = fir.call @_FortranAAllocatableAllocate(%[[VAL_35]], %[[VAL_6]], %[[VAL_34]], %[[VAL_36]], %[[VAL_2]]) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +// CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_22]] : !fir.ref>>>> +// CHECK: %[[VAL_39:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.class>>>) -> !fir.box +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_39]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_40]], %[[VAL_41]], %[[VAL_42]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_43:.*]] = fir.shift %[[VAL_17]]#0, %[[VAL_18]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_44:.*]] = fir.rebox %[[VAL_38]](%[[VAL_43]]) : (!fir.class>>>, !fir.shift<2>) -> !fir.class>> +// CHECK: fir.result %[[VAL_44]] : !fir.class>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class>> +// CHECK: } +// CHECK: fir.result %[[VAL_16]] : !fir.class>> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class>> +// CHECK: } +// CHECK: %[[VAL_45:.*]] = fir.declare %[[VAL_10]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest6_stackEx"} : (!fir.class>>, !fir.dscope) -> !fir.class>> +// CHECK: %[[VAL_46:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>>) -> i1 +// CHECK: fir.if %[[VAL_46]] { +// CHECK: %[[VAL_47:.*]] = fir.box_addr %[[VAL_10]] : (!fir.class>>) -> !fir.heap>> +// CHECK: %[[VAL_49:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>>) -> !fir.heap>> +// CHECK: %[[VAL_48:.*]] = fir.convert %[[VAL_47]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_50:.*]] = fir.convert %[[VAL_49]] : (!fir.heap>>) -> index +// CHECK: %[[VAL_51:.*]] = arith.cmpi ne, %[[VAL_48]], %[[VAL_50]] : index +// CHECK: fir.if %[[VAL_51]] { +// CHECK: %[[VAL_52:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_53:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_10]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_52]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_53]], %[[VAL_54]], %[[VAL_55]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_47]] : !fir.heap>> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test unlimited polymorphic type array with heap allocation. +func.func @_QPtest7(%arg0: !fir.class> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 heap innermost : (!fir.class>) -> !fir.class> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest7Ex"} : (!fir.class>, !fir.dscope) -> !fir.class> + fir.unpack_array %1 to %arg0 heap : !fir.class> + return +} +// CHECK-LABEL: func.func @_QPtest7( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.class> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_4:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant false +// CHECK: %[[VAL_7:.*]] = fir.alloca !fir.class>> +// CHECK: %[[VAL_8:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>) -> i1 +// CHECK: %[[VAL_10:.*]] = fir.if %[[VAL_9]] -> (!fir.class>) { +// CHECK: %[[VAL_11:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.class>) -> i1 +// CHECK: %[[VAL_12:.*]] = arith.cmpi eq, %[[VAL_11]], %[[VAL_6]] : i1 +// CHECK: %[[VAL_13:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>) -> !fir.ref>> +// CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_13]] : (!fir.ref>>) -> i1 +// CHECK: %[[VAL_15:.*]] = arith.andi %[[VAL_12]], %[[VAL_14]] : i1 +// CHECK: %[[VAL_16:.*]] = fir.if %[[VAL_15]] -> (!fir.class>) { +// CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_5]] : (!fir.class>, index) -> (index, index, index) +// CHECK: %[[VAL_18:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.class>, index) -> (index, index, index) +// CHECK: %[[VAL_19:.*]] = fir.zero_bits !fir.heap> +// CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_5]], %[[VAL_5]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_19]](%[[VAL_20]]) : (!fir.heap>, !fir.shape<2>) -> !fir.class>> +// CHECK: fir.store %[[VAL_21]] to %[[VAL_7]] : !fir.ref>>> +// CHECK: %[[VAL_22:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = ".repacked"} : (!fir.ref>>>) -> !fir.ref>>> +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.class>) -> !fir.box +// CHECK: fir.call @_FortranAAllocatableApplyMold(%[[VAL_23]], %[[VAL_24]], %[[VAL_3]]) : (!fir.ref>, !fir.box, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_5]] : (index) -> i32 +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_17]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_25]], %[[VAL_26]], %[[VAL_27]], %[[VAL_28]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_4]] : (index) -> i32 +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_18]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_29]], %[[VAL_30]], %[[VAL_31]], %[[VAL_32]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_33:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_34:.*]] = fir.absent !fir.box +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_33]] : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_37:.*]] = fir.call @_FortranAAllocatableAllocate(%[[VAL_35]], %[[VAL_6]], %[[VAL_34]], %[[VAL_36]], %[[VAL_2]]) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +// CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_22]] : !fir.ref>>> +// CHECK: %[[VAL_39:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_0]] : (!fir.class>) -> !fir.box +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_39]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_40]], %[[VAL_41]], %[[VAL_42]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_43:.*]] = fir.shift %[[VAL_17]]#0, %[[VAL_18]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_44:.*]] = fir.rebox %[[VAL_38]](%[[VAL_43]]) : (!fir.class>>, !fir.shift<2>) -> !fir.class> +// CHECK: fir.result %[[VAL_44]] : !fir.class> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class> +// CHECK: } +// CHECK: fir.result %[[VAL_16]] : !fir.class> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class> +// CHECK: } +// CHECK: %[[VAL_45:.*]] = fir.declare %[[VAL_10]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest7Ex"} : (!fir.class>, !fir.dscope) -> !fir.class> +// CHECK: %[[VAL_46:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>) -> i1 +// CHECK: fir.if %[[VAL_46]] { +// CHECK: %[[VAL_47:.*]] = fir.box_addr %[[VAL_10]] : (!fir.class>) -> !fir.heap> +// CHECK: %[[VAL_49:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>) -> !fir.heap> +// CHECK: %[[VAL_48:.*]] = fir.convert %[[VAL_47]] : (!fir.heap>) -> index +// CHECK: %[[VAL_50:.*]] = fir.convert %[[VAL_49]] : (!fir.heap>) -> index +// CHECK: %[[VAL_51:.*]] = arith.cmpi ne, %[[VAL_48]], %[[VAL_50]] : index +// CHECK: fir.if %[[VAL_51]] { +// CHECK: %[[VAL_52:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_53:.*]] = fir.convert %[[VAL_0]] : (!fir.class>) -> !fir.box +// CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_10]] : (!fir.class>) -> !fir.box +// CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_52]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_53]], %[[VAL_54]], %[[VAL_55]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_47]] : !fir.heap> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: } + +// Test unlimited polymorphic type array with requested stack allocation. +// The actual allocation is done in heap memory. +func.func @_QPtest7_stack(%arg0: !fir.class> {fir.bindc_name = "x"}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.pack_array %arg0 stack innermost : (!fir.class>) -> !fir.class> + %2 = fir.declare %1 dummy_scope %0 {uniq_name = "_QFtest7Ex"} : (!fir.class>, !fir.dscope) -> !fir.class> + fir.unpack_array %1 to %arg0 stack : !fir.class> + return +} +// CHECK-LABEL: func.func @_QPtest7_stack( +// CHECK-SAME: %[[VAL_0:[0-9]+|[a-zA-Z$._-][a-zA-Z0-9$._-]*]]: !fir.class> {fir.bindc_name = "x"}) { +// CHECK: %[[VAL_1:.*]] = arith.constant +// CHECK: %[[VAL_2:.*]] = arith.constant +// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_4:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant false +// CHECK: %[[VAL_7:.*]] = fir.alloca !fir.class>> +// CHECK: %[[VAL_8:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_9:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>) -> i1 +// CHECK: %[[VAL_10:.*]] = fir.if %[[VAL_9]] -> (!fir.class>) { +// CHECK: %[[VAL_11:.*]] = fir.is_contiguous_box %[[VAL_0]] innermost : (!fir.class>) -> i1 +// CHECK: %[[VAL_12:.*]] = arith.cmpi eq, %[[VAL_11]], %[[VAL_6]] : i1 +// CHECK: %[[VAL_13:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>) -> !fir.ref>> +// CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_13]] : (!fir.ref>>) -> i1 +// CHECK: %[[VAL_15:.*]] = arith.andi %[[VAL_12]], %[[VAL_14]] : i1 +// CHECK: %[[VAL_16:.*]] = fir.if %[[VAL_15]] -> (!fir.class>) { +// CHECK: %[[VAL_17:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_5]] : (!fir.class>, index) -> (index, index, index) +// CHECK: %[[VAL_18:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_4]] : (!fir.class>, index) -> (index, index, index) +// CHECK: %[[VAL_19:.*]] = fir.zero_bits !fir.heap> +// CHECK: %[[VAL_20:.*]] = fir.shape %[[VAL_5]], %[[VAL_5]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_19]](%[[VAL_20]]) : (!fir.heap>, !fir.shape<2>) -> !fir.class>> +// CHECK: fir.store %[[VAL_21]] to %[[VAL_7]] : !fir.ref>>> +// CHECK: %[[VAL_22:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = ".repacked"} : (!fir.ref>>>) -> !fir.ref>>> +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_0]] : (!fir.class>) -> !fir.box +// CHECK: fir.call @_FortranAAllocatableApplyMold(%[[VAL_23]], %[[VAL_24]], %[[VAL_3]]) : (!fir.ref>, !fir.box, i32) -> () +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_5]] : (index) -> i32 +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_17]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_25]], %[[VAL_26]], %[[VAL_27]], %[[VAL_28]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_4]] : (index) -> i32 +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_4]] : (index) -> i64 +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_18]]#1 : (index) -> i64 +// CHECK: fir.call @_FortranAAllocatableSetBounds(%[[VAL_29]], %[[VAL_30]], %[[VAL_31]], %[[VAL_32]]) : (!fir.ref>, i32, i64, i64) -> () +// CHECK: %[[VAL_33:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_34:.*]] = fir.absent !fir.box +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_7]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_33]] : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_37:.*]] = fir.call @_FortranAAllocatableAllocate(%[[VAL_35]], %[[VAL_6]], %[[VAL_34]], %[[VAL_36]], %[[VAL_2]]) : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 +// CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_22]] : !fir.ref>>> +// CHECK: %[[VAL_39:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_0]] : (!fir.class>) -> !fir.box +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_39]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_40]], %[[VAL_41]], %[[VAL_42]], %[[VAL_2]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: %[[VAL_43:.*]] = fir.shift %[[VAL_17]]#0, %[[VAL_18]]#0 : (index, index) -> !fir.shift<2> +// CHECK: %[[VAL_44:.*]] = fir.rebox %[[VAL_38]](%[[VAL_43]]) : (!fir.class>>, !fir.shift<2>) -> !fir.class> +// CHECK: fir.result %[[VAL_44]] : !fir.class> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class> +// CHECK: } +// CHECK: fir.result %[[VAL_16]] : !fir.class> +// CHECK: } else { +// CHECK: fir.result %[[VAL_0]] : !fir.class> +// CHECK: } +// CHECK: %[[VAL_45:.*]] = fir.declare %[[VAL_10]] dummy_scope %[[VAL_8]] {uniq_name = "_QFtest7Ex"} : (!fir.class>, !fir.dscope) -> !fir.class> +// CHECK: %[[VAL_46:.*]] = fir.is_present %[[VAL_0]] : (!fir.class>) -> i1 +// CHECK: fir.if %[[VAL_46]] { +// CHECK: %[[VAL_47:.*]] = fir.box_addr %[[VAL_10]] : (!fir.class>) -> !fir.heap> +// CHECK: %[[VAL_49:.*]] = fir.box_addr %[[VAL_0]] : (!fir.class>) -> !fir.heap> +// CHECK: %[[VAL_48:.*]] = fir.convert %[[VAL_47]] : (!fir.heap>) -> index +// CHECK: %[[VAL_50:.*]] = fir.convert %[[VAL_49]] : (!fir.heap>) -> index +// CHECK: %[[VAL_51:.*]] = arith.cmpi ne, %[[VAL_48]], %[[VAL_50]] : index +// CHECK: fir.if %[[VAL_51]] { +// CHECK: %[[VAL_52:.*]] = fir.address_of(@{{_QQcl.*}} +// CHECK: %[[VAL_53:.*]] = fir.convert %[[VAL_0]] : (!fir.class>) -> !fir.box +// CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_10]] : (!fir.class>) -> !fir.box +// CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_52]] : (!fir.ref>) -> !fir.ref +// CHECK: fir.call @_FortranAShallowCopyDirect(%[[VAL_53]], %[[VAL_54]], %[[VAL_55]], %[[VAL_1]]) : (!fir.box, !fir.box, !fir.ref, i32) -> () +// CHECK: fir.freemem %[[VAL_47]] : !fir.heap> +// CHECK: } +// CHECK: } +// CHECK: return +// CHECK: }