diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp index b6d692a0226cd..086dd66711602 100644 --- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp +++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp @@ -416,7 +416,10 @@ hlfir::Entity hlfir::loadTrivialScalar(mlir::Location loc, entity = derefPointersAndAllocatables(loc, builder, entity); if (entity.isVariable() && entity.isScalar() && fir::isa_trivial(entity.getFortranElementType())) { - return Entity{fir::LoadOp::create(builder, loc, entity)}; + // Optional entities may be represented with !fir.box. + // We need to take the data pointer before loading the scalar. + mlir::Value base = genVariableRawAddress(loc, builder, entity); + return Entity{fir::LoadOp::create(builder, loc, base)}; } return entity; } diff --git a/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp b/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp index b27c3a8526945..fe12f49c655b8 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/SimplifyHLFIRIntrinsics.cpp @@ -10,6 +10,7 @@ // into the calling function. //===----------------------------------------------------------------------===// +#include "flang/Optimizer/Builder/Character.h" #include "flang/Optimizer/Builder/Complex.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/HLFIRTools.h" @@ -1269,64 +1270,91 @@ class ReductionConversion : public mlir::OpRewritePattern { } }; -class CShiftConversion : public mlir::OpRewritePattern { +template +class ArrayShiftConversion : public mlir::OpRewritePattern { public: - using mlir::OpRewritePattern::OpRewritePattern; + // The implementation below only support CShiftOp and EOShiftOp. + static_assert(std::is_same_v || + std::is_same_v); + + using mlir::OpRewritePattern::OpRewritePattern; llvm::LogicalResult - matchAndRewrite(hlfir::CShiftOp cshift, - mlir::PatternRewriter &rewriter) const override { + matchAndRewrite(Op op, mlir::PatternRewriter &rewriter) const override { - hlfir::ExprType expr = mlir::dyn_cast(cshift.getType()); + hlfir::ExprType expr = mlir::dyn_cast(op.getType()); assert(expr && - "expected an expression type for the result of hlfir.cshift"); + "expected an expression type for the result of the array shift"); unsigned arrayRank = expr.getRank(); - // When it is a 1D CSHIFT, we may assume that the DIM argument + // When it is a 1D CSHIFT/EOSHIFT, we may assume that the DIM argument // (whether it is present or absent) is equal to 1, otherwise, // the program is illegal. int64_t dimVal = 1; if (arrayRank != 1) - if (mlir::Value dim = cshift.getDim()) { + if (mlir::Value dim = op.getDim()) { auto constDim = fir::getIntIfConstant(dim); if (!constDim) - return rewriter.notifyMatchFailure(cshift, - "Nonconstant DIM for CSHIFT"); + return rewriter.notifyMatchFailure( + op, "Nonconstant DIM for CSHIFT/EOSHIFT"); dimVal = *constDim; } if (dimVal <= 0 || dimVal > arrayRank) - return rewriter.notifyMatchFailure(cshift, "Invalid DIM for CSHIFT"); + return rewriter.notifyMatchFailure(op, "Invalid DIM for CSHIFT/EOSHIFT"); + + if constexpr (std::is_same_v) { + // TODO: the EOSHIFT inlining code is not ready to produce + // fir.if selecting between ARRAY and BOUNDARY (or the default + // boundary value), when they are expressions of type CHARACTER. + // This needs more work. + if (mlir::isa(expr.getEleTy())) { + if (!hlfir::Entity{op.getArray()}.isVariable()) + return rewriter.notifyMatchFailure( + op, "EOSHIFT with ARRAY being CHARACTER expression"); + if (op.getBoundary() && !hlfir::Entity{op.getBoundary()}.isVariable()) + return rewriter.notifyMatchFailure( + op, "EOSHIFT with BOUNDARY being CHARACTER expression"); + } + // TODO: selecting between ARRAY and BOUNDARY values with derived types + // need more work. + if (fir::isa_derived(expr.getEleTy())) + return rewriter.notifyMatchFailure(op, "EOSHIFT of derived type"); + } // When DIM==1 and the contiguity of the input array is not statically // known, try to exploit the fact that the leading dimension might be // contiguous. We can do this now using hlfir.eval_in_mem with // a dynamic check for the leading dimension contiguity. - // Otherwise, convert hlfir.cshift to hlfir.elemental. + // Otherwise, convert hlfir.cshift/eoshift to hlfir.elemental. // // Note that the hlfir.elemental can be inlined into other hlfir.elemental, // while hlfir.eval_in_mem prevents this, and we will end up creating // a temporary array for the result. We may need to come up with // a more sophisticated logic for picking the most efficient // representation. - hlfir::Entity array = hlfir::Entity{cshift.getArray()}; + hlfir::Entity array = hlfir::Entity{op.getArray()}; mlir::Type elementType = array.getFortranElementType(); if (dimVal == 1 && fir::isa_trivial(elementType) && - // genInMemCShift() only works for variables currently. + // genInMemArrayShift() only works for variables currently. array.isVariable()) - rewriter.replaceOp(cshift, genInMemCShift(rewriter, cshift, dimVal)); + rewriter.replaceOp(op, genInMemArrayShift(rewriter, op, dimVal)); else - rewriter.replaceOp(cshift, genElementalCShift(rewriter, cshift, dimVal)); + rewriter.replaceOp(op, genElementalArrayShift(rewriter, op, dimVal)); return mlir::success(); } private: - /// Generate MODULO(\p shiftVal, \p extent). + /// For CSHIFT, generate MODULO(\p shiftVal, \p extent). + /// For EOSHIFT, return \p shiftVal casted to \p calcType. static mlir::Value normalizeShiftValue(mlir::Location loc, fir::FirOpBuilder &builder, mlir::Value shiftVal, mlir::Value extent, mlir::Type calcType) { shiftVal = builder.createConvert(loc, calcType, shiftVal); + if constexpr (std::is_same_v) + return shiftVal; + extent = builder.createConvert(loc, calcType, extent); // Make sure that we do not divide by zero. When the dimension // has zero size, turn the extent into 1. Note that the computed @@ -1342,24 +1370,227 @@ class CShiftConversion : public mlir::OpRewritePattern { return builder.createConvert(loc, calcType, shiftVal); } - /// Convert \p cshift into an hlfir.elemental using + /// The indices computations for the array shifts are done using I64 type. + /// For CSHIFT, all computations do not overflow signed and unsigned I64. + /// For EOSHIFT, some computations may involve negative shift values, + /// so using no-unsigned wrap flag would be incorrect. + static void setArithOverflowFlags(Op op, fir::FirOpBuilder &builder) { + if constexpr (std::is_same_v) + builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw); + else + builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw | + mlir::arith::IntegerOverflowFlags::nuw); + } + + /// Return the element type of the EOSHIFT boundary that may be omitted + /// statically or dynamically. This element type might be used + /// to generate MLIR where we have to select between the default + /// boundary value and the dynamically absent/present boundary value. + /// If the boundary has a type not defined in Table 16.4 in 16.9.77 + /// of F2023, then the return value is nullptr. + static mlir::Type getDefaultBoundaryValueType(mlir::Type elementType) { + // To be able to generate a "select" between the default boundary value + // and the dynamic boundary value, use BoxCharType for the CHARACTER + // cases. This might be a little bit inefficient, because we may + // create unnecessary tuples, but it simplifies the inlining code. + if (auto charTy = mlir::dyn_cast(elementType)) + return fir::BoxCharType::get(charTy.getContext(), charTy.getFKind()); + + if (mlir::isa(elementType) || + fir::isa_integer(elementType) || fir::isa_real(elementType) || + fir::isa_complex(elementType)) + return elementType; + + return nullptr; + } + + /// Generate the default boundary value as defined in Table 16.4 in 16.9.77 + /// of F2023. + static mlir::Value genDefaultBoundary(mlir::Location loc, + fir::FirOpBuilder &builder, + mlir::Type elementType) { + assert(getDefaultBoundaryValueType(elementType) && + "default boundary value cannot be computed for the given type"); + if (mlir::isa(elementType)) { + // Create an empty CHARACTER of the same kind. The assignment + // of this empty CHARACTER into the result will add the padding + // if necessary. + fir::factory::CharacterExprHelper charHelper{builder, loc}; + mlir::Value zeroLen = builder.createIntegerConstant( + loc, builder.getCharacterLengthType(), 0); + fir::CharBoxValue emptyCharTemp = + charHelper.createCharacterTemp(elementType, zeroLen); + return charHelper.createEmbox(emptyCharTemp); + } + + return fir::factory::createZeroValue(builder, loc, elementType); + } + + /// \p entity represents the boundary operand of hlfir.eoshift. + /// This method generates a scalar boundary value fetched + /// from the boundary entity using \p indices (which may be empty, + /// if the boundary operand is scalar). + static mlir::Value loadEoshiftVal(mlir::Location loc, + fir::FirOpBuilder &builder, + hlfir::Entity entity, + mlir::ValueRange indices = {}) { + hlfir::Entity boundaryVal = + hlfir::loadElementAt(loc, builder, entity, indices); + + mlir::Type boundaryValTy = + getDefaultBoundaryValueType(entity.getFortranElementType()); + + // Boxed !fir.char with known LEN are loaded + // as raw references to !fir.char. + // We need to wrap them into the !fir.boxchar. + if (boundaryVal.isVariable() && boundaryValTy && + mlir::isa(boundaryValTy)) + return hlfir::genVariableBoxChar(loc, builder, boundaryVal); + return boundaryVal; + } + + /// This method generates a scalar boundary value for the given hlfir.eoshift + /// \p op that can be used to initialize cells of the result + /// if the scalar/array boundary operand is statically or dynamically + /// absent. The first result is the scalar boundary value. The second result + /// is a dynamic predicate indicating whether the scalar boundary value + /// should actually be used. + [[maybe_unused]] static std::pair + genScalarBoundaryForEOShift(mlir::Location loc, fir::FirOpBuilder &builder, + hlfir::EOShiftOp op) { + hlfir::Entity array{op.getArray()}; + mlir::Type elementType = array.getFortranElementType(); + + if (!op.getBoundary()) { + // Boundary operand is statically absent. + mlir::Value defaultVal = genDefaultBoundary(loc, builder, elementType); + mlir::Value boundaryIsScalarPred = builder.createBool(loc, true); + return {defaultVal, boundaryIsScalarPred}; + } + + hlfir::Entity boundary{op.getBoundary()}; + mlir::Type boundaryValTy = getDefaultBoundaryValueType(elementType); + + if (boundary.isScalar()) { + if (!boundaryValTy || !boundary.mayBeOptional()) { + // The boundary must be present. + mlir::Value boundaryVal = loadEoshiftVal(loc, builder, boundary); + mlir::Value boundaryIsScalarPred = builder.createBool(loc, true); + return {boundaryVal, boundaryIsScalarPred}; + } + + // Boundary is a scalar that may be dynamically absent. + // If boundary is not present dynamically, we must use the default + // value. + assert(mlir::isa(boundary.getType())); + mlir::Value isPresentPred = + fir::IsPresentOp::create(builder, loc, builder.getI1Type(), boundary); + mlir::Value boundaryVal = + builder + .genIfOp(loc, {boundaryValTy}, isPresentPred, + /*withElseRegion=*/true) + .genThen([&]() { + mlir::Value boundaryVal = + loadEoshiftVal(loc, builder, boundary); + fir::ResultOp::create(builder, loc, boundaryVal); + }) + .genElse([&]() { + mlir::Value defaultVal = + genDefaultBoundary(loc, builder, elementType); + fir::ResultOp::create(builder, loc, defaultVal); + }) + .getResults()[0]; + mlir::Value boundaryIsScalarPred = builder.createBool(loc, true); + return {boundaryVal, boundaryIsScalarPred}; + } + if (!boundaryValTy || !boundary.mayBeOptional()) { + // The boundary must be present + mlir::Value boundaryIsScalarPred = builder.createBool(loc, false); + return {nullptr, boundaryIsScalarPred}; + } + + // Boundary is an array that may be dynamically absent. + mlir::Value defaultVal = genDefaultBoundary(loc, builder, elementType); + mlir::Value isPresentPred = + fir::IsPresentOp::create(builder, loc, builder.getI1Type(), boundary); + // If the array is present, then boundaryIsScalarPred must be equal + // to false, otherwise, it should be true. + mlir::Value trueVal = builder.createBool(loc, true); + mlir::Value falseVal = builder.createBool(loc, false); + mlir::Value boundaryIsScalarPred = mlir::arith::SelectOp::create( + builder, loc, isPresentPred, falseVal, trueVal); + return {defaultVal, boundaryIsScalarPred}; + } + + /// Generate code that produces the final boundary value to be assigned + /// to the result of hlfir.eoshift \p op. \p precomputedScalarBoundary + /// specifies the scalar boundary value pre-computed before the elemental + /// or the assignment loop. If it is nullptr, then the boundary operand + /// of \p op must be a present array. \p boundaryIsScalarPred is a dynamic + /// predicate that is true, when the pre-computed scalar value must be used. + /// \p oneBasedIndices specify the indices to address into the boundary + /// array - they may be empty, if the boundary is scalar. + [[maybe_unused]] static mlir::Value selectBoundaryValue( + mlir::Location loc, fir::FirOpBuilder &builder, hlfir::EOShiftOp op, + mlir::Value precomputedScalarBoundary, mlir::Value boundaryIsScalarPred, + mlir::ValueRange oneBasedIndices) { + // Boundary is statically absent: a default value has been precomputed. + if (!op.getBoundary()) + return precomputedScalarBoundary; + + // Boundary is statically present and is a scalar: boundary does not depend + // upon the indices and so it has been precomputed. + hlfir::Entity boundary{op.getBoundary()}; + if (boundary.isScalar()) + return precomputedScalarBoundary; + + // Boundary is statically present and is an array: if the scalar + // boundary has not been precomputed, this means that the data type + // of the shifted values does not provide a way to compute + // the default boundary value, so the array boundary must be dynamically + // present, and we can load the boundary values from it. + bool mustBePresent = !precomputedScalarBoundary; + if (mustBePresent) + return loadEoshiftVal(loc, builder, boundary, oneBasedIndices); + + // The array boundary may be dynamically absent. + // In this case, precomputedScalarBoundary is a pre-computed scalar + // boundary value that has to be used if boundaryIsScalarPred + // is true, otherwise, the boundary value has to be loaded + // from the boundary array. + mlir::Type boundaryValTy = precomputedScalarBoundary.getType(); + mlir::Value newBoundaryVal = + builder + .genIfOp(loc, {boundaryValTy}, boundaryIsScalarPred, + /*withElseRegion=*/true) + .genThen([&]() { + fir::ResultOp::create(builder, loc, precomputedScalarBoundary); + }) + .genElse([&]() { + mlir::Value elem = + loadEoshiftVal(loc, builder, boundary, oneBasedIndices); + fir::ResultOp::create(builder, loc, elem); + }) + .getResults()[0]; + return newBoundaryVal; + } + + /// Convert \p op into an hlfir.elemental using /// the pre-computed constant \p dimVal. - static mlir::Operation *genElementalCShift(mlir::PatternRewriter &rewriter, - hlfir::CShiftOp cshift, - int64_t dimVal) { + static mlir::Operation * + genElementalArrayShift(mlir::PatternRewriter &rewriter, Op op, + int64_t dimVal) { using Fortran::common::maxRank; - hlfir::Entity shift = hlfir::Entity{cshift.getShift()}; - hlfir::Entity array = hlfir::Entity{cshift.getArray()}; + hlfir::Entity shift = hlfir::Entity{op.getShift()}; + hlfir::Entity array = hlfir::Entity{op.getArray()}; - mlir::Location loc = cshift.getLoc(); - fir::FirOpBuilder builder{rewriter, cshift.getOperation()}; + mlir::Location loc = op.getLoc(); + fir::FirOpBuilder builder{rewriter, op.getOperation()}; // The new index computation involves MODULO, which is not implemented // for IndexType, so use I64 instead. mlir::Type calcType = builder.getI64Type(); - // All the indices arithmetic used below does not overflow - // signed and unsigned I64. - builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw | - mlir::arith::IntegerOverflowFlags::nuw); + // Set the indices arithmetic overflow flags. + setArithOverflowFlags(op, builder); mlir::Value arrayShape = hlfir::genShape(loc, builder, array); llvm::SmallVector arrayExtents = @@ -1374,6 +1605,17 @@ class CShiftConversion : public mlir::OpRewritePattern { shiftVal = normalizeShiftValue(loc, builder, shiftVal, shiftDimExtent, calcType); } + // The boundary operand of hlfir.eoshift may be statically or + // dynamically absent. + // In both cases, it is assumed to be a scalar with the value + // corresponding to the array element type. + // boundaryIsScalarPred is a dynamic predicate that identifies + // these cases. If boundaryIsScalarPred is dynamicaly false, + // then the boundary operand must be a present array. + mlir::Value boundaryVal, boundaryIsScalarPred; + if constexpr (std::is_same_v) + std::tie(boundaryVal, boundaryIsScalarPred) = + genScalarBoundaryForEOShift(loc, builder, op); auto genKernel = [&](mlir::Location loc, fir::FirOpBuilder &builder, mlir::ValueRange inputIndices) -> hlfir::Entity { @@ -1394,34 +1636,84 @@ class CShiftConversion : public mlir::OpRewritePattern { shiftVal = normalizeShiftValue(loc, builder, shiftVal, shiftDimExtent, calcType); } + if constexpr (std::is_same_v) { + llvm::SmallVector boundaryIndices{indices}; + boundaryIndices.erase(boundaryIndices.begin() + dimVal - 1); + boundaryVal = + selectBoundaryValue(loc, builder, op, boundaryVal, + boundaryIsScalarPred, boundaryIndices); + } - // Element i of the result (1-based) is element - // 'MODULO(i + SH - 1, SIZE(ARRAY,DIM)) + 1' (1-based) of the original - // ARRAY (or its section, when ARRAY is not a vector). - - // Compute the index into the original array using the normalized - // shift value, which satisfies (SH >= 0 && SH < SIZE(ARRAY,DIM)): - // newIndex = - // i + ((i <= SIZE(ARRAY,DIM) - SH) ? SH : SH - SIZE(ARRAY,DIM)) - // - // Such index computation allows for further loop vectorization - // in LLVM. - mlir::Value wrapBound = - mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, shiftVal); - mlir::Value adjustedShiftVal = - mlir::arith::SubIOp::create(builder, loc, shiftVal, shiftDimExtent); - mlir::Value index = - builder.createConvert(loc, calcType, inputIndices[dimVal - 1]); - mlir::Value wrapCheck = mlir::arith::CmpIOp::create( - builder, loc, mlir::arith::CmpIPredicate::sle, index, wrapBound); - mlir::Value actualShift = mlir::arith::SelectOp::create( - builder, loc, wrapCheck, shiftVal, adjustedShiftVal); - mlir::Value newIndex = - mlir::arith::AddIOp::create(builder, loc, index, actualShift); - newIndex = builder.createConvert(loc, builder.getIndexType(), newIndex); - indices[dimVal - 1] = newIndex; - hlfir::Entity element = hlfir::getElementAt(loc, builder, array, indices); - return hlfir::loadTrivialScalar(loc, builder, element); + if constexpr (std::is_same_v) { + // EOSHIFT: + // Element i of the result (1-based) is the element of the original + // array (or its section, when ARRAY is not a vector) with index + // (i + SH), if (1 <= i + SH <= SIZE(ARRAY,DIM)), otherwise + // it is the BOUNDARY value. + mlir::Value index = + builder.createConvert(loc, calcType, inputIndices[dimVal - 1]); + mlir::arith::IntegerOverflowFlags savedFlags = + builder.getIntegerOverflowFlags(); + builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw); + mlir::Value indexPlusShift = + mlir::arith::AddIOp::create(builder, loc, index, shiftVal); + builder.setIntegerOverflowFlags(savedFlags); + mlir::Value one = builder.createIntegerConstant(loc, calcType, 1); + mlir::Value cmp1 = mlir::arith::CmpIOp::create( + builder, loc, mlir::arith::CmpIPredicate::sge, indexPlusShift, one); + mlir::Value cmp2 = mlir::arith::CmpIOp::create( + builder, loc, mlir::arith::CmpIPredicate::sle, indexPlusShift, + shiftDimExtent); + mlir::Value loadFromArray = + mlir::arith::AndIOp::create(builder, loc, cmp1, cmp2); + mlir::Type boundaryValTy = boundaryVal.getType(); + mlir::Value result = + builder + .genIfOp(loc, {boundaryValTy}, loadFromArray, + /*withElseRegion=*/true) + .genThen([&]() { + indices[dimVal - 1] = builder.createConvert( + loc, builder.getIndexType(), indexPlusShift); + ; + mlir::Value elem = + loadEoshiftVal(loc, builder, array, indices); + fir::ResultOp::create(builder, loc, elem); + }) + .genElse( + [&]() { fir::ResultOp::create(builder, loc, boundaryVal); }) + .getResults()[0]; + return hlfir::Entity{result}; + } else { + // CSHIFT: + // Element i of the result (1-based) is element + // 'MODULO(i + SH - 1, SIZE(ARRAY,DIM)) + 1' (1-based) of the original + // ARRAY (or its section, when ARRAY is not a vector). + + // Compute the index into the original array using the normalized + // shift value, which satisfies (SH >= 0 && SH < SIZE(ARRAY,DIM)): + // newIndex = + // i + ((i <= SIZE(ARRAY,DIM) - SH) ? SH : SH - SIZE(ARRAY,DIM)) + // + // Such index computation allows for further loop vectorization + // in LLVM. + mlir::Value wrapBound = + mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, shiftVal); + mlir::Value adjustedShiftVal = + mlir::arith::SubIOp::create(builder, loc, shiftVal, shiftDimExtent); + mlir::Value index = + builder.createConvert(loc, calcType, inputIndices[dimVal - 1]); + mlir::Value wrapCheck = mlir::arith::CmpIOp::create( + builder, loc, mlir::arith::CmpIPredicate::sle, index, wrapBound); + mlir::Value actualShift = mlir::arith::SelectOp::create( + builder, loc, wrapCheck, shiftVal, adjustedShiftVal); + mlir::Value newIndex = + mlir::arith::AddIOp::create(builder, loc, index, actualShift); + newIndex = builder.createConvert(loc, builder.getIndexType(), newIndex); + indices[dimVal - 1] = newIndex; + hlfir::Entity element = + hlfir::getElementAt(loc, builder, array, indices); + return hlfir::loadTrivialScalar(loc, builder, element); + } }; mlir::Type elementType = array.getFortranElementType(); @@ -1429,19 +1721,42 @@ class CShiftConversion : public mlir::OpRewritePattern { loc, builder, elementType, arrayShape, typeParams, genKernel, /*isUnordered=*/true, array.isPolymorphic() ? static_cast(array) : nullptr, - cshift.getResult().getType()); + op.getResult().getType()); return elementalOp.getOperation(); } - /// Convert \p cshift into an hlfir.eval_in_mem using the pre-computed + /// Convert \p op into an hlfir.eval_in_mem using the pre-computed /// constant \p dimVal. - /// The converted code looks like this: - /// do i=1,SH - /// result(i + (SIZE(ARRAY,DIM) - SH)) = array(i) + /// The converted code for CSHIFT looks like this: + /// DEST_OFFSET = SIZE(ARRAY,DIM) - SH + /// COPY_END1 = SH + /// do i=1,COPY_END1 + /// result(i + DEST_OFFSET) = array(i) + /// end + /// SOURCE_OFFSET = SH + /// COPY_END2 = SIZE(ARRAY,DIM) - SH + /// do i=1,COPY_END2 + /// result(i) = array(i + SOURCE_OFFSET) + /// end + /// Where SH is the normalized shift value, which satisfies + /// (SH >= 0 && SH < SIZE(ARRAY,DIM)). + /// + /// The converted code for EOSHIFT looks like this: + /// EXTENT = SIZE(ARRAY,DIM) + /// DEST_OFFSET = SH < 0 ? -SH : 0 + /// SOURCE_OFFSET = SH < 0 ? 0 : SH + /// COPY_END = SH < 0 ? + /// (-EXTENT > SH ? 0 : EXTENT + SH) : + /// (EXTENT < SH ? 0 : EXTENT - SH) + /// do i=1,COPY_END + /// result(i + DEST_OFFSET) = array(i + SOURCE_OFFSET) /// end - /// do i=1,SIZE(ARRAY,DIM) - SH - /// result(i) = array(i + SH) + /// INIT_END = EXTENT - COPY_END + /// INIT_OFFSET = SH < 0 ? 0 : COPY_END + /// do i=1,INIT_END + /// result(i + INIT_OFFSET) = BOUNDARY /// end + /// Where SH is the original shift value. /// /// When \p dimVal is 1, we generate the same code twice /// under a dynamic check for the contiguity of the leading @@ -1450,24 +1765,21 @@ class CShiftConversion : public mlir::OpRewritePattern { /// as a contiguous slice of the original array. /// This allows recognizing the above two loops as memcpy /// loop idioms in LLVM. - static mlir::Operation *genInMemCShift(mlir::PatternRewriter &rewriter, - hlfir::CShiftOp cshift, - int64_t dimVal) { + static mlir::Operation *genInMemArrayShift(mlir::PatternRewriter &rewriter, + Op op, int64_t dimVal) { using Fortran::common::maxRank; - hlfir::Entity shift = hlfir::Entity{cshift.getShift()}; - hlfir::Entity array = hlfir::Entity{cshift.getArray()}; + hlfir::Entity shift = hlfir::Entity{op.getShift()}; + hlfir::Entity array = hlfir::Entity{op.getArray()}; assert(array.isVariable() && "array must be a variable"); assert(!array.isPolymorphic() && - "genInMemCShift does not support polymorphic types"); - mlir::Location loc = cshift.getLoc(); - fir::FirOpBuilder builder{rewriter, cshift.getOperation()}; + "genInMemArrayShift does not support polymorphic types"); + mlir::Location loc = op.getLoc(); + fir::FirOpBuilder builder{rewriter, op.getOperation()}; // The new index computation involves MODULO, which is not implemented // for IndexType, so use I64 instead. mlir::Type calcType = builder.getI64Type(); - // All the indices arithmetic used below does not overflow - // signed and unsigned I64. - builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw | - mlir::arith::IntegerOverflowFlags::nuw); + // Set the indices arithmetic overflow flags. + setArithOverflowFlags(op, builder); mlir::Value arrayShape = hlfir::genShape(loc, builder, array); llvm::SmallVector arrayExtents = @@ -1482,10 +1794,20 @@ class CShiftConversion : public mlir::OpRewritePattern { shiftVal = normalizeShiftValue(loc, builder, shiftVal, shiftDimExtent, calcType); } + // The boundary operand of hlfir.eoshift may be statically or + // dynamically absent. + // In both cases, it is assumed to be a scalar with the value + // corresponding to the array element type. + // boundaryIsScalarPred is a dynamic predicate that identifies + // these cases. If boundaryIsScalarPred is dynamicaly false, + // then the boundary operand must be a present array. + mlir::Value boundaryVal, boundaryIsScalarPred; + if constexpr (std::is_same_v) + std::tie(boundaryVal, boundaryIsScalarPred) = + genScalarBoundaryForEOShift(loc, builder, op); hlfir::EvaluateInMemoryOp evalOp = hlfir::EvaluateInMemoryOp::create( - builder, loc, mlir::cast(cshift.getType()), - arrayShape); + builder, loc, mlir::cast(op.getType()), arrayShape); builder.setInsertionPointToStart(&evalOp.getBody().front()); mlir::Value resultArray = evalOp.getMemory(); @@ -1499,11 +1821,12 @@ class CShiftConversion : public mlir::OpRewritePattern { // (if any). If exposeContiguity is true, the array's section // array(s(1), ..., s(dim-1), :, s(dim+1), ..., s(n)) is represented // as a contiguous 1D array. - // shiftVal is the normalized shift value that satisfies (SH >= 0 && SH < - // SIZE(ARRAY,DIM)). + // For CSHIFT, shiftVal is the normalized shift value that satisfies + // (SH >= 0 && SH < SIZE(ARRAY,DIM)). // auto genDimensionShift = [&](mlir::Location loc, fir::FirOpBuilder &builder, - mlir::Value shiftVal, bool exposeContiguity, + mlir::Value shiftVal, mlir::Value boundary, + bool exposeContiguity, mlir::ValueRange oneBasedIndices) -> llvm::SmallVector { // Create a vector of indices (s(1), ..., s(dim-1), nullptr, s(dim+1), @@ -1536,63 +1859,143 @@ class CShiftConversion : public mlir::OpRewritePattern { srcIndices.resize(1); } - // Copy first portion of the array: - // do i=1,SH - // result(i + (SIZE(ARRAY,DIM) - SH)) = array(i) - // end - auto genAssign1 = [&](mlir::Location loc, fir::FirOpBuilder &builder, - mlir::ValueRange index, - mlir::ValueRange reductionArgs) + // genCopy labda generates the body of a generic copy loop. + // do i=1,COPY_END + // result(i + DEST_OFFSET) = array(i + SOURCE_OFFSET) + // end + // + // It is parameterized by DEST_OFFSET and SOURCE_OFFSET. + mlir::Value dstOffset, srcOffset; + auto genCopy = [&](mlir::Location loc, fir::FirOpBuilder &builder, + mlir::ValueRange index, mlir::ValueRange reductionArgs) -> llvm::SmallVector { assert(index.size() == 1 && "expected single loop"); mlir::Value srcIndex = builder.createConvert(loc, calcType, index[0]); + mlir::Value dstIndex = srcIndex; + if (srcOffset) + srcIndex = + mlir::arith::AddIOp::create(builder, loc, srcIndex, srcOffset); srcIndices[dimVal - 1] = srcIndex; hlfir::Entity srcElementValue = hlfir::loadElementAt(loc, builder, srcArray, srcIndices); - mlir::Value dstIndex = mlir::arith::AddIOp::create( - builder, loc, srcIndex, - mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, - shiftVal)); - dstIndices[dimVal - 1] = dstIndex; - hlfir::Entity dstElement = hlfir::getElementAt( - loc, builder, hlfir::Entity{resultArray}, dstIndices); - hlfir::AssignOp::create(builder, loc, srcElementValue, dstElement); - return {}; - }; - - // Generate the first loop. - hlfir::genLoopNestWithReductions(loc, builder, {shiftVal}, - /*reductionInits=*/{}, genAssign1, - /*isUnordered=*/true); - - // Copy second portion of the array: - // do i=1,SIZE(ARRAY,DIM)-SH - // result(i) = array(i + SH) - // end - auto genAssign2 = [&](mlir::Location loc, fir::FirOpBuilder &builder, - mlir::ValueRange index, - mlir::ValueRange reductionArgs) - -> llvm::SmallVector { - assert(index.size() == 1 && "expected single loop"); - mlir::Value dstIndex = builder.createConvert(loc, calcType, index[0]); - mlir::Value srcIndex = - mlir::arith::AddIOp::create(builder, loc, dstIndex, shiftVal); - srcIndices[dimVal - 1] = srcIndex; - hlfir::Entity srcElementValue = - hlfir::loadElementAt(loc, builder, srcArray, srcIndices); + if (dstOffset) + dstIndex = + mlir::arith::AddIOp::create(builder, loc, dstIndex, dstOffset); dstIndices[dimVal - 1] = dstIndex; hlfir::Entity dstElement = hlfir::getElementAt( loc, builder, hlfir::Entity{resultArray}, dstIndices); hlfir::AssignOp::create(builder, loc, srcElementValue, dstElement); + // Reset the external parameters' values to make sure + // they are properly updated between the labda calls. + // WARNING: if genLoopNestWithReductions() calls the lambda + // multiple times, this is going to be a problem. + dstOffset = nullptr; + srcOffset = nullptr; return {}; }; - // Generate the second loop. - mlir::Value bound = - mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, shiftVal); - hlfir::genLoopNestWithReductions(loc, builder, {bound}, - /*reductionInits=*/{}, genAssign2, - /*isUnordered=*/true); + if constexpr (std::is_same_v) { + // Copy first portion of the array: + // DEST_OFFSET = SIZE(ARRAY,DIM) - SH + // COPY_END1 = SH + // do i=1,COPY_END1 + // result(i + DEST_OFFSET) = array(i) + // end + dstOffset = + mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, shiftVal); + srcOffset = nullptr; + hlfir::genLoopNestWithReductions(loc, builder, {shiftVal}, + /*reductionInits=*/{}, genCopy, + /*isUnordered=*/true); + + // Copy second portion of the array: + // SOURCE_OFFSET = SH + // COPY_END2 = SIZE(ARRAY,DIM) - SH + // do i=1,COPY_END2 + // result(i) = array(i + SOURCE_OFFSET) + // end + mlir::Value bound = + mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, shiftVal); + dstOffset = nullptr; + srcOffset = shiftVal; + hlfir::genLoopNestWithReductions(loc, builder, {bound}, + /*reductionInits=*/{}, genCopy, + /*isUnordered=*/true); + } else { + // Do the copy: + // EXTENT = SIZE(ARRAY,DIM) + // DEST_OFFSET = SH < 0 ? -SH : 0 + // SOURCE_OFFSET = SH < 0 ? 0 : SH + // COPY_END = SH < 0 ? + // (-EXTENT > SH ? 0 : EXTENT + SH) : + // (EXTENT < SH ? 0 : EXTENT - SH) + // do i=1,COPY_END + // result(i + DEST_OFFSET) = array(i + SOURCE_OFFSET) + // end + mlir::arith::IntegerOverflowFlags savedFlags = + builder.getIntegerOverflowFlags(); + builder.setIntegerOverflowFlags(mlir::arith::IntegerOverflowFlags::nsw); + + mlir::Value zero = builder.createIntegerConstant(loc, calcType, 0); + mlir::Value isNegativeShift = mlir::arith::CmpIOp::create( + builder, loc, mlir::arith::CmpIPredicate::slt, shiftVal, zero); + mlir::Value shiftNeg = + mlir::arith::SubIOp::create(builder, loc, zero, shiftVal); + dstOffset = mlir::arith::SelectOp::create(builder, loc, isNegativeShift, + shiftNeg, zero); + srcOffset = mlir::arith::SelectOp::create(builder, loc, isNegativeShift, + zero, shiftVal); + mlir::Value extentNeg = + mlir::arith::SubIOp::create(builder, loc, zero, shiftDimExtent); + mlir::Value extentPlusShift = + mlir::arith::AddIOp::create(builder, loc, shiftDimExtent, shiftVal); + mlir::Value extentNegShiftCmp = mlir::arith::CmpIOp::create( + builder, loc, mlir::arith::CmpIPredicate::sgt, extentNeg, shiftVal); + mlir::Value negativeShiftBound = mlir::arith::SelectOp::create( + builder, loc, extentNegShiftCmp, zero, extentPlusShift); + mlir::Value extentMinusShift = + mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, shiftVal); + mlir::Value extentShiftCmp = mlir::arith::CmpIOp::create( + builder, loc, mlir::arith::CmpIPredicate::slt, shiftDimExtent, + shiftVal); + mlir::Value positiveShiftBound = mlir::arith::SelectOp::create( + builder, loc, extentShiftCmp, zero, extentMinusShift); + mlir::Value copyEnd = mlir::arith::SelectOp::create( + builder, loc, isNegativeShift, negativeShiftBound, + positiveShiftBound); + hlfir::genLoopNestWithReductions(loc, builder, {copyEnd}, + /*reductionInits=*/{}, genCopy, + /*isUnordered=*/true); + + // Do the init: + // INIT_END = EXTENT - COPY_END + // INIT_OFFSET = SH < 0 ? 0 : COPY_END + // do i=1,INIT_END + // result(i + INIT_OFFSET) = BOUNDARY + // end + assert(boundary && "boundary cannot be null"); + mlir::Value initEnd = + mlir::arith::SubIOp::create(builder, loc, shiftDimExtent, copyEnd); + mlir::Value initOffset = mlir::arith::SelectOp::create( + builder, loc, isNegativeShift, zero, copyEnd); + auto genInit = [&](mlir::Location loc, fir::FirOpBuilder &builder, + mlir::ValueRange index, + mlir::ValueRange reductionArgs) + -> llvm::SmallVector { + mlir::Value dstIndex = builder.createConvert(loc, calcType, index[0]); + dstIndex = + mlir::arith::AddIOp::create(builder, loc, dstIndex, initOffset); + dstIndices[dimVal - 1] = dstIndex; + hlfir::Entity dstElement = hlfir::getElementAt( + loc, builder, hlfir::Entity{resultArray}, dstIndices); + hlfir::AssignOp::create(builder, loc, boundary, dstElement); + return {}; + }; + hlfir::genLoopNestWithReductions(loc, builder, {initEnd}, + /*reductionInits=*/{}, genInit, + /*isUnordered=*/true); + builder.setIntegerOverflowFlags(savedFlags); + } return {}; }; @@ -1614,6 +2017,10 @@ class CShiftConversion : public mlir::OpRewritePattern { shiftVal = normalizeShiftValue(loc, builder, shiftVal, shiftDimExtent, calcType); } + if constexpr (std::is_same_v) + boundaryVal = + selectBoundaryValue(loc, builder, op, boundaryVal, + boundaryIsScalarPred, oneBasedIndices); // If we can fetch the byte stride of the leading dimension, // and the byte size of the element, then we can generate @@ -1635,8 +2042,8 @@ class CShiftConversion : public mlir::OpRewritePattern { } if (array.isSimplyContiguous() || !elemSize || !stride) { - genDimensionShift(loc, builder, shiftVal, /*exposeContiguity=*/false, - oneBasedIndices); + genDimensionShift(loc, builder, shiftVal, boundaryVal, + /*exposeContiguity=*/false, oneBasedIndices); return {}; } @@ -1644,11 +2051,11 @@ class CShiftConversion : public mlir::OpRewritePattern { builder, loc, mlir::arith::CmpIPredicate::eq, elemSize, stride); builder.genIfOp(loc, {}, isContiguous, /*withElseRegion=*/true) .genThen([&]() { - genDimensionShift(loc, builder, shiftVal, /*exposeContiguity=*/true, - oneBasedIndices); + genDimensionShift(loc, builder, shiftVal, boundaryVal, + /*exposeContiguity=*/true, oneBasedIndices); }) .genElse([&]() { - genDimensionShift(loc, builder, shiftVal, + genDimensionShift(loc, builder, shiftVal, boundaryVal, /*exposeContiguity=*/false, oneBasedIndices); }); @@ -2339,7 +2746,8 @@ class SimplifyHLFIRIntrinsics mlir::RewritePatternSet patterns(context); patterns.insert(context); patterns.insert>(context); - patterns.insert(context); + patterns.insert>(context); + patterns.insert>(context); patterns.insert>(context); patterns.insert>(context); diff --git a/flang/test/HLFIR/simplify-hlfir-intrinsics-cshift.fir b/flang/test/HLFIR/simplify-hlfir-intrinsics-cshift.fir index 8684a429ea5b4..f5af990da194c 100644 --- a/flang/test/HLFIR/simplify-hlfir-intrinsics-cshift.fir +++ b/flang/test/HLFIR/simplify-hlfir-intrinsics-cshift.fir @@ -38,12 +38,12 @@ func.func @cshift_vector(%arg0: !fir.box>, %arg1: !fir.ref>, index, index, index, !fir.shape<1>) -> !fir.box> // CHECK: %[[VAL_25:.*]] = fir.box_addr %[[VAL_24]] : (!fir.box>) -> !fir.ref> // CHECK: %[[VAL_26:.*]] = fir.embox %[[VAL_25]](%[[VAL_23]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> +// CHECK: %[[VAL_36:.*]] = arith.subi %[[VAL_8]], %[[VAL_17]] overflow : i64 // CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_17]] : (i64) -> index // CHECK: fir.do_loop %[[VAL_28:.*]] = %[[VAL_2]] to %[[VAL_27]] step %[[VAL_2]] unordered { // CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_28]] : (index) -> i64 // CHECK: %[[VAL_34:.*]] = hlfir.designate %[[VAL_26]] (%[[VAL_29]]) : (!fir.box>, i64) -> !fir.ref // CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_34]] : !fir.ref -// CHECK: %[[VAL_36:.*]] = arith.subi %[[VAL_8]], %[[VAL_17]] overflow : i64 // CHECK: %[[VAL_37:.*]] = arith.addi %[[VAL_29]], %[[VAL_36]] overflow : i64 // CHECK: %[[VAL_42:.*]] = hlfir.designate %[[VAL_20]] (%[[VAL_37]]) : (!fir.box>, i64) -> !fir.ref // CHECK: hlfir.assign %[[VAL_35]] to %[[VAL_42]] : i32, !fir.ref @@ -59,6 +59,7 @@ func.func @cshift_vector(%arg0: !fir.box>, %arg1: !fir.ref // CHECK: } // CHECK: } else { +// CHECK: %[[VAL_68:.*]] = arith.subi %[[VAL_8]], %[[VAL_17]] overflow : i64 // CHECK: %[[VAL_59:.*]] = fir.convert %[[VAL_17]] : (i64) -> index // CHECK: fir.do_loop %[[VAL_60:.*]] = %[[VAL_2]] to %[[VAL_59]] step %[[VAL_2]] unordered { // CHECK: %[[VAL_61:.*]] = fir.convert %[[VAL_60]] : (index) -> i64 @@ -68,7 +69,6 @@ func.func @cshift_vector(%arg0: !fir.box>, %arg1: !fir.ref : index // CHECK: %[[VAL_66:.*]] = hlfir.designate %[[VAL_0]] (%[[VAL_65]]) : (!fir.box>, index) -> !fir.ref // CHECK: %[[VAL_67:.*]] = fir.load %[[VAL_66]] : !fir.ref -// CHECK: %[[VAL_68:.*]] = arith.subi %[[VAL_8]], %[[VAL_17]] overflow : i64 // CHECK: %[[VAL_69:.*]] = arith.addi %[[VAL_61]], %[[VAL_68]] overflow : i64 // CHECK: %[[VAL_74:.*]] = hlfir.designate %[[VAL_20]] (%[[VAL_69]]) : (!fir.box>, i64) -> !fir.ref // CHECK: hlfir.assign %[[VAL_67]] to %[[VAL_74]] : i32, !fir.ref diff --git a/flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir b/flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir new file mode 100644 index 0000000000000..88191d517c2b5 --- /dev/null +++ b/flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir @@ -0,0 +1,2210 @@ +// Test hlfir.eoshift simplification to hlfir.elemental and hlfir.eval_in_mem: +// RUN: fir-opt --simplify-hlfir-intrinsics %s | FileCheck %s + +// module eoshift_types +// type t +// end type t +// end module eoshift_types +// +// ! Test contiguous 1D array with statically absent boundary. +// subroutine eoshift1(n, array) +// integer :: n +// real(2) :: array(n) +// array = EOSHIFT(array, 2) +// end subroutine +func.func @_QPeoshift1(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref> {fir.bindc_name = "array"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift1En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2 = fir.load %1#0 : !fir.ref + %3 = fir.convert %2 : (i32) -> index + %4 = arith.cmpi sgt, %3, %c0 : index + %5 = arith.select %4, %3, %c0 : index + %6 = fir.shape %5 : (index) -> !fir.shape<1> + %7:2 = hlfir.declare %arg1(%6) dummy_scope %0 {uniq_name = "_QFeoshift1Earray"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.box>, !fir.ref>) + %8 = hlfir.eoshift %7#0 %c2_i32 : (!fir.box>, i32) -> !hlfir.expr + hlfir.assign %8 to %7#0 : !hlfir.expr, !fir.box> + hlfir.destroy %8 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @_QPeoshift1( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref> {fir.bindc_name = "array"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_2:.*]] = arith.constant 0.000000e+00 : f16 +// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift1En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> index +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_4]] : index +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_4]] : index +// CHECK: %[[VAL_11:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[ARG1]](%[[VAL_11]]) dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift1Earray"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.box>, !fir.ref>) +// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (index) -> i64 +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_3]] : (i32) -> i64 +// CHECK: %[[VAL_15:.*]] = hlfir.eval_in_mem shape %[[VAL_11]] : (!fir.shape<1>) -> !hlfir.expr { +// CHECK: ^bb0(%[[VAL_16:.*]]: !fir.ref>): +// CHECK: %[[VAL_17:.*]] = fir.embox %[[VAL_16]](%[[VAL_11]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> +// CHECK: %[[VAL_18:.*]] = arith.cmpi slt, %[[VAL_14]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_19:.*]] = arith.subi %[[VAL_1]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_18]], %[[VAL_19]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_18]], %[[VAL_1]], %[[VAL_14]] : i64 +// CHECK: %[[VAL_22:.*]] = arith.subi %[[VAL_1]], %[[VAL_13]] overflow : i64 +// CHECK: %[[VAL_23:.*]] = arith.addi %[[VAL_13]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_24:.*]] = arith.cmpi sgt, %[[VAL_22]], %[[VAL_14]] : i64 +// CHECK: %[[VAL_25:.*]] = arith.select %[[VAL_24]], %[[VAL_1]], %[[VAL_23]] : i64 +// CHECK: %[[VAL_26:.*]] = arith.subi %[[VAL_13]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_27:.*]] = arith.cmpi slt, %[[VAL_13]], %[[VAL_14]] : i64 +// CHECK: %[[VAL_28:.*]] = arith.select %[[VAL_27]], %[[VAL_1]], %[[VAL_26]] : i64 +// CHECK: %[[VAL_29:.*]] = arith.select %[[VAL_18]], %[[VAL_25]], %[[VAL_28]] : i64 +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_31:.*]] = %[[VAL_0]] to %[[VAL_30]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (index) -> i64 +// CHECK: %[[VAL_33:.*]] = arith.addi %[[VAL_32]], %[[VAL_21]] overflow : i64 +// CHECK: %[[VAL_34:.*]] = hlfir.designate %[[VAL_12]]#0 (%[[VAL_33]]) : (!fir.box>, i64) -> !fir.ref +// CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_34]] : !fir.ref +// CHECK: %[[VAL_36:.*]] = arith.addi %[[VAL_32]], %[[VAL_20]] overflow : i64 +// CHECK: %[[VAL_37:.*]] = hlfir.designate %[[VAL_17]] (%[[VAL_36]]) : (!fir.box>, i64) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_35]] to %[[VAL_37]] : f16, !fir.ref +// CHECK: } +// CHECK: %[[VAL_38:.*]] = arith.subi %[[VAL_13]], %[[VAL_29]] overflow : i64 +// CHECK: %[[VAL_39:.*]] = arith.select %[[VAL_18]], %[[VAL_1]], %[[VAL_29]] : i64 +// CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_38]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_41:.*]] = %[[VAL_0]] to %[[VAL_40]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_41]] : (index) -> i64 +// CHECK: %[[VAL_43:.*]] = arith.addi %[[VAL_42]], %[[VAL_39]] overflow : i64 +// CHECK: %[[VAL_44:.*]] = hlfir.designate %[[VAL_17]] (%[[VAL_43]]) : (!fir.box>, i64) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_44]] : f16, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_12]]#0 : !hlfir.expr, !fir.box> +// CHECK: hlfir.destroy %[[VAL_15]] : !hlfir.expr +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the scalar constant boundary. +// subroutine eoshift2(n, array) +// integer :: n +// logical(2) :: array(n) +// array = EOSHIFT(array, 2, boundary=.true._2, dim=1) +// end subroutine +func.func @_QPeoshift2(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref>> {fir.bindc_name = "array"}) { + %c1_i32 = arith.constant 1 : i32 + %true = arith.constant true + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift2En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2 = fir.load %1#0 : !fir.ref + %3 = fir.convert %2 : (i32) -> index + %4 = arith.cmpi sgt, %3, %c0 : index + %5 = arith.select %4, %3, %c0 : index + %6 = fir.shape %5 : (index) -> !fir.shape<1> + %7:2 = hlfir.declare %arg1(%6) dummy_scope %0 {uniq_name = "_QFeoshift2Earray"} : (!fir.ref>>, !fir.shape<1>, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %8 = fir.convert %true : (i1) -> !fir.logical<2> + %9 = hlfir.eoshift %7#0 %c2_i32 boundary %8 dim %c1_i32 : (!fir.box>>, i32, !fir.logical<2>, i32) -> !hlfir.expr> + hlfir.assign %9 to %7#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %9 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift2( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref>> {fir.bindc_name = "array"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_2:.*]] = arith.constant true +// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift2En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> index +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_4]] : index +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_4]] : index +// CHECK: %[[VAL_11:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[ARG1]](%[[VAL_11]]) dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift2Earray"} : (!fir.ref>>, !fir.shape<1>, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_2]] : (i1) -> !fir.logical<2> +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_10]] : (index) -> i64 +// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_3]] : (i32) -> i64 +// CHECK: %[[VAL_16:.*]] = hlfir.eval_in_mem shape %[[VAL_11]] : (!fir.shape<1>) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_17:.*]]: !fir.ref>>): +// CHECK: %[[VAL_18:.*]] = fir.embox %[[VAL_17]](%[[VAL_11]]) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> +// CHECK: %[[VAL_19:.*]] = arith.cmpi slt, %[[VAL_15]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_1]], %[[VAL_15]] overflow : i64 +// CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_19]], %[[VAL_20]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_22:.*]] = arith.select %[[VAL_19]], %[[VAL_1]], %[[VAL_15]] : i64 +// CHECK: %[[VAL_23:.*]] = arith.subi %[[VAL_1]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_24:.*]] = arith.addi %[[VAL_14]], %[[VAL_15]] overflow : i64 +// CHECK: %[[VAL_25:.*]] = arith.cmpi sgt, %[[VAL_23]], %[[VAL_15]] : i64 +// CHECK: %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_1]], %[[VAL_24]] : i64 +// CHECK: %[[VAL_27:.*]] = arith.subi %[[VAL_14]], %[[VAL_15]] overflow : i64 +// CHECK: %[[VAL_28:.*]] = arith.cmpi slt, %[[VAL_14]], %[[VAL_15]] : i64 +// CHECK: %[[VAL_29:.*]] = arith.select %[[VAL_28]], %[[VAL_1]], %[[VAL_27]] : i64 +// CHECK: %[[VAL_30:.*]] = arith.select %[[VAL_19]], %[[VAL_26]], %[[VAL_29]] : i64 +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_32:.*]] = %[[VAL_0]] to %[[VAL_31]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (index) -> i64 +// CHECK: %[[VAL_34:.*]] = arith.addi %[[VAL_33]], %[[VAL_22]] overflow : i64 +// CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_12]]#0 (%[[VAL_34]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: %[[VAL_36:.*]] = fir.load %[[VAL_35]] : !fir.ref> +// CHECK: %[[VAL_37:.*]] = arith.addi %[[VAL_33]], %[[VAL_21]] overflow : i64 +// CHECK: %[[VAL_38:.*]] = hlfir.designate %[[VAL_18]] (%[[VAL_37]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: hlfir.assign %[[VAL_36]] to %[[VAL_38]] : !fir.logical<2>, !fir.ref> +// CHECK: } +// CHECK: %[[VAL_39:.*]] = arith.subi %[[VAL_14]], %[[VAL_30]] overflow : i64 +// CHECK: %[[VAL_40:.*]] = arith.select %[[VAL_19]], %[[VAL_1]], %[[VAL_30]] : i64 +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_39]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_42:.*]] = %[[VAL_0]] to %[[VAL_41]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_42]] : (index) -> i64 +// CHECK: %[[VAL_44:.*]] = arith.addi %[[VAL_43]], %[[VAL_40]] overflow : i64 +// CHECK: %[[VAL_45:.*]] = hlfir.designate %[[VAL_18]] (%[[VAL_44]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_45]] : !fir.logical<2>, !fir.ref> +// CHECK: } +// CHECK: } +// CHECK: hlfir.assign %[[VAL_16]] to %[[VAL_12]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_16]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the scalar always present boundary. +// subroutine eoshift3(n, array, boundary) +// integer :: n +// complex(2) :: array(n), boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift3(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref>> {fir.bindc_name = "array"}, %arg2: !fir.ref> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift3En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg2 dummy_scope %0 {uniq_name = "_QFeoshift3Eboundary"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) + %3 = fir.load %1#0 : !fir.ref + %4 = fir.convert %3 : (i32) -> index + %5 = arith.cmpi sgt, %4, %c0 : index + %6 = arith.select %5, %4, %c0 : index + %7 = fir.shape %6 : (index) -> !fir.shape<1> + %8:2 = hlfir.declare %arg1(%7) dummy_scope %0 {uniq_name = "_QFeoshift3Earray"} : (!fir.ref>>, !fir.shape<1>, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %9 = hlfir.eoshift %8#0 %c2_i32 boundary %2#0 : (!fir.box>>, i32, !fir.ref>) -> !hlfir.expr> + hlfir.assign %9 to %8#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %9 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift3( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref>> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.ref> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_2:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift3En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift3Eboundary"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> index +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_3]] : index +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_3]] : index +// CHECK: %[[VAL_11:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[ARG1]](%[[VAL_11]]) dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift3Earray"} : (!fir.ref>>, !fir.shape<1>, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (index) -> i64 +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_2]] : (i32) -> i64 +// CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref> +// CHECK: %[[VAL_16:.*]] = hlfir.eval_in_mem shape %[[VAL_11]] : (!fir.shape<1>) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_17:.*]]: !fir.ref>>): +// CHECK: %[[VAL_18:.*]] = fir.embox %[[VAL_17]](%[[VAL_11]]) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> +// CHECK: %[[VAL_19:.*]] = arith.cmpi slt, %[[VAL_14]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_1]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_19]], %[[VAL_20]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_22:.*]] = arith.select %[[VAL_19]], %[[VAL_1]], %[[VAL_14]] : i64 +// CHECK: %[[VAL_23:.*]] = arith.subi %[[VAL_1]], %[[VAL_13]] overflow : i64 +// CHECK: %[[VAL_24:.*]] = arith.addi %[[VAL_13]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_25:.*]] = arith.cmpi sgt, %[[VAL_23]], %[[VAL_14]] : i64 +// CHECK: %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_1]], %[[VAL_24]] : i64 +// CHECK: %[[VAL_27:.*]] = arith.subi %[[VAL_13]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_28:.*]] = arith.cmpi slt, %[[VAL_13]], %[[VAL_14]] : i64 +// CHECK: %[[VAL_29:.*]] = arith.select %[[VAL_28]], %[[VAL_1]], %[[VAL_27]] : i64 +// CHECK: %[[VAL_30:.*]] = arith.select %[[VAL_19]], %[[VAL_26]], %[[VAL_29]] : i64 +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_32:.*]] = %[[VAL_0]] to %[[VAL_31]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (index) -> i64 +// CHECK: %[[VAL_34:.*]] = arith.addi %[[VAL_33]], %[[VAL_22]] overflow : i64 +// CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_12]]#0 (%[[VAL_34]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: %[[VAL_36:.*]] = fir.load %[[VAL_35]] : !fir.ref> +// CHECK: %[[VAL_37:.*]] = arith.addi %[[VAL_33]], %[[VAL_21]] overflow : i64 +// CHECK: %[[VAL_38:.*]] = hlfir.designate %[[VAL_18]] (%[[VAL_37]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: hlfir.assign %[[VAL_36]] to %[[VAL_38]] : complex, !fir.ref> +// CHECK: } +// CHECK: %[[VAL_39:.*]] = arith.subi %[[VAL_13]], %[[VAL_30]] overflow : i64 +// CHECK: %[[VAL_40:.*]] = arith.select %[[VAL_19]], %[[VAL_1]], %[[VAL_30]] : i64 +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_39]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_42:.*]] = %[[VAL_0]] to %[[VAL_41]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_43:.*]] = fir.convert %[[VAL_42]] : (index) -> i64 +// CHECK: %[[VAL_44:.*]] = arith.addi %[[VAL_43]], %[[VAL_40]] overflow : i64 +// CHECK: %[[VAL_45:.*]] = hlfir.designate %[[VAL_18]] (%[[VAL_44]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_45]] : complex, !fir.ref> +// CHECK: } +// CHECK: } +// CHECK: hlfir.assign %[[VAL_16]] to %[[VAL_12]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_16]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the scalar optional boundary. +// subroutine eoshift4(n, array, boundary) +// integer :: n +// logical :: array(n) +// logical, optional :: boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift4(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref>> {fir.bindc_name = "array"}, %arg2: !fir.ref> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift4En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg2 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift4Eboundary"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) + %3 = fir.load %1#0 : !fir.ref + %4 = fir.convert %3 : (i32) -> index + %5 = arith.cmpi sgt, %4, %c0 : index + %6 = arith.select %5, %4, %c0 : index + %7 = fir.shape %6 : (index) -> !fir.shape<1> + %8:2 = hlfir.declare %arg1(%7) dummy_scope %0 {uniq_name = "_QFeoshift4Earray"} : (!fir.ref>>, !fir.shape<1>, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %9 = fir.is_present %2#0 : (!fir.ref>) -> i1 + %10 = fir.embox %2#0 : (!fir.ref>) -> !fir.box> + %11 = fir.absent !fir.box> + %12 = arith.select %9, %10, %11 : !fir.box> + %13 = hlfir.eoshift %8#0 %c2_i32 boundary %12 : (!fir.box>>, i32, !fir.box>) -> !hlfir.expr> + hlfir.assign %13 to %8#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %13 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift4( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref>> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.ref> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_1:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_2:.*]] = arith.constant false +// CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift4En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %[[VAL_5]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift4Eboundary"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i32) -> index +// CHECK: %[[VAL_10:.*]] = arith.cmpi sgt, %[[VAL_9]], %[[VAL_4]] : index +// CHECK: %[[VAL_11:.*]] = arith.select %[[VAL_10]], %[[VAL_9]], %[[VAL_4]] : index +// CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_11]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[ARG1]](%[[VAL_12]]) dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift4Earray"} : (!fir.ref>>, !fir.shape<1>, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_7]]#0 : (!fir.ref>) -> i1 +// CHECK: %[[VAL_15:.*]] = fir.embox %[[VAL_7]]#0 : (!fir.ref>) -> !fir.box> +// CHECK: %[[VAL_16:.*]] = fir.absent !fir.box> +// CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_14]], %[[VAL_15]], %[[VAL_16]] : !fir.box> +// CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_11]] : (index) -> i64 +// CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_3]] : (i32) -> i64 +// CHECK: %[[VAL_20:.*]] = fir.is_present %[[VAL_17]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_21:.*]] = fir.if %[[VAL_20]] -> (!fir.logical<4>) { +// CHECK: %[[VAL_22:.*]] = fir.box_addr %[[VAL_17]] : (!fir.box>) -> !fir.ref> +// CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_22]] : !fir.ref> +// CHECK: fir.result %[[VAL_23]] : !fir.logical<4> +// CHECK: } else { +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_2]] : (i1) -> !fir.logical<4> +// CHECK: fir.result %[[VAL_24]] : !fir.logical<4> +// CHECK: } +// CHECK: %[[VAL_25:.*]] = hlfir.eval_in_mem shape %[[VAL_12]] : (!fir.shape<1>) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_26:.*]]: !fir.ref>>): +// CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_26]](%[[VAL_12]]) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> +// CHECK: %[[VAL_28:.*]] = arith.cmpi slt, %[[VAL_19]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_29:.*]] = arith.subi %[[VAL_1]], %[[VAL_19]] overflow : i64 +// CHECK: %[[VAL_30:.*]] = arith.select %[[VAL_28]], %[[VAL_29]], %[[VAL_1]] : i64 +// CHECK: %[[VAL_31:.*]] = arith.select %[[VAL_28]], %[[VAL_1]], %[[VAL_19]] : i64 +// CHECK: %[[VAL_32:.*]] = arith.subi %[[VAL_1]], %[[VAL_18]] overflow : i64 +// CHECK: %[[VAL_33:.*]] = arith.addi %[[VAL_18]], %[[VAL_19]] overflow : i64 +// CHECK: %[[VAL_34:.*]] = arith.cmpi sgt, %[[VAL_32]], %[[VAL_19]] : i64 +// CHECK: %[[VAL_35:.*]] = arith.select %[[VAL_34]], %[[VAL_1]], %[[VAL_33]] : i64 +// CHECK: %[[VAL_36:.*]] = arith.subi %[[VAL_18]], %[[VAL_19]] overflow : i64 +// CHECK: %[[VAL_37:.*]] = arith.cmpi slt, %[[VAL_18]], %[[VAL_19]] : i64 +// CHECK: %[[VAL_38:.*]] = arith.select %[[VAL_37]], %[[VAL_1]], %[[VAL_36]] : i64 +// CHECK: %[[VAL_39:.*]] = arith.select %[[VAL_28]], %[[VAL_35]], %[[VAL_38]] : i64 +// CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_39]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_41:.*]] = %[[VAL_0]] to %[[VAL_40]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_42:.*]] = fir.convert %[[VAL_41]] : (index) -> i64 +// CHECK: %[[VAL_43:.*]] = arith.addi %[[VAL_42]], %[[VAL_31]] overflow : i64 +// CHECK: %[[VAL_44:.*]] = hlfir.designate %[[VAL_13]]#0 (%[[VAL_43]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: %[[VAL_45:.*]] = fir.load %[[VAL_44]] : !fir.ref> +// CHECK: %[[VAL_46:.*]] = arith.addi %[[VAL_42]], %[[VAL_30]] overflow : i64 +// CHECK: %[[VAL_47:.*]] = hlfir.designate %[[VAL_27]] (%[[VAL_46]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: hlfir.assign %[[VAL_45]] to %[[VAL_47]] : !fir.logical<4>, !fir.ref> +// CHECK: } +// CHECK: %[[VAL_48:.*]] = arith.subi %[[VAL_18]], %[[VAL_39]] overflow : i64 +// CHECK: %[[VAL_49:.*]] = arith.select %[[VAL_28]], %[[VAL_1]], %[[VAL_39]] : i64 +// CHECK: %[[VAL_50:.*]] = fir.convert %[[VAL_48]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_51:.*]] = %[[VAL_0]] to %[[VAL_50]] step %[[VAL_0]] unordered { +// CHECK: %[[VAL_52:.*]] = fir.convert %[[VAL_51]] : (index) -> i64 +// CHECK: %[[VAL_53:.*]] = arith.addi %[[VAL_52]], %[[VAL_49]] overflow : i64 +// CHECK: %[[VAL_54:.*]] = hlfir.designate %[[VAL_27]] (%[[VAL_53]]) : (!fir.box>>, i64) -> !fir.ref> +// CHECK: hlfir.assign %[[VAL_21]] to %[[VAL_54]] : !fir.logical<4>, !fir.ref> +// CHECK: } +// CHECK: } +// CHECK: hlfir.assign %[[VAL_25]] to %[[VAL_13]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_25]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array always present boundary. +// subroutine eoshift5(n, array, boundary) +// integer :: n +// real :: array(n,n) +// real :: boundary(:) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift5(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref> {fir.bindc_name = "array"}, %arg2: !fir.box> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift5En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg2 dummy_scope %0 {uniq_name = "_QFeoshift5Eboundary"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) + %3 = fir.load %1#0 : !fir.ref + %4 = fir.convert %3 : (i32) -> index + %5 = arith.cmpi sgt, %4, %c0 : index + %6 = arith.select %5, %4, %c0 : index + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.shape %6, %10 : (index, index) -> !fir.shape<2> + %12:2 = hlfir.declare %arg1(%11) dummy_scope %0 {uniq_name = "_QFeoshift5Earray"} : (!fir.ref>, !fir.shape<2>, !fir.dscope) -> (!fir.box>, !fir.ref>) + %13 = hlfir.eoshift %12#0 %c2_i32 boundary %2#0 : (!fir.box>, i32, !fir.box>) -> !hlfir.expr + hlfir.assign %13 to %12#0 : !hlfir.expr, !fir.box> + hlfir.destroy %13 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @_QPeoshift5( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.box> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift5En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift5Eboundary"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +// CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> index +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_3]] : index +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_3]] : index +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i32) -> index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_3]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_12]], %[[VAL_3]] : index +// CHECK: %[[VAL_15:.*]] = fir.shape %[[VAL_10]], %[[VAL_14]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[ARG1]](%[[VAL_15]]) dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift5Earray"} : (!fir.ref>, !fir.shape<2>, !fir.dscope) -> (!fir.box>, !fir.ref>) +// CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_10]] : (index) -> i64 +// CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_2]] : (i32) -> i64 +// CHECK: %[[VAL_19:.*]] = hlfir.eval_in_mem shape %[[VAL_15]] : (!fir.shape<2>) -> !hlfir.expr { +// CHECK: ^bb0(%[[VAL_20:.*]]: !fir.ref>): +// CHECK: %[[VAL_21:.*]] = fir.embox %[[VAL_20]](%[[VAL_15]]) : (!fir.ref>, !fir.shape<2>) -> !fir.box> +// CHECK: fir.do_loop %[[VAL_22:.*]] = %[[VAL_1]] to %[[VAL_14]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_23:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_22]]) : (!fir.box>, index) -> !fir.ref +// CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_23]] : !fir.ref +// CHECK: %[[VAL_25:.*]] = arith.cmpi slt, %[[VAL_18]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_26:.*]] = arith.subi %[[VAL_0]], %[[VAL_18]] overflow : i64 +// CHECK: %[[VAL_27:.*]] = arith.select %[[VAL_25]], %[[VAL_26]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_28:.*]] = arith.select %[[VAL_25]], %[[VAL_0]], %[[VAL_18]] : i64 +// CHECK: %[[VAL_29:.*]] = arith.subi %[[VAL_0]], %[[VAL_17]] overflow : i64 +// CHECK: %[[VAL_30:.*]] = arith.addi %[[VAL_17]], %[[VAL_18]] overflow : i64 +// CHECK: %[[VAL_31:.*]] = arith.cmpi sgt, %[[VAL_29]], %[[VAL_18]] : i64 +// CHECK: %[[VAL_32:.*]] = arith.select %[[VAL_31]], %[[VAL_0]], %[[VAL_30]] : i64 +// CHECK: %[[VAL_33:.*]] = arith.subi %[[VAL_17]], %[[VAL_18]] overflow : i64 +// CHECK: %[[VAL_34:.*]] = arith.cmpi slt, %[[VAL_17]], %[[VAL_18]] : i64 +// CHECK: %[[VAL_35:.*]] = arith.select %[[VAL_34]], %[[VAL_0]], %[[VAL_33]] : i64 +// CHECK: %[[VAL_36:.*]] = arith.select %[[VAL_25]], %[[VAL_32]], %[[VAL_35]] : i64 +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_36]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_38:.*]] = %[[VAL_1]] to %[[VAL_37]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_38]] : (index) -> i64 +// CHECK: %[[VAL_40:.*]] = arith.addi %[[VAL_39]], %[[VAL_28]] overflow : i64 +// CHECK: %[[VAL_41:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_40]], %[[VAL_22]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: %[[VAL_42:.*]] = fir.load %[[VAL_41]] : !fir.ref +// CHECK: %[[VAL_43:.*]] = arith.addi %[[VAL_39]], %[[VAL_27]] overflow : i64 +// CHECK: %[[VAL_44:.*]] = hlfir.designate %[[VAL_21]] (%[[VAL_43]], %[[VAL_22]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_42]] to %[[VAL_44]] : f32, !fir.ref +// CHECK: } +// CHECK: %[[VAL_45:.*]] = arith.subi %[[VAL_17]], %[[VAL_36]] overflow : i64 +// CHECK: %[[VAL_46:.*]] = arith.select %[[VAL_25]], %[[VAL_0]], %[[VAL_36]] : i64 +// CHECK: %[[VAL_47:.*]] = fir.convert %[[VAL_45]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_48:.*]] = %[[VAL_1]] to %[[VAL_47]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_49:.*]] = fir.convert %[[VAL_48]] : (index) -> i64 +// CHECK: %[[VAL_50:.*]] = arith.addi %[[VAL_49]], %[[VAL_46]] overflow : i64 +// CHECK: %[[VAL_51:.*]] = hlfir.designate %[[VAL_21]] (%[[VAL_50]], %[[VAL_22]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_51]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: hlfir.assign %[[VAL_19]] to %[[VAL_16]]#0 : !hlfir.expr, !fir.box> +// CHECK: hlfir.destroy %[[VAL_19]] : !hlfir.expr +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array optional boundary. +// subroutine eoshift6(n, array, boundary) +// integer :: n +// real :: array(n,n) +// real, optional :: boundary(n) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift6(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref> {fir.bindc_name = "array"}, %arg2: !fir.ref> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift6En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2 = fir.load %1#0 : !fir.ref + %3 = fir.convert %2 : (i32) -> index + %4 = arith.cmpi sgt, %3, %c0 : index + %5 = arith.select %4, %3, %c0 : index + %6 = fir.load %1#0 : !fir.ref + %7 = fir.convert %6 : (i32) -> index + %8 = arith.cmpi sgt, %7, %c0 : index + %9 = arith.select %8, %7, %c0 : index + %10 = fir.shape %5, %9 : (index, index) -> !fir.shape<2> + %11:2 = hlfir.declare %arg1(%10) dummy_scope %0 {uniq_name = "_QFeoshift6Earray"} : (!fir.ref>, !fir.shape<2>, !fir.dscope) -> (!fir.box>, !fir.ref>) + %12 = fir.load %1#0 : !fir.ref + %13 = fir.convert %12 : (i32) -> index + %14 = arith.cmpi sgt, %13, %c0 : index + %15 = arith.select %14, %13, %c0 : index + %16 = fir.shape %15 : (index) -> !fir.shape<1> + %17:2 = hlfir.declare %arg2(%16) dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift6Eboundary"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.box>, !fir.ref>) + %18 = fir.is_present %17#0 : (!fir.box>) -> i1 + %19 = fir.shape %15 : (index) -> !fir.shape<1> + %20 = fir.embox %17#1(%19) : (!fir.ref>, !fir.shape<1>) -> !fir.box> + %21 = fir.absent !fir.box> + %22 = arith.select %18, %20, %21 : !fir.box> + %23 = hlfir.eoshift %11#0 %c2_i32 boundary %22 : (!fir.box>, i32, !fir.box>) -> !hlfir.expr + hlfir.assign %23 to %11#0 : !hlfir.expr, !fir.box> + hlfir.destroy %23 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @_QPeoshift6( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.ref> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant false +// CHECK: %[[VAL_3:.*]] = arith.constant true +// CHECK: %[[VAL_4:.*]] = arith.constant 0.000000e+00 : f32 +// CHECK: %[[VAL_5:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_6:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_7:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_7]] {uniq_name = "_QFeoshift6En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i32) -> index +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_6]] : index +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_10]], %[[VAL_6]] : index +// CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> index +// CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_6]] : index +// CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_14]], %[[VAL_6]] : index +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_12]], %[[VAL_16]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[ARG1]](%[[VAL_17]]) dummy_scope %[[VAL_7]] {uniq_name = "_QFeoshift6Earray"} : (!fir.ref>, !fir.shape<2>, !fir.dscope) -> (!fir.box>, !fir.ref>) +// CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (i32) -> index +// CHECK: %[[VAL_21:.*]] = arith.cmpi sgt, %[[VAL_20]], %[[VAL_6]] : index +// CHECK: %[[VAL_22:.*]] = arith.select %[[VAL_21]], %[[VAL_20]], %[[VAL_6]] : index +// CHECK: %[[VAL_23:.*]] = fir.shape %[[VAL_22]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[ARG2]](%[[VAL_23]]) dummy_scope %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift6Eboundary"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.box>, !fir.ref>) +// CHECK: %[[VAL_25:.*]] = fir.is_present %[[VAL_24]]#0 : (!fir.box>) -> i1 +// CHECK: %[[VAL_26:.*]] = fir.shape %[[VAL_22]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_27:.*]] = fir.embox %[[VAL_24]]#1(%[[VAL_26]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> +// CHECK: %[[VAL_28:.*]] = fir.absent !fir.box> +// CHECK: %[[VAL_29:.*]] = arith.select %[[VAL_25]], %[[VAL_27]], %[[VAL_28]] : !fir.box> +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_12]] : (index) -> i64 +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_5]] : (i32) -> i64 +// CHECK: %[[VAL_32:.*]] = fir.is_present %[[VAL_29]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_33:.*]] = arith.select %[[VAL_32]], %[[VAL_2]], %[[VAL_3]] : i1 +// CHECK: %[[VAL_34:.*]] = hlfir.eval_in_mem shape %[[VAL_17]] : (!fir.shape<2>) -> !hlfir.expr { +// CHECK: ^bb0(%[[VAL_35:.*]]: !fir.ref>): +// CHECK: %[[VAL_36:.*]] = fir.embox %[[VAL_35]](%[[VAL_17]]) : (!fir.ref>, !fir.shape<2>) -> !fir.box> +// CHECK: fir.do_loop %[[VAL_37:.*]] = %[[VAL_1]] to %[[VAL_16]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_38:.*]] = fir.if %[[VAL_33]] -> (f32) { +// CHECK: fir.result %[[VAL_4]] : f32 +// CHECK: } else { +// CHECK: %[[VAL_39:.*]]:3 = fir.box_dims %[[VAL_29]], %[[VAL_6]] : (!fir.box>, index) -> (index, index, index) +// CHECK: %[[VAL_40:.*]] = arith.subi %[[VAL_39]]#0, %[[VAL_1]] overflow : index +// CHECK: %[[VAL_41:.*]] = arith.addi %[[VAL_37]], %[[VAL_40]] overflow : index +// CHECK: %[[VAL_42:.*]] = hlfir.designate %[[VAL_29]] (%[[VAL_41]]) : (!fir.box>, index) -> !fir.ref +// CHECK: %[[VAL_43:.*]] = fir.load %[[VAL_42]] : !fir.ref +// CHECK: fir.result %[[VAL_43]] : f32 +// CHECK: } +// CHECK: %[[VAL_44:.*]] = arith.cmpi slt, %[[VAL_31]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_45:.*]] = arith.subi %[[VAL_0]], %[[VAL_31]] overflow : i64 +// CHECK: %[[VAL_46:.*]] = arith.select %[[VAL_44]], %[[VAL_45]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_47:.*]] = arith.select %[[VAL_44]], %[[VAL_0]], %[[VAL_31]] : i64 +// CHECK: %[[VAL_48:.*]] = arith.subi %[[VAL_0]], %[[VAL_30]] overflow : i64 +// CHECK: %[[VAL_49:.*]] = arith.addi %[[VAL_30]], %[[VAL_31]] overflow : i64 +// CHECK: %[[VAL_50:.*]] = arith.cmpi sgt, %[[VAL_48]], %[[VAL_31]] : i64 +// CHECK: %[[VAL_51:.*]] = arith.select %[[VAL_50]], %[[VAL_0]], %[[VAL_49]] : i64 +// CHECK: %[[VAL_52:.*]] = arith.subi %[[VAL_30]], %[[VAL_31]] overflow : i64 +// CHECK: %[[VAL_53:.*]] = arith.cmpi slt, %[[VAL_30]], %[[VAL_31]] : i64 +// CHECK: %[[VAL_54:.*]] = arith.select %[[VAL_53]], %[[VAL_0]], %[[VAL_52]] : i64 +// CHECK: %[[VAL_55:.*]] = arith.select %[[VAL_44]], %[[VAL_51]], %[[VAL_54]] : i64 +// CHECK: %[[VAL_56:.*]] = fir.convert %[[VAL_55]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_57:.*]] = %[[VAL_1]] to %[[VAL_56]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_58:.*]] = fir.convert %[[VAL_57]] : (index) -> i64 +// CHECK: %[[VAL_59:.*]] = arith.addi %[[VAL_58]], %[[VAL_47]] overflow : i64 +// CHECK: %[[VAL_60:.*]] = hlfir.designate %[[VAL_18]]#0 (%[[VAL_59]], %[[VAL_37]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: %[[VAL_61:.*]] = fir.load %[[VAL_60]] : !fir.ref +// CHECK: %[[VAL_62:.*]] = arith.addi %[[VAL_58]], %[[VAL_46]] overflow : i64 +// CHECK: %[[VAL_63:.*]] = hlfir.designate %[[VAL_36]] (%[[VAL_62]], %[[VAL_37]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_61]] to %[[VAL_63]] : f32, !fir.ref +// CHECK: } +// CHECK: %[[VAL_64:.*]] = arith.subi %[[VAL_30]], %[[VAL_55]] overflow : i64 +// CHECK: %[[VAL_65:.*]] = arith.select %[[VAL_44]], %[[VAL_0]], %[[VAL_55]] : i64 +// CHECK: %[[VAL_66:.*]] = fir.convert %[[VAL_64]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_67:.*]] = %[[VAL_1]] to %[[VAL_66]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_68:.*]] = fir.convert %[[VAL_67]] : (index) -> i64 +// CHECK: %[[VAL_69:.*]] = arith.addi %[[VAL_68]], %[[VAL_65]] overflow : i64 +// CHECK: %[[VAL_70:.*]] = hlfir.designate %[[VAL_36]] (%[[VAL_69]], %[[VAL_37]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_38]] to %[[VAL_70]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: hlfir.assign %[[VAL_34]] to %[[VAL_18]]#0 : !hlfir.expr, !fir.box> +// CHECK: hlfir.destroy %[[VAL_34]] : !hlfir.expr +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array expression boundary. +// subroutine eoshift7(n, array) +// interface +// function real_boundary(n) +// integer :: n +// real :: real_boundary(n) +// end function +// end interface +// integer :: n +// real :: array(n,n) +// array = EOSHIFT(array, 2, real_boundary(n)) +// end subroutine +func.func @_QPeoshift7(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref> {fir.bindc_name = "array"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift7En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2 = fir.load %1#0 : !fir.ref + %3 = fir.convert %2 : (i32) -> index + %4 = arith.cmpi sgt, %3, %c0 : index + %5 = arith.select %4, %3, %c0 : index + %6 = fir.load %1#0 : !fir.ref + %7 = fir.convert %6 : (i32) -> index + %8 = arith.cmpi sgt, %7, %c0 : index + %9 = arith.select %8, %7, %c0 : index + %10 = fir.shape %5, %9 : (index, index) -> !fir.shape<2> + %11:2 = hlfir.declare %arg1(%10) dummy_scope %0 {uniq_name = "_QFeoshift7Earray"} : (!fir.ref>, !fir.shape<2>, !fir.dscope) -> (!fir.box>, !fir.ref>) + %12:2 = hlfir.declare %1#0 {uniq_name = "_QFeoshift7Freal_boundaryEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %13 = fir.load %12#0 : !fir.ref + %14 = fir.convert %13 : (i32) -> index + %15 = arith.cmpi sgt, %14, %c0 : index + %16 = arith.select %15, %14, %c0 : index + %17 = fir.shape %16 : (index) -> !fir.shape<1> + %18 = hlfir.eval_in_mem shape %17 : (!fir.shape<1>) -> !hlfir.expr { + ^bb0(%arg2: !fir.ref>): + %20 = fir.call @_QPreal_boundary(%1#0) fastmath : (!fir.ref) -> !fir.array + fir.save_result %20 to %arg2(%17) : !fir.array, !fir.ref>, !fir.shape<1> + } + %19 = hlfir.eoshift %11#0 %c2_i32 boundary %18 : (!fir.box>, i32, !hlfir.expr) -> !hlfir.expr + hlfir.assign %19 to %11#0 : !hlfir.expr, !fir.box> + hlfir.destroy %19 : !hlfir.expr + hlfir.destroy %18 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @_QPeoshift7( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.ref> {fir.bindc_name = "array"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 0 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift7En"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i32) -> index +// CHECK: %[[VAL_8:.*]] = arith.cmpi sgt, %[[VAL_7]], %[[VAL_3]] : index +// CHECK: %[[VAL_9:.*]] = arith.select %[[VAL_8]], %[[VAL_7]], %[[VAL_3]] : index +// CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i32) -> index +// CHECK: %[[VAL_12:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_3]] : index +// CHECK: %[[VAL_13:.*]] = arith.select %[[VAL_12]], %[[VAL_11]], %[[VAL_3]] : index +// CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_9]], %[[VAL_13]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[ARG1]](%[[VAL_14]]) dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift7Earray"} : (!fir.ref>, !fir.shape<2>, !fir.dscope) -> (!fir.box>, !fir.ref>) +// CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_5]]#0 {uniq_name = "_QFeoshift7Freal_boundaryEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_16]]#0 : !fir.ref +// CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i32) -> index +// CHECK: %[[VAL_19:.*]] = arith.cmpi sgt, %[[VAL_18]], %[[VAL_3]] : index +// CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_19]], %[[VAL_18]], %[[VAL_3]] : index +// CHECK: %[[VAL_21:.*]] = fir.shape %[[VAL_20]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_22:.*]] = hlfir.eval_in_mem shape %[[VAL_21]] : (!fir.shape<1>) -> !hlfir.expr { +// CHECK: ^bb0(%[[VAL_23:.*]]: !fir.ref>): +// CHECK: %[[VAL_24:.*]] = fir.call @_QPreal_boundary(%[[VAL_5]]#0) fastmath : (!fir.ref) -> !fir.array +// CHECK: fir.save_result %[[VAL_24]] to %[[VAL_23]](%[[VAL_21]]) : !fir.array, !fir.ref>, !fir.shape<1> +// CHECK: } +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_9]] : (index) -> i64 +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_2]] : (i32) -> i64 +// CHECK: %[[VAL_27:.*]] = hlfir.eval_in_mem shape %[[VAL_14]] : (!fir.shape<2>) -> !hlfir.expr { +// CHECK: ^bb0(%[[VAL_28:.*]]: !fir.ref>): +// CHECK: %[[VAL_29:.*]] = fir.embox %[[VAL_28]](%[[VAL_14]]) : (!fir.ref>, !fir.shape<2>) -> !fir.box> +// CHECK: fir.do_loop %[[VAL_30:.*]] = %[[VAL_1]] to %[[VAL_13]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_31:.*]] = hlfir.apply %[[VAL_22]], %[[VAL_30]] : (!hlfir.expr, index) -> f32 +// CHECK: %[[VAL_32:.*]] = arith.cmpi slt, %[[VAL_26]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_33:.*]] = arith.subi %[[VAL_0]], %[[VAL_26]] overflow : i64 +// CHECK: %[[VAL_34:.*]] = arith.select %[[VAL_32]], %[[VAL_33]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_35:.*]] = arith.select %[[VAL_32]], %[[VAL_0]], %[[VAL_26]] : i64 +// CHECK: %[[VAL_36:.*]] = arith.subi %[[VAL_0]], %[[VAL_25]] overflow : i64 +// CHECK: %[[VAL_37:.*]] = arith.addi %[[VAL_25]], %[[VAL_26]] overflow : i64 +// CHECK: %[[VAL_38:.*]] = arith.cmpi sgt, %[[VAL_36]], %[[VAL_26]] : i64 +// CHECK: %[[VAL_39:.*]] = arith.select %[[VAL_38]], %[[VAL_0]], %[[VAL_37]] : i64 +// CHECK: %[[VAL_40:.*]] = arith.subi %[[VAL_25]], %[[VAL_26]] overflow : i64 +// CHECK: %[[VAL_41:.*]] = arith.cmpi slt, %[[VAL_25]], %[[VAL_26]] : i64 +// CHECK: %[[VAL_42:.*]] = arith.select %[[VAL_41]], %[[VAL_0]], %[[VAL_40]] : i64 +// CHECK: %[[VAL_43:.*]] = arith.select %[[VAL_32]], %[[VAL_39]], %[[VAL_42]] : i64 +// CHECK: %[[VAL_44:.*]] = fir.convert %[[VAL_43]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_45:.*]] = %[[VAL_1]] to %[[VAL_44]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_46:.*]] = fir.convert %[[VAL_45]] : (index) -> i64 +// CHECK: %[[VAL_47:.*]] = arith.addi %[[VAL_46]], %[[VAL_35]] overflow : i64 +// CHECK: %[[VAL_48:.*]] = hlfir.designate %[[VAL_15]]#0 (%[[VAL_47]], %[[VAL_30]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: %[[VAL_49:.*]] = fir.load %[[VAL_48]] : !fir.ref +// CHECK: %[[VAL_50:.*]] = arith.addi %[[VAL_46]], %[[VAL_34]] overflow : i64 +// CHECK: %[[VAL_51:.*]] = hlfir.designate %[[VAL_29]] (%[[VAL_50]], %[[VAL_30]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_49]] to %[[VAL_51]] : f32, !fir.ref +// CHECK: } +// CHECK: %[[VAL_52:.*]] = arith.subi %[[VAL_25]], %[[VAL_43]] overflow : i64 +// CHECK: %[[VAL_53:.*]] = arith.select %[[VAL_32]], %[[VAL_0]], %[[VAL_43]] : i64 +// CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_52]] : (i64) -> index +// CHECK: fir.do_loop %[[VAL_55:.*]] = %[[VAL_1]] to %[[VAL_54]] step %[[VAL_1]] unordered { +// CHECK: %[[VAL_56:.*]] = fir.convert %[[VAL_55]] : (index) -> i64 +// CHECK: %[[VAL_57:.*]] = arith.addi %[[VAL_56]], %[[VAL_53]] overflow : i64 +// CHECK: %[[VAL_58:.*]] = hlfir.designate %[[VAL_29]] (%[[VAL_57]], %[[VAL_30]]) : (!fir.box>, i64, index) -> !fir.ref +// CHECK: hlfir.assign %[[VAL_31]] to %[[VAL_58]] : f32, !fir.ref +// CHECK: } +// CHECK: } +// CHECK: } +// CHECK: hlfir.assign %[[VAL_27]] to %[[VAL_15]]#0 : !hlfir.expr, !fir.box> +// CHECK: hlfir.destroy %[[VAL_27]] : !hlfir.expr +// CHECK: hlfir.destroy %[[VAL_22]] : !hlfir.expr +// CHECK: return +// CHECK: } + +// ! Tests for CHARACTER type (lowered via hlfir.elemental). + +// ! Test contiguous 1D array with statically absent boundary. +// ! CHARACTER with constant length. +// subroutine eoshift1c(n, array) +// integer :: n +// character(10,1) :: array(n) +// array = EOSHIFT(array, 2) +// end subroutine +func.func @_QPeoshift1c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift1cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = arith.cmpi sgt, %5, %c0 : index + %7 = arith.select %6, %5, %c0 : index + %8 = fir.shape %7 : (index) -> !fir.shape<1> + %9:2 = hlfir.declare %3(%8) typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift1cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %10 = hlfir.eoshift %9#0 %c2_i32 : (!fir.box>>, i32) -> !hlfir.expr> + hlfir.assign %10 to %9#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %10 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift1c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift1cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i32) -> index +// CHECK: %[[VAL_10:.*]] = arith.cmpi sgt, %[[VAL_9]], %[[VAL_2]] : index +// CHECK: %[[VAL_11:.*]] = arith.select %[[VAL_10]], %[[VAL_9]], %[[VAL_2]] : index +// CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_11]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_12]]) typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift1cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_11]] : (index) -> i64 +// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_16:.*]] = fir.alloca !fir.char<1,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_17:.*]] = fir.emboxchar %[[VAL_16]], %[[VAL_2]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_18:.*]] = hlfir.elemental %[[VAL_12]] typeparams %[[VAL_3]] unordered : (!fir.shape<1>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_19:.*]]: index): +// CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_19]] : (index) -> i64 +// CHECK: %[[VAL_21:.*]] = arith.addi %[[VAL_20]], %[[VAL_15]] overflow : i64 +// CHECK: %[[VAL_22:.*]] = arith.cmpi sge, %[[VAL_21]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_23:.*]] = arith.cmpi sle, %[[VAL_21]], %[[VAL_14]] : i64 +// CHECK: %[[VAL_24:.*]] = arith.andi %[[VAL_22]], %[[VAL_23]] : i1 +// CHECK: %[[VAL_25:.*]] = fir.if %[[VAL_24]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_21]] : (i64) -> index +// CHECK: %[[VAL_27:.*]] = hlfir.designate %[[VAL_13]]#0 (%[[VAL_26]]) typeparams %[[VAL_3]] : (!fir.box>>, index, index) -> !fir.ref> +// CHECK: %[[VAL_28:.*]] = fir.emboxchar %[[VAL_27]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_28]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_17]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_25]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_18]] to %[[VAL_13]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_18]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with statically absent boundary. +// ! CHARACTER with variable length. +// subroutine eoshift2c(n, array) +// integer :: n +// character(n,1) :: array(n) +// array = EOSHIFT(array, 2) +// end subroutine +func.func @_QPeoshift2c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c0_i32 = arith.constant 0 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift2cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = arith.cmpi sgt, %4, %c0_i32 : i32 + %6 = arith.select %5, %4, %c0_i32 : i32 + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.shape %10 : (index) -> !fir.shape<1> + %12:2 = hlfir.declare %3(%11) typeparams %6 dummy_scope %0 {uniq_name = "_QFeoshift2cEarray"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %13 = hlfir.eoshift %12#0 %c2_i32 : (!fir.box>>, i32) -> !hlfir.expr> + hlfir.assign %13 to %12#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %13 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift2c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift2cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i32) -> index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_15:.*]] = fir.shape %[[VAL_14]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_15]]) typeparams %[[VAL_10]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift2cEarray"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_14]] : (index) -> i64 +// CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_19:.*]] = fir.alloca !fir.char<1,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_20:.*]] = fir.emboxchar %[[VAL_19]], %[[VAL_2]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_21:.*]] = hlfir.elemental %[[VAL_15]] typeparams %[[VAL_10]] unordered : (!fir.shape<1>, i32) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_22:.*]]: index): +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22]] : (index) -> i64 +// CHECK: %[[VAL_24:.*]] = arith.addi %[[VAL_23]], %[[VAL_18]] overflow : i64 +// CHECK: %[[VAL_25:.*]] = arith.cmpi sge, %[[VAL_24]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_26:.*]] = arith.cmpi sle, %[[VAL_24]], %[[VAL_17]] : i64 +// CHECK: %[[VAL_27:.*]] = arith.andi %[[VAL_25]], %[[VAL_26]] : i1 +// CHECK: %[[VAL_28:.*]] = fir.if %[[VAL_27]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_24]] : (i64) -> index +// CHECK: %[[VAL_30:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_29]]) typeparams %[[VAL_10]] : (!fir.box>>, index, i32) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_30]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_20]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_28]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_21]] to %[[VAL_16]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_21]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with statically absent boundary. +// ! CHARACTER with assumed length. +// subroutine eoshift3c(n, array) +// integer :: n +// character(*,1) :: array(n) +// array = EOSHIFT(array, 2) +// end subroutine +func.func @_QPeoshift3c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift3cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = arith.cmpi sgt, %5, %c0 : index + %7 = arith.select %6, %5, %c0 : index + %8 = fir.shape %7 : (index) -> !fir.shape<1> + %9:2 = hlfir.declare %3(%8) typeparams %2#1 dummy_scope %0 {uniq_name = "_QFeoshift3cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %10 = hlfir.eoshift %9#0 %c2_i32 : (!fir.box>>, i32) -> !hlfir.expr> + hlfir.assign %10 to %9#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %10 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift3c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift3cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_5:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> index +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_2]] : index +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_2]] : index +// CHECK: %[[VAL_11:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_6]](%[[VAL_11]]) typeparams %[[VAL_5]]#1 dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift3cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (index) -> i64 +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_15:.*]] = fir.alloca !fir.char<1,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_16:.*]] = fir.emboxchar %[[VAL_15]], %[[VAL_2]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_17:.*]] = hlfir.elemental %[[VAL_11]] typeparams %[[VAL_5]]#1 unordered : (!fir.shape<1>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_18:.*]]: index): +// CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (index) -> i64 +// CHECK: %[[VAL_20:.*]] = arith.addi %[[VAL_19]], %[[VAL_14]] overflow : i64 +// CHECK: %[[VAL_21:.*]] = arith.cmpi sge, %[[VAL_20]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_22:.*]] = arith.cmpi sle, %[[VAL_20]], %[[VAL_13]] : i64 +// CHECK: %[[VAL_23:.*]] = arith.andi %[[VAL_21]], %[[VAL_22]] : i1 +// CHECK: %[[VAL_24:.*]] = fir.if %[[VAL_23]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_20]] : (i64) -> index +// CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_12]]#0 (%[[VAL_25]]) typeparams %[[VAL_5]]#1 : (!fir.box>>, index, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_26]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_16]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_24]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_12]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_17]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with scalar constant boundary. +// subroutine eoshift4c(n, array) +// integer :: n +// character(10,1) :: array(n) +// array = EOSHIFT(array, 2, '0123456789') +// end subroutine +func.func @_QPeoshift4c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift4cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = arith.cmpi sgt, %5, %c0 : index + %7 = arith.select %6, %5, %c0 : index + %8 = fir.shape %7 : (index) -> !fir.shape<1> + %9:2 = hlfir.declare %3(%8) typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift4cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %10 = fir.address_of(@_QQclX30313233343536373839) : !fir.ref> + %11:2 = hlfir.declare %10 typeparams %c10 {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX30313233343536373839"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) + %12 = hlfir.eoshift %9#0 %c2_i32 boundary %11#0 : (!fir.box>>, i32, !fir.ref>) -> !hlfir.expr> + hlfir.assign %12 to %9#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %12 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift4c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift4cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i32) -> index +// CHECK: %[[VAL_10:.*]] = arith.cmpi sgt, %[[VAL_9]], %[[VAL_2]] : index +// CHECK: %[[VAL_11:.*]] = arith.select %[[VAL_10]], %[[VAL_9]], %[[VAL_2]] : index +// CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_11]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_12]]) typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift4cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_14:.*]] = fir.address_of(@_QQclX30313233343536373839) : !fir.ref> +// CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] typeparams %[[VAL_3]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX30313233343536373839"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_11]] : (index) -> i64 +// CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_18:.*]] = fir.emboxchar %[[VAL_15]]#0, %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_19:.*]] = hlfir.elemental %[[VAL_12]] typeparams %[[VAL_3]] unordered : (!fir.shape<1>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_20:.*]]: index): +// CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (index) -> i64 +// CHECK: %[[VAL_22:.*]] = arith.addi %[[VAL_21]], %[[VAL_17]] overflow : i64 +// CHECK: %[[VAL_23:.*]] = arith.cmpi sge, %[[VAL_22]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_24:.*]] = arith.cmpi sle, %[[VAL_22]], %[[VAL_16]] : i64 +// CHECK: %[[VAL_25:.*]] = arith.andi %[[VAL_23]], %[[VAL_24]] : i1 +// CHECK: %[[VAL_26:.*]] = fir.if %[[VAL_25]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_22]] : (i64) -> index +// CHECK: %[[VAL_28:.*]] = hlfir.designate %[[VAL_13]]#0 (%[[VAL_27]]) typeparams %[[VAL_3]] : (!fir.box>>, index, index) -> !fir.ref> +// CHECK: %[[VAL_29:.*]] = fir.emboxchar %[[VAL_28]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_29]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_18]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_26]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_19]] to %[[VAL_13]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_19]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with scalar always present boundary. +// ! CHARACTER with constant length. +// subroutine eoshift5c(n, array, boundary) +// integer :: n +// character(10,1) :: array(n), boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift5c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<1> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift5cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref> + %4:2 = hlfir.declare %3 typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift5cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.ref>, !fir.ref>) + %5:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %6 = fir.convert %5#0 : (!fir.ref>) -> !fir.ref>> + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.shape %10 : (index) -> !fir.shape<1> + %12:2 = hlfir.declare %6(%11) typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift5cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %13 = hlfir.eoshift %12#0 %c2_i32 boundary %4#0 : (!fir.box>>, i32, !fir.ref>) -> !hlfir.expr> + hlfir.assign %13 to %12#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %13 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift5c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<1> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift5cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref>) -> !fir.ref> +// CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift5cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_9:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i32) -> index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_15:.*]] = fir.shape %[[VAL_14]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_10]](%[[VAL_15]]) typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift5cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_14]] : (index) -> i64 +// CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_19:.*]] = fir.emboxchar %[[VAL_8]]#0, %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_20:.*]] = hlfir.elemental %[[VAL_15]] typeparams %[[VAL_3]] unordered : (!fir.shape<1>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_21:.*]]: index): +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_21]] : (index) -> i64 +// CHECK: %[[VAL_23:.*]] = arith.addi %[[VAL_22]], %[[VAL_18]] overflow : i64 +// CHECK: %[[VAL_24:.*]] = arith.cmpi sge, %[[VAL_23]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_25:.*]] = arith.cmpi sle, %[[VAL_23]], %[[VAL_17]] : i64 +// CHECK: %[[VAL_26:.*]] = arith.andi %[[VAL_24]], %[[VAL_25]] : i1 +// CHECK: %[[VAL_27:.*]] = fir.if %[[VAL_26]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_23]] : (i64) -> index +// CHECK: %[[VAL_29:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_28]]) typeparams %[[VAL_3]] : (!fir.box>>, index, index) -> !fir.ref> +// CHECK: %[[VAL_30:.*]] = fir.emboxchar %[[VAL_29]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_30]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_19]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_27]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_20]] to %[[VAL_16]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_20]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with scalar always present boundary. +// ! CHARACTER with variable length. +// subroutine eoshift6c(n, array, boundary) +// integer :: n +// character(n,1) :: array(n), boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift6c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<1> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c0_i32 = arith.constant 0 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift6cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = arith.cmpi sgt, %4, %c0_i32 : i32 + %6 = arith.select %5, %4, %c0_i32 : i32 + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.shape %10 : (index) -> !fir.shape<1> + %12:2 = hlfir.declare %3(%11) typeparams %6 dummy_scope %0 {uniq_name = "_QFeoshift6cEarray"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %13:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %14 = fir.load %1#0 : !fir.ref + %15 = arith.cmpi sgt, %14, %c0_i32 : i32 + %16 = arith.select %15, %14, %c0_i32 : i32 + %17:2 = hlfir.declare %13#0 typeparams %16 dummy_scope %0 {uniq_name = "_QFeoshift6cEboundary"} : (!fir.ref>, i32, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref>) + %18 = hlfir.eoshift %12#0 %c2_i32 boundary %17#0 : (!fir.box>>, i32, !fir.boxchar<1>) -> !hlfir.expr> + hlfir.assign %18 to %12#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %18 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift6c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<1> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift6cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i32) -> index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_15:.*]] = fir.shape %[[VAL_14]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_15]]) typeparams %[[VAL_10]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift6cEarray"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_17:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_19:.*]] = arith.cmpi sgt, %[[VAL_18]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_19]], %[[VAL_18]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]]#0 typeparams %[[VAL_20]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift6cEboundary"} : (!fir.ref>, i32, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref>) +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_14]] : (index) -> i64 +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_24:.*]] = hlfir.elemental %[[VAL_15]] typeparams %[[VAL_10]] unordered : (!fir.shape<1>, i32) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_25:.*]]: index): +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (index) -> i64 +// CHECK: %[[VAL_27:.*]] = arith.addi %[[VAL_26]], %[[VAL_23]] overflow : i64 +// CHECK: %[[VAL_28:.*]] = arith.cmpi sge, %[[VAL_27]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_29:.*]] = arith.cmpi sle, %[[VAL_27]], %[[VAL_22]] : i64 +// CHECK: %[[VAL_30:.*]] = arith.andi %[[VAL_28]], %[[VAL_29]] : i1 +// CHECK: %[[VAL_31:.*]] = fir.if %[[VAL_30]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_27]] : (i64) -> index +// CHECK: %[[VAL_33:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_32]]) typeparams %[[VAL_10]] : (!fir.box>>, index, i32) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_33]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_21]]#0 : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_31]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_16]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_24]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with scalar always present boundary. +// ! CHARACTER with assumed length. +// subroutine eoshift7c(n, array, boundary) +// integer :: n +// character(*,1) :: array(n), boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift7c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<1> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift7cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3:2 = hlfir.declare %2#0 typeparams %2#1 dummy_scope %0 {uniq_name = "_QFeoshift7cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref>) + %4:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %5 = fir.convert %4#0 : (!fir.ref>) -> !fir.ref>> + %6 = fir.load %1#0 : !fir.ref + %7 = fir.convert %6 : (i32) -> index + %8 = arith.cmpi sgt, %7, %c0 : index + %9 = arith.select %8, %7, %c0 : index + %10 = fir.shape %9 : (index) -> !fir.shape<1> + %11:2 = hlfir.declare %5(%10) typeparams %4#1 dummy_scope %0 {uniq_name = "_QFeoshift7cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %12 = hlfir.eoshift %11#0 %c2_i32 boundary %3#0 : (!fir.box>>, i32, !fir.boxchar<1>) -> !hlfir.expr> + hlfir.assign %12 to %11#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %12 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift7c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<1> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift7cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_5:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]]#0 typeparams %[[VAL_5]]#1 dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift7cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.boxchar<1>, !fir.ref>) +// CHECK: %[[VAL_7:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i32) -> index +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_2]] : index +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_10]], %[[VAL_2]] : index +// CHECK: %[[VAL_13:.*]] = fir.shape %[[VAL_12]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_13]]) typeparams %[[VAL_7]]#1 dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift7cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_12]] : (index) -> i64 +// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_17:.*]] = hlfir.elemental %[[VAL_13]] typeparams %[[VAL_7]]#1 unordered : (!fir.shape<1>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_18:.*]]: index): +// CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (index) -> i64 +// CHECK: %[[VAL_20:.*]] = arith.addi %[[VAL_19]], %[[VAL_16]] overflow : i64 +// CHECK: %[[VAL_21:.*]] = arith.cmpi sge, %[[VAL_20]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_22:.*]] = arith.cmpi sle, %[[VAL_20]], %[[VAL_15]] : i64 +// CHECK: %[[VAL_23:.*]] = arith.andi %[[VAL_21]], %[[VAL_22]] : i1 +// CHECK: %[[VAL_24:.*]] = fir.if %[[VAL_23]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_20]] : (i64) -> index +// CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_14]]#0 (%[[VAL_25]]) typeparams %[[VAL_7]]#1 : (!fir.box>>, index, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_26]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_6]]#0 : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_24]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_14]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_17]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the scalar optional boundary. +// ! CHARACTER with constant length. +// subroutine eoshift8c(n, array, boundary) +// integer :: n +// character(10,2) :: array(n) +// character(10,2), optional :: boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift8c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<2> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<2> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift8cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg2 : (!fir.boxchar<2>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref> + %4:2 = hlfir.declare %3 typeparams %c10 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift8cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.ref>, !fir.ref>) + %5:2 = fir.unboxchar %arg1 : (!fir.boxchar<2>) -> (!fir.ref>, index) + %6 = fir.convert %5#0 : (!fir.ref>) -> !fir.ref>> + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.shape %10 : (index) -> !fir.shape<1> + %12:2 = hlfir.declare %6(%11) typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift8cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %13 = fir.is_present %4#0 : (!fir.ref>) -> i1 + %14 = fir.embox %4#0 : (!fir.ref>) -> !fir.box> + %15 = fir.absent !fir.box> + %16 = arith.select %13, %14, %15 : !fir.box> + %17 = hlfir.eoshift %12#0 %c2_i32 boundary %16 : (!fir.box>>, i32, !fir.box>) -> !hlfir.expr> + hlfir.assign %17 to %12#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %17 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift8c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<2> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<2> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift8cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<2>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref>) -> !fir.ref> +// CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift8cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.ref>, !fir.ref>) +// CHECK: %[[VAL_9:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<2>) -> (!fir.ref>, index) +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i32) -> index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_15:.*]] = fir.shape %[[VAL_14]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_10]](%[[VAL_15]]) typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift8cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_17:.*]] = fir.is_present %[[VAL_8]]#0 : (!fir.ref>) -> i1 +// CHECK: %[[VAL_18:.*]] = fir.embox %[[VAL_8]]#0 : (!fir.ref>) -> !fir.box> +// CHECK: %[[VAL_19:.*]] = fir.absent !fir.box> +// CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_17]], %[[VAL_18]], %[[VAL_19]] : !fir.box> +// CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_14]] : (index) -> i64 +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_23:.*]] = fir.is_present %[[VAL_20]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_24:.*]] = fir.if %[[VAL_23]] -> (!fir.boxchar<2>) { +// CHECK: %[[VAL_25:.*]] = fir.box_addr %[[VAL_20]] : (!fir.box>) -> !fir.ref> +// CHECK: %[[VAL_26:.*]] = fir.emboxchar %[[VAL_25]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_26]] : !fir.boxchar<2> +// CHECK: } else { +// CHECK: %[[VAL_27:.*]] = fir.alloca !fir.char<2,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_28:.*]] = fir.emboxchar %[[VAL_27]], %[[VAL_2]] : (!fir.ref>, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_28]] : !fir.boxchar<2> +// CHECK: } +// CHECK: %[[VAL_29:.*]] = hlfir.elemental %[[VAL_15]] typeparams %[[VAL_3]] unordered : (!fir.shape<1>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_30:.*]]: index): +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (index) -> i64 +// CHECK: %[[VAL_32:.*]] = arith.addi %[[VAL_31]], %[[VAL_22]] overflow : i64 +// CHECK: %[[VAL_33:.*]] = arith.cmpi sge, %[[VAL_32]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_34:.*]] = arith.cmpi sle, %[[VAL_32]], %[[VAL_21]] : i64 +// CHECK: %[[VAL_35:.*]] = arith.andi %[[VAL_33]], %[[VAL_34]] : i1 +// CHECK: %[[VAL_36:.*]] = fir.if %[[VAL_35]] -> (!fir.boxchar<2>) { +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_32]] : (i64) -> index +// CHECK: %[[VAL_38:.*]] = hlfir.designate %[[VAL_16]]#0 (%[[VAL_37]]) typeparams %[[VAL_3]] : (!fir.box>>, index, index) -> !fir.ref> +// CHECK: %[[VAL_39:.*]] = fir.emboxchar %[[VAL_38]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_39]] : !fir.boxchar<2> +// CHECK: } else { +// CHECK: fir.result %[[VAL_24]] : !fir.boxchar<2> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_36]] : !fir.boxchar<2> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_29]] to %[[VAL_16]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_29]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the scalar optional boundary. +// ! CHARACTER with variable length. +// subroutine eoshift9c(n, array, boundary) +// integer :: n +// character(n,2) :: array(n) +// character(n,2), optional :: boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift9c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<2> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<2> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c0_i32 = arith.constant 0 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift9cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<2>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = arith.cmpi sgt, %4, %c0_i32 : i32 + %6 = arith.select %5, %4, %c0_i32 : i32 + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.shape %10 : (index) -> !fir.shape<1> + %12:2 = hlfir.declare %3(%11) typeparams %6 dummy_scope %0 {uniq_name = "_QFeoshift9cEarray"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %13:2 = fir.unboxchar %arg2 : (!fir.boxchar<2>) -> (!fir.ref>, index) + %14 = fir.load %1#0 : !fir.ref + %15 = arith.cmpi sgt, %14, %c0_i32 : i32 + %16 = arith.select %15, %14, %c0_i32 : i32 + %17:2 = hlfir.declare %13#0 typeparams %16 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift9cEboundary"} : (!fir.ref>, i32, !fir.dscope) -> (!fir.boxchar<2>, !fir.ref>) + %18 = fir.is_present %17#0 : (!fir.boxchar<2>) -> i1 + %19 = fir.embox %17#1 typeparams %16 : (!fir.ref>, i32) -> !fir.box> + %20 = fir.absent !fir.box> + %21 = arith.select %18, %19, %20 : !fir.box> + %22 = hlfir.eoshift %12#0 %c2_i32 boundary %21 : (!fir.box>>, i32, !fir.box>) -> !hlfir.expr> + hlfir.assign %22 to %12#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %22 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift9c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<2> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<2> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_5:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift9cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_7:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<2>) -> (!fir.ref>, index) +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +// CHECK: %[[VAL_10:.*]] = arith.cmpi sgt, %[[VAL_9]], %[[VAL_4]] : i32 +// CHECK: %[[VAL_11:.*]] = arith.select %[[VAL_10]], %[[VAL_9]], %[[VAL_4]] : i32 +// CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +// CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i32) -> index +// CHECK: %[[VAL_14:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_3]] : index +// CHECK: %[[VAL_15:.*]] = arith.select %[[VAL_14]], %[[VAL_13]], %[[VAL_3]] : index +// CHECK: %[[VAL_16:.*]] = fir.shape %[[VAL_15]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_16]]) typeparams %[[VAL_11]] dummy_scope %[[VAL_5]] {uniq_name = "_QFeoshift9cEarray"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_18:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<2>) -> (!fir.ref>, index) +// CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref +// CHECK: %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_19]], %[[VAL_4]] : i32 +// CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_19]], %[[VAL_4]] : i32 +// CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]]#0 typeparams %[[VAL_21]] dummy_scope %[[VAL_5]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift9cEboundary"} : (!fir.ref>, i32, !fir.dscope) -> (!fir.boxchar<2>, !fir.ref>) +// CHECK: %[[VAL_23:.*]] = fir.is_present %[[VAL_22]]#0 : (!fir.boxchar<2>) -> i1 +// CHECK: %[[VAL_24:.*]] = fir.embox %[[VAL_22]]#1 typeparams %[[VAL_21]] : (!fir.ref>, i32) -> !fir.box> +// CHECK: %[[VAL_25:.*]] = fir.absent !fir.box> +// CHECK: %[[VAL_26:.*]] = arith.select %[[VAL_23]], %[[VAL_24]], %[[VAL_25]] : !fir.box> +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_15]] : (index) -> i64 +// CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_2]] : (i32) -> i64 +// CHECK: %[[VAL_29:.*]] = fir.is_present %[[VAL_26]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_30:.*]] = fir.if %[[VAL_29]] -> (!fir.boxchar<2>) { +// CHECK: %[[VAL_31:.*]] = fir.box_addr %[[VAL_26]] : (!fir.box>) -> !fir.ref> +// CHECK: %[[VAL_32:.*]] = fir.box_elesize %[[VAL_26]] : (!fir.box>) -> index +// CHECK: %[[VAL_33:.*]] = arith.divsi %[[VAL_32]], %[[VAL_1]] : index +// CHECK: %[[VAL_34:.*]] = fir.emboxchar %[[VAL_31]], %[[VAL_33]] : (!fir.ref>, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_34]] : !fir.boxchar<2> +// CHECK: } else { +// CHECK: %[[VAL_35:.*]] = fir.alloca !fir.char<2,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_36:.*]] = fir.emboxchar %[[VAL_35]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_36]] : !fir.boxchar<2> +// CHECK: } +// CHECK: %[[VAL_37:.*]] = hlfir.elemental %[[VAL_16]] typeparams %[[VAL_11]] unordered : (!fir.shape<1>, i32) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_38:.*]]: index): +// CHECK: %[[VAL_39:.*]] = fir.convert %[[VAL_38]] : (index) -> i64 +// CHECK: %[[VAL_40:.*]] = arith.addi %[[VAL_39]], %[[VAL_28]] overflow : i64 +// CHECK: %[[VAL_41:.*]] = arith.cmpi sge, %[[VAL_40]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_42:.*]] = arith.cmpi sle, %[[VAL_40]], %[[VAL_27]] : i64 +// CHECK: %[[VAL_43:.*]] = arith.andi %[[VAL_41]], %[[VAL_42]] : i1 +// CHECK: %[[VAL_44:.*]] = fir.if %[[VAL_43]] -> (!fir.boxchar<2>) { +// CHECK: %[[VAL_45:.*]] = fir.convert %[[VAL_40]] : (i64) -> index +// CHECK: %[[VAL_46:.*]] = hlfir.designate %[[VAL_17]]#0 (%[[VAL_45]]) typeparams %[[VAL_11]] : (!fir.box>>, index, i32) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_46]] : !fir.boxchar<2> +// CHECK: } else { +// CHECK: fir.result %[[VAL_30]] : !fir.boxchar<2> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_44]] : !fir.boxchar<2> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_37]] to %[[VAL_17]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_37]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the scalar optional boundary. +// ! CHARACTER with assumed length. +// subroutine eoshift10c(n, array, boundary) +// integer :: n +// character(*,2) :: array(n) +// character(*,2), optional :: boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift10c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<2> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<2> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift10cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg2 : (!fir.boxchar<2>) -> (!fir.ref>, index) + %3:2 = hlfir.declare %2#0 typeparams %2#1 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift10cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.boxchar<2>, !fir.ref>) + %4:2 = fir.unboxchar %arg1 : (!fir.boxchar<2>) -> (!fir.ref>, index) + %5 = fir.convert %4#0 : (!fir.ref>) -> !fir.ref>> + %6 = fir.load %1#0 : !fir.ref + %7 = fir.convert %6 : (i32) -> index + %8 = arith.cmpi sgt, %7, %c0 : index + %9 = arith.select %8, %7, %c0 : index + %10 = fir.shape %9 : (index) -> !fir.shape<1> + %11:2 = hlfir.declare %5(%10) typeparams %4#1 dummy_scope %0 {uniq_name = "_QFeoshift10cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %12 = fir.is_present %3#0 : (!fir.boxchar<2>) -> i1 + %13 = fir.embox %3#1 typeparams %2#1 : (!fir.ref>, index) -> !fir.box> + %14 = fir.absent !fir.box> + %15 = arith.select %12, %13, %14 : !fir.box> + %16 = hlfir.eoshift %11#0 %c2_i32 boundary %15 : (!fir.box>>, i32, !fir.box>) -> !hlfir.expr> + hlfir.assign %16 to %11#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %16 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift10c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<2> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<2> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift10cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<2>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]]#0 typeparams %[[VAL_6]]#1 dummy_scope %[[VAL_4]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift10cEboundary"} : (!fir.ref>, index, !fir.dscope) -> (!fir.boxchar<2>, !fir.ref>) +// CHECK: %[[VAL_8:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<2>) -> (!fir.ref>, index) +// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i32) -> index +// CHECK: %[[VAL_12:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_3]] : index +// CHECK: %[[VAL_13:.*]] = arith.select %[[VAL_12]], %[[VAL_11]], %[[VAL_3]] : index +// CHECK: %[[VAL_14:.*]] = fir.shape %[[VAL_13]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_9]](%[[VAL_14]]) typeparams %[[VAL_8]]#1 dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift10cEarray"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_16:.*]] = fir.is_present %[[VAL_7]]#0 : (!fir.boxchar<2>) -> i1 +// CHECK: %[[VAL_17:.*]] = fir.embox %[[VAL_7]]#1 typeparams %[[VAL_6]]#1 : (!fir.ref>, index) -> !fir.box> +// CHECK: %[[VAL_18:.*]] = fir.absent !fir.box> +// CHECK: %[[VAL_19:.*]] = arith.select %[[VAL_16]], %[[VAL_17]], %[[VAL_18]] : !fir.box> +// CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_13]] : (index) -> i64 +// CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_2]] : (i32) -> i64 +// CHECK: %[[VAL_22:.*]] = fir.is_present %[[VAL_19]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_23:.*]] = fir.if %[[VAL_22]] -> (!fir.boxchar<2>) { +// CHECK: %[[VAL_24:.*]] = fir.box_addr %[[VAL_19]] : (!fir.box>) -> !fir.ref> +// CHECK: %[[VAL_25:.*]] = fir.box_elesize %[[VAL_19]] : (!fir.box>) -> index +// CHECK: %[[VAL_26:.*]] = arith.divsi %[[VAL_25]], %[[VAL_1]] : index +// CHECK: %[[VAL_27:.*]] = fir.emboxchar %[[VAL_24]], %[[VAL_26]] : (!fir.ref>, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_27]] : !fir.boxchar<2> +// CHECK: } else { +// CHECK: %[[VAL_28:.*]] = fir.alloca !fir.char<2,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_29:.*]] = fir.emboxchar %[[VAL_28]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_29]] : !fir.boxchar<2> +// CHECK: } +// CHECK: %[[VAL_30:.*]] = hlfir.elemental %[[VAL_14]] typeparams %[[VAL_8]]#1 unordered : (!fir.shape<1>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_31:.*]]: index): +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_31]] : (index) -> i64 +// CHECK: %[[VAL_33:.*]] = arith.addi %[[VAL_32]], %[[VAL_21]] overflow : i64 +// CHECK: %[[VAL_34:.*]] = arith.cmpi sge, %[[VAL_33]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_35:.*]] = arith.cmpi sle, %[[VAL_33]], %[[VAL_20]] : i64 +// CHECK: %[[VAL_36:.*]] = arith.andi %[[VAL_34]], %[[VAL_35]] : i1 +// CHECK: %[[VAL_37:.*]] = fir.if %[[VAL_36]] -> (!fir.boxchar<2>) { +// CHECK: %[[VAL_38:.*]] = fir.convert %[[VAL_33]] : (i64) -> index +// CHECK: %[[VAL_39:.*]] = hlfir.designate %[[VAL_15]]#0 (%[[VAL_38]]) typeparams %[[VAL_8]]#1 : (!fir.box>>, index, index) -> !fir.boxchar<2> +// CHECK: fir.result %[[VAL_39]] : !fir.boxchar<2> +// CHECK: } else { +// CHECK: fir.result %[[VAL_23]] : !fir.boxchar<2> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_37]] : !fir.boxchar<2> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_30]] to %[[VAL_15]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_30]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array always present boundary. +// ! CHARACTER with constant length. +// subroutine eoshift11c(n, array, boundary) +// integer :: n +// character(10,4) :: array(n,n), boundary(:) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift11c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<4> {fir.bindc_name = "array"}, %arg2: !fir.box>> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift11cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg2 typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift11cEboundary"} : (!fir.box>>, index, !fir.dscope) -> (!fir.box>>, !fir.box>>) + %3:2 = fir.unboxchar %arg1 : (!fir.boxchar<4>) -> (!fir.ref>, index) + %4 = fir.convert %3#0 : (!fir.ref>) -> !fir.ref>> + %5 = fir.load %1#0 : !fir.ref + %6 = fir.convert %5 : (i32) -> index + %7 = arith.cmpi sgt, %6, %c0 : index + %8 = arith.select %7, %6, %c0 : index + %9 = fir.load %1#0 : !fir.ref + %10 = fir.convert %9 : (i32) -> index + %11 = arith.cmpi sgt, %10, %c0 : index + %12 = arith.select %11, %10, %c0 : index + %13 = fir.shape %8, %12 : (index, index) -> !fir.shape<2> + %14:2 = hlfir.declare %4(%13) typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift11cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %15 = hlfir.eoshift %14#0 %c2_i32 boundary %2#0 : (!fir.box>>, i32, !fir.box>>) -> !hlfir.expr> + hlfir.assign %15 to %14#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %15 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift11c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<4> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.box>> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift11cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG2]] typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift11cEboundary"} : (!fir.box>>, index, !fir.dscope) -> (!fir.box>>, !fir.box>>) +// CHECK: %[[VAL_7:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<4>) -> (!fir.ref>, index) +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i32) -> index +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_2]] : index +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_10]], %[[VAL_2]] : index +// CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> index +// CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_2]] : index +// CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_14]], %[[VAL_2]] : index +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_12]], %[[VAL_16]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_17]]) typeparams %[[VAL_3]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift11cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_12]] : (index) -> i64 +// CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_21:.*]] = hlfir.elemental %[[VAL_17]] typeparams %[[VAL_3]] unordered : (!fir.shape<2>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_22:.*]]: index, %[[VAL_23:.*]]: index): +// CHECK: %[[VAL_24:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_23]]) typeparams %[[VAL_3]] : (!fir.box>>, index, index) -> !fir.ref> +// CHECK: %[[VAL_25:.*]] = fir.emboxchar %[[VAL_24]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<4> +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_22]] : (index) -> i64 +// CHECK: %[[VAL_27:.*]] = arith.addi %[[VAL_26]], %[[VAL_20]] overflow : i64 +// CHECK: %[[VAL_28:.*]] = arith.cmpi sge, %[[VAL_27]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_29:.*]] = arith.cmpi sle, %[[VAL_27]], %[[VAL_19]] : i64 +// CHECK: %[[VAL_30:.*]] = arith.andi %[[VAL_28]], %[[VAL_29]] : i1 +// CHECK: %[[VAL_31:.*]] = fir.if %[[VAL_30]] -> (!fir.boxchar<4>) { +// CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_27]] : (i64) -> index +// CHECK: %[[VAL_33:.*]] = hlfir.designate %[[VAL_18]]#0 (%[[VAL_32]], %[[VAL_23]]) typeparams %[[VAL_3]] : (!fir.box>>, index, index, index) -> !fir.ref> +// CHECK: %[[VAL_34:.*]] = fir.emboxchar %[[VAL_33]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<4> +// CHECK: fir.result %[[VAL_34]] : !fir.boxchar<4> +// CHECK: } else { +// CHECK: fir.result %[[VAL_25]] : !fir.boxchar<4> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_31]] : !fir.boxchar<4> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_21]] to %[[VAL_18]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_21]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array always present boundary. +// ! CHARACTER with variable length. +// subroutine eoshift12c(n, array, boundary) +// integer :: n +// character(n,4) :: array(n,n), boundary(:) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift12c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<4> {fir.bindc_name = "array"}, %arg2: !fir.box>> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c0_i32 = arith.constant 0 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift12cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<4>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = arith.cmpi sgt, %4, %c0_i32 : i32 + %6 = arith.select %5, %4, %c0_i32 : i32 + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.load %1#0 : !fir.ref + %12 = fir.convert %11 : (i32) -> index + %13 = arith.cmpi sgt, %12, %c0 : index + %14 = arith.select %13, %12, %c0 : index + %15 = fir.shape %10, %14 : (index, index) -> !fir.shape<2> + %16:2 = hlfir.declare %3(%15) typeparams %6 dummy_scope %0 {uniq_name = "_QFeoshift12cEarray"} : (!fir.ref>>, !fir.shape<2>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %17 = fir.load %1#0 : !fir.ref + %18 = arith.cmpi sgt, %17, %c0_i32 : i32 + %19 = arith.select %18, %17, %c0_i32 : i32 + %20:2 = hlfir.declare %arg2 typeparams %19 dummy_scope %0 {uniq_name = "_QFeoshift12cEboundary"} : (!fir.box>>, i32, !fir.dscope) -> (!fir.box>>, !fir.box>>) + %21 = hlfir.eoshift %16#0 %c2_i32 boundary %20#0 : (!fir.box>>, i32, !fir.box>>) -> !hlfir.expr> + hlfir.assign %21 to %16#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %21 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift12c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<4> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.box>> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift12cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<4>) -> (!fir.ref>, index) +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_8]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_9]], %[[VAL_8]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i32) -> index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_12]], %[[VAL_2]] : index +// CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (i32) -> index +// CHECK: %[[VAL_17:.*]] = arith.cmpi sgt, %[[VAL_16]], %[[VAL_2]] : index +// CHECK: %[[VAL_18:.*]] = arith.select %[[VAL_17]], %[[VAL_16]], %[[VAL_2]] : index +// CHECK: %[[VAL_19:.*]] = fir.shape %[[VAL_14]], %[[VAL_18]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_19]]) typeparams %[[VAL_10]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift12cEarray"} : (!fir.ref>>, !fir.shape<2>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_21:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_22:.*]] = arith.cmpi sgt, %[[VAL_21]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_23:.*]] = arith.select %[[VAL_22]], %[[VAL_21]], %[[VAL_3]] : i32 +// CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[ARG2]] typeparams %[[VAL_23]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift12cEboundary"} : (!fir.box>>, i32, !fir.dscope) -> (!fir.box>>, !fir.box>>) +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_14]] : (index) -> i64 +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_1]] : (i32) -> i64 +// CHECK: %[[VAL_27:.*]] = hlfir.elemental %[[VAL_19]] typeparams %[[VAL_10]] unordered : (!fir.shape<2>, i32) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_28:.*]]: index, %[[VAL_29:.*]]: index): +// CHECK: %[[VAL_30:.*]] = hlfir.designate %[[VAL_24]]#0 (%[[VAL_29]]) typeparams %[[VAL_23]] : (!fir.box>>, index, i32) -> !fir.boxchar<4> +// CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_28]] : (index) -> i64 +// CHECK: %[[VAL_32:.*]] = arith.addi %[[VAL_31]], %[[VAL_26]] overflow : i64 +// CHECK: %[[VAL_33:.*]] = arith.cmpi sge, %[[VAL_32]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_34:.*]] = arith.cmpi sle, %[[VAL_32]], %[[VAL_25]] : i64 +// CHECK: %[[VAL_35:.*]] = arith.andi %[[VAL_33]], %[[VAL_34]] : i1 +// CHECK: %[[VAL_36:.*]] = fir.if %[[VAL_35]] -> (!fir.boxchar<4>) { +// CHECK: %[[VAL_37:.*]] = fir.convert %[[VAL_32]] : (i64) -> index +// CHECK: %[[VAL_38:.*]] = hlfir.designate %[[VAL_20]]#0 (%[[VAL_37]], %[[VAL_29]]) typeparams %[[VAL_10]] : (!fir.box>>, index, index, i32) -> !fir.boxchar<4> +// CHECK: fir.result %[[VAL_38]] : !fir.boxchar<4> +// CHECK: } else { +// CHECK: fir.result %[[VAL_30]] : !fir.boxchar<4> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_36]] : !fir.boxchar<4> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_27]] to %[[VAL_20]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_27]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array always present boundary. +// ! CHARACTER with assumed length. +// subroutine eoshift13c(n, array, boundary) +// integer :: n +// character(*,4) :: array(n,n), boundary(:) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift13c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<4> {fir.bindc_name = "array"}, %arg2: !fir.box>> {fir.bindc_name = "boundary"}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift13cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg2 dummy_scope %0 {uniq_name = "_QFeoshift13cEboundary"} : (!fir.box>>, !fir.dscope) -> (!fir.box>>, !fir.box>>) + %3:2 = fir.unboxchar %arg1 : (!fir.boxchar<4>) -> (!fir.ref>, index) + %4 = fir.convert %3#0 : (!fir.ref>) -> !fir.ref>> + %5 = fir.load %1#0 : !fir.ref + %6 = fir.convert %5 : (i32) -> index + %7 = arith.cmpi sgt, %6, %c0 : index + %8 = arith.select %7, %6, %c0 : index + %9 = fir.load %1#0 : !fir.ref + %10 = fir.convert %9 : (i32) -> index + %11 = arith.cmpi sgt, %10, %c0 : index + %12 = arith.select %11, %10, %c0 : index + %13 = fir.shape %8, %12 : (index, index) -> !fir.shape<2> + %14:2 = hlfir.declare %4(%13) typeparams %3#1 dummy_scope %0 {uniq_name = "_QFeoshift13cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %15 = hlfir.eoshift %14#0 %c2_i32 boundary %2#0 : (!fir.box>>, i32, !fir.box>>) -> !hlfir.expr> + hlfir.assign %15 to %14#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %15 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift13c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<4> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.box>> {fir.bindc_name = "boundary"}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 4 : index +// CHECK: %[[VAL_2:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_3:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_4:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift13cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift13cEboundary"} : (!fir.box>>, !fir.dscope) -> (!fir.box>>, !fir.box>>) +// CHECK: %[[VAL_7:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<4>) -> (!fir.ref>, index) +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i32) -> index +// CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_3]] : index +// CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_10]], %[[VAL_3]] : index +// CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +// CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (i32) -> index +// CHECK: %[[VAL_15:.*]] = arith.cmpi sgt, %[[VAL_14]], %[[VAL_3]] : index +// CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_14]], %[[VAL_3]] : index +// CHECK: %[[VAL_17:.*]] = fir.shape %[[VAL_12]], %[[VAL_16]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_8]](%[[VAL_17]]) typeparams %[[VAL_7]]#1 dummy_scope %[[VAL_4]] {uniq_name = "_QFeoshift13cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_12]] : (index) -> i64 +// CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_2]] : (i32) -> i64 +// CHECK: %[[VAL_21:.*]] = hlfir.elemental %[[VAL_17]] typeparams %[[VAL_7]]#1 unordered : (!fir.shape<2>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_22:.*]]: index, %[[VAL_23:.*]]: index): +// CHECK: %[[VAL_24:.*]] = fir.box_elesize %[[VAL_6]]#1 : (!fir.box>>) -> index +// CHECK: %[[VAL_25:.*]] = arith.divsi %[[VAL_24]], %[[VAL_1]] : index +// CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_23]]) typeparams %[[VAL_25]] : (!fir.box>>, index, index) -> !fir.boxchar<4> +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_22]] : (index) -> i64 +// CHECK: %[[VAL_28:.*]] = arith.addi %[[VAL_27]], %[[VAL_20]] overflow : i64 +// CHECK: %[[VAL_29:.*]] = arith.cmpi sge, %[[VAL_28]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_30:.*]] = arith.cmpi sle, %[[VAL_28]], %[[VAL_19]] : i64 +// CHECK: %[[VAL_31:.*]] = arith.andi %[[VAL_29]], %[[VAL_30]] : i1 +// CHECK: %[[VAL_32:.*]] = fir.if %[[VAL_31]] -> (!fir.boxchar<4>) { +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_28]] : (i64) -> index +// CHECK: %[[VAL_34:.*]] = hlfir.designate %[[VAL_18]]#0 (%[[VAL_33]], %[[VAL_23]]) typeparams %[[VAL_7]]#1 : (!fir.box>>, index, index, index) -> !fir.boxchar<4> +// CHECK: fir.result %[[VAL_34]] : !fir.boxchar<4> +// CHECK: } else { +// CHECK: fir.result %[[VAL_26]] : !fir.boxchar<4> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_32]] : !fir.boxchar<4> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_21]] to %[[VAL_18]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_21]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array optional boundary. +// ! CHARACTER with constant length. +// subroutine eoshift14c(n, array, boundary) +// integer :: n +// character(10,1) :: array(n,n) +// character(10,1), optional :: boundary(n) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift14c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<1> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift14cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = arith.cmpi sgt, %5, %c0 : index + %7 = arith.select %6, %5, %c0 : index + %8 = fir.load %1#0 : !fir.ref + %9 = fir.convert %8 : (i32) -> index + %10 = arith.cmpi sgt, %9, %c0 : index + %11 = arith.select %10, %9, %c0 : index + %12 = fir.shape %7, %11 : (index, index) -> !fir.shape<2> + %13:2 = hlfir.declare %3(%12) typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift14cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %14:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %15 = fir.convert %14#0 : (!fir.ref>) -> !fir.ref>> + %16 = fir.load %1#0 : !fir.ref + %17 = fir.convert %16 : (i32) -> index + %18 = arith.cmpi sgt, %17, %c0 : index + %19 = arith.select %18, %17, %c0 : index + %20 = fir.shape %19 : (index) -> !fir.shape<1> + %21:2 = hlfir.declare %15(%20) typeparams %c10 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift14cEboundary"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %22 = fir.is_present %21#0 : (!fir.box>>) -> i1 + %23 = fir.shape %19 : (index) -> !fir.shape<1> + %24 = fir.embox %21#1(%23) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> + %25 = fir.absent !fir.box>> + %26 = arith.select %22, %24, %25 : !fir.box>> + %27 = hlfir.eoshift %13#0 %c2_i32 boundary %26 : (!fir.box>>, i32, !fir.box>>) -> !hlfir.expr> + hlfir.assign %27 to %13#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %27 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift14c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<1> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant false +// CHECK: %[[VAL_3:.*]] = arith.constant true +// CHECK: %[[VAL_4:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant 10 : index +// CHECK: %[[VAL_7:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_7]] {uniq_name = "_QFeoshift14cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_9:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (i32) -> index +// CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_12]], %[[VAL_5]] : index +// CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_12]], %[[VAL_5]] : index +// CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_15]] : (i32) -> index +// CHECK: %[[VAL_17:.*]] = arith.cmpi sgt, %[[VAL_16]], %[[VAL_5]] : index +// CHECK: %[[VAL_18:.*]] = arith.select %[[VAL_17]], %[[VAL_16]], %[[VAL_5]] : index +// CHECK: %[[VAL_19:.*]] = fir.shape %[[VAL_14]], %[[VAL_18]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_10]](%[[VAL_19]]) typeparams %[[VAL_6]] dummy_scope %[[VAL_7]] {uniq_name = "_QFeoshift14cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_21:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_21]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_23]] : (i32) -> index +// CHECK: %[[VAL_25:.*]] = arith.cmpi sgt, %[[VAL_24]], %[[VAL_5]] : index +// CHECK: %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_24]], %[[VAL_5]] : index +// CHECK: %[[VAL_27:.*]] = fir.shape %[[VAL_26]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_22]](%[[VAL_27]]) typeparams %[[VAL_6]] dummy_scope %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift14cEboundary"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_29:.*]] = fir.is_present %[[VAL_28]]#0 : (!fir.box>>) -> i1 +// CHECK: %[[VAL_30:.*]] = fir.shape %[[VAL_26]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_31:.*]] = fir.embox %[[VAL_28]]#1(%[[VAL_30]]) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> +// CHECK: %[[VAL_32:.*]] = fir.absent !fir.box>> +// CHECK: %[[VAL_33:.*]] = arith.select %[[VAL_29]], %[[VAL_31]], %[[VAL_32]] : !fir.box>> +// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_14]] : (index) -> i64 +// CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64 +// CHECK: %[[VAL_36:.*]] = fir.alloca !fir.char<1,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_37:.*]] = fir.emboxchar %[[VAL_36]], %[[VAL_5]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_38:.*]] = fir.is_present %[[VAL_33]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_39:.*]] = arith.select %[[VAL_38]], %[[VAL_2]], %[[VAL_3]] : i1 +// CHECK: %[[VAL_40:.*]] = hlfir.elemental %[[VAL_19]] typeparams %[[VAL_6]] unordered : (!fir.shape<2>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_41:.*]]: index, %[[VAL_42:.*]]: index): +// CHECK: %[[VAL_43:.*]] = fir.if %[[VAL_39]] -> (!fir.boxchar<1>) { +// CHECK: fir.result %[[VAL_37]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: %[[VAL_44:.*]]:3 = fir.box_dims %[[VAL_33]], %[[VAL_5]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_45:.*]] = arith.subi %[[VAL_44]]#0, %[[VAL_1]] overflow : index +// CHECK: %[[VAL_46:.*]] = arith.addi %[[VAL_42]], %[[VAL_45]] overflow : index +// CHECK: %[[VAL_47:.*]] = hlfir.designate %[[VAL_33]] (%[[VAL_46]]) typeparams %[[VAL_6]] : (!fir.box>>, index, index) -> !fir.ref> +// CHECK: %[[VAL_48:.*]] = fir.emboxchar %[[VAL_47]], %[[VAL_6]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_48]] : !fir.boxchar<1> +// CHECK: } +// CHECK: %[[VAL_49:.*]] = fir.convert %[[VAL_41]] : (index) -> i64 +// CHECK: %[[VAL_50:.*]] = arith.addi %[[VAL_49]], %[[VAL_35]] overflow : i64 +// CHECK: %[[VAL_51:.*]] = arith.cmpi sge, %[[VAL_50]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_52:.*]] = arith.cmpi sle, %[[VAL_50]], %[[VAL_34]] : i64 +// CHECK: %[[VAL_53:.*]] = arith.andi %[[VAL_51]], %[[VAL_52]] : i1 +// CHECK: %[[VAL_54:.*]] = fir.if %[[VAL_53]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_50]] : (i64) -> index +// CHECK: %[[VAL_56:.*]] = hlfir.designate %[[VAL_20]]#0 (%[[VAL_55]], %[[VAL_42]]) typeparams %[[VAL_6]] : (!fir.box>>, index, index, index) -> !fir.ref> +// CHECK: %[[VAL_57:.*]] = fir.emboxchar %[[VAL_56]], %[[VAL_6]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_57]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_43]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_54]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_40]] to %[[VAL_20]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_40]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array optional boundary. +// ! CHARACTER with variable length. +// subroutine eoshift15c(n, array, boundary) +// integer :: n +// character(n,1) :: array(n,n) +// character(n,1), optional :: boundary(n) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift15c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<1> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c0_i32 = arith.constant 0 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift15cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = arith.cmpi sgt, %4, %c0_i32 : i32 + %6 = arith.select %5, %4, %c0_i32 : i32 + %7 = fir.load %1#0 : !fir.ref + %8 = fir.convert %7 : (i32) -> index + %9 = arith.cmpi sgt, %8, %c0 : index + %10 = arith.select %9, %8, %c0 : index + %11 = fir.load %1#0 : !fir.ref + %12 = fir.convert %11 : (i32) -> index + %13 = arith.cmpi sgt, %12, %c0 : index + %14 = arith.select %13, %12, %c0 : index + %15 = fir.shape %10, %14 : (index, index) -> !fir.shape<2> + %16:2 = hlfir.declare %3(%15) typeparams %6 dummy_scope %0 {uniq_name = "_QFeoshift15cEarray"} : (!fir.ref>>, !fir.shape<2>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %17:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %18 = fir.convert %17#0 : (!fir.ref>) -> !fir.ref>> + %19 = fir.load %1#0 : !fir.ref + %20 = arith.cmpi sgt, %19, %c0_i32 : i32 + %21 = arith.select %20, %19, %c0_i32 : i32 + %22 = fir.load %1#0 : !fir.ref + %23 = fir.convert %22 : (i32) -> index + %24 = arith.cmpi sgt, %23, %c0 : index + %25 = arith.select %24, %23, %c0 : index + %26 = fir.shape %25 : (index) -> !fir.shape<1> + %27:2 = hlfir.declare %18(%26) typeparams %21 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift15cEboundary"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %28 = fir.is_present %27#0 : (!fir.box>>) -> i1 + %29 = fir.shape %25 : (index) -> !fir.shape<1> + %30 = fir.embox %27#1(%29) typeparams %21 : (!fir.ref>>, !fir.shape<1>, i32) -> !fir.box>> + %31 = fir.absent !fir.box>> + %32 = arith.select %28, %30, %31 : !fir.box>> + %33 = hlfir.eoshift %16#0 %c2_i32 boundary %32 : (!fir.box>>, i32, !fir.box>>) -> !hlfir.expr> + hlfir.assign %33 to %16#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %33 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift15c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<1> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant false +// CHECK: %[[VAL_3:.*]] = arith.constant true +// CHECK: %[[VAL_4:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 +// CHECK: %[[VAL_7:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_7]] {uniq_name = "_QFeoshift15cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_9:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_12:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_6]] : i32 +// CHECK: %[[VAL_13:.*]] = arith.select %[[VAL_12]], %[[VAL_11]], %[[VAL_6]] : i32 +// CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i32) -> index +// CHECK: %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_5]] : index +// CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_16]], %[[VAL_15]], %[[VAL_5]] : index +// CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (i32) -> index +// CHECK: %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_19]], %[[VAL_5]] : index +// CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_19]], %[[VAL_5]] : index +// CHECK: %[[VAL_22:.*]] = fir.shape %[[VAL_17]], %[[VAL_21]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_23:.*]]:2 = hlfir.declare %[[VAL_10]](%[[VAL_22]]) typeparams %[[VAL_13]] dummy_scope %[[VAL_7]] {uniq_name = "_QFeoshift15cEarray"} : (!fir.ref>>, !fir.shape<2>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_24:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_27:.*]] = arith.cmpi sgt, %[[VAL_26]], %[[VAL_6]] : i32 +// CHECK: %[[VAL_28:.*]] = arith.select %[[VAL_27]], %[[VAL_26]], %[[VAL_6]] : i32 +// CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref +// CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (i32) -> index +// CHECK: %[[VAL_31:.*]] = arith.cmpi sgt, %[[VAL_30]], %[[VAL_5]] : index +// CHECK: %[[VAL_32:.*]] = arith.select %[[VAL_31]], %[[VAL_30]], %[[VAL_5]] : index +// CHECK: %[[VAL_33:.*]] = fir.shape %[[VAL_32]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_34:.*]]:2 = hlfir.declare %[[VAL_25]](%[[VAL_33]]) typeparams %[[VAL_28]] dummy_scope %[[VAL_7]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift15cEboundary"} : (!fir.ref>>, !fir.shape<1>, i32, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_35:.*]] = fir.is_present %[[VAL_34]]#0 : (!fir.box>>) -> i1 +// CHECK: %[[VAL_36:.*]] = fir.shape %[[VAL_32]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_37:.*]] = fir.embox %[[VAL_34]]#1(%[[VAL_36]]) typeparams %[[VAL_28]] : (!fir.ref>>, !fir.shape<1>, i32) -> !fir.box>> +// CHECK: %[[VAL_38:.*]] = fir.absent !fir.box>> +// CHECK: %[[VAL_39:.*]] = arith.select %[[VAL_35]], %[[VAL_37]], %[[VAL_38]] : !fir.box>> +// CHECK: %[[VAL_40:.*]] = fir.convert %[[VAL_17]] : (index) -> i64 +// CHECK: %[[VAL_41:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64 +// CHECK: %[[VAL_42:.*]] = fir.alloca !fir.char<1,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_43:.*]] = fir.emboxchar %[[VAL_42]], %[[VAL_5]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_44:.*]] = fir.is_present %[[VAL_39]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_45:.*]] = arith.select %[[VAL_44]], %[[VAL_2]], %[[VAL_3]] : i1 +// CHECK: %[[VAL_46:.*]] = hlfir.elemental %[[VAL_22]] typeparams %[[VAL_13]] unordered : (!fir.shape<2>, i32) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_47:.*]]: index, %[[VAL_48:.*]]: index): +// CHECK: %[[VAL_49:.*]] = fir.if %[[VAL_45]] -> (!fir.boxchar<1>) { +// CHECK: fir.result %[[VAL_43]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: %[[VAL_50:.*]] = fir.box_elesize %[[VAL_39]] : (!fir.box>>) -> index +// CHECK: %[[VAL_51:.*]]:3 = fir.box_dims %[[VAL_39]], %[[VAL_5]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_52:.*]] = arith.subi %[[VAL_51]]#0, %[[VAL_1]] overflow : index +// CHECK: %[[VAL_53:.*]] = arith.addi %[[VAL_48]], %[[VAL_52]] overflow : index +// CHECK: %[[VAL_54:.*]] = hlfir.designate %[[VAL_39]] (%[[VAL_53]]) typeparams %[[VAL_50]] : (!fir.box>>, index, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_54]] : !fir.boxchar<1> +// CHECK: } +// CHECK: %[[VAL_55:.*]] = fir.convert %[[VAL_47]] : (index) -> i64 +// CHECK: %[[VAL_56:.*]] = arith.addi %[[VAL_55]], %[[VAL_41]] overflow : i64 +// CHECK: %[[VAL_57:.*]] = arith.cmpi sge, %[[VAL_56]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_58:.*]] = arith.cmpi sle, %[[VAL_56]], %[[VAL_40]] : i64 +// CHECK: %[[VAL_59:.*]] = arith.andi %[[VAL_57]], %[[VAL_58]] : i1 +// CHECK: %[[VAL_60:.*]] = fir.if %[[VAL_59]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_61:.*]] = fir.convert %[[VAL_56]] : (i64) -> index +// CHECK: %[[VAL_62:.*]] = hlfir.designate %[[VAL_23]]#0 (%[[VAL_61]], %[[VAL_48]]) typeparams %[[VAL_13]] : (!fir.box>>, index, index, i32) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_62]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_49]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_60]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_46]] to %[[VAL_23]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_46]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! Test contiguous 1D array with the array optional boundary. +// ! CHARACTER with assumed length. +// subroutine eoshift16c(n, array, boundary) +// integer :: n +// character(*,1) :: array(n,n) +// character(*,1), optional :: boundary(n) +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift16c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}, %arg2: !fir.boxchar<1> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift16cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = arith.cmpi sgt, %5, %c0 : index + %7 = arith.select %6, %5, %c0 : index + %8 = fir.load %1#0 : !fir.ref + %9 = fir.convert %8 : (i32) -> index + %10 = arith.cmpi sgt, %9, %c0 : index + %11 = arith.select %10, %9, %c0 : index + %12 = fir.shape %7, %11 : (index, index) -> !fir.shape<2> + %13:2 = hlfir.declare %3(%12) typeparams %2#1 dummy_scope %0 {uniq_name = "_QFeoshift16cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %14:2 = fir.unboxchar %arg2 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %15 = fir.convert %14#0 : (!fir.ref>) -> !fir.ref>> + %16 = fir.load %1#0 : !fir.ref + %17 = fir.convert %16 : (i32) -> index + %18 = arith.cmpi sgt, %17, %c0 : index + %19 = arith.select %18, %17, %c0 : index + %20 = fir.shape %19 : (index) -> !fir.shape<1> + %21:2 = hlfir.declare %15(%20) typeparams %14#1 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift16cEboundary"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %22 = fir.is_present %21#0 : (!fir.box>>) -> i1 + %23 = fir.shape %19 : (index) -> !fir.shape<1> + %24 = fir.embox %21#1(%23) typeparams %14#1 : (!fir.ref>>, !fir.shape<1>, index) -> !fir.box>> + %25 = fir.absent !fir.box>> + %26 = arith.select %22, %24, %25 : !fir.box>> + %27 = hlfir.eoshift %13#0 %c2_i32 boundary %26 : (!fir.box>>, i32, !fir.box>>) -> !hlfir.expr> + hlfir.assign %27 to %13#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %27 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift16c( +// CHECK-SAME: %[[ARG0:.*]]: !fir.ref {fir.bindc_name = "n"}, +// CHECK-SAME: %[[ARG1:.*]]: !fir.boxchar<1> {fir.bindc_name = "array"}, +// CHECK-SAME: %[[ARG2:.*]]: !fir.boxchar<1> {fir.bindc_name = "boundary", fir.optional}) { +// CHECK: %[[VAL_0:.*]] = arith.constant 1 : i64 +// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index +// CHECK: %[[VAL_2:.*]] = arith.constant false +// CHECK: %[[VAL_3:.*]] = arith.constant true +// CHECK: %[[VAL_4:.*]] = arith.constant 2 : i32 +// CHECK: %[[VAL_5:.*]] = arith.constant 0 : index +// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope +// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_6]] {uniq_name = "_QFeoshift16cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +// CHECK: %[[VAL_8:.*]]:2 = fir.unboxchar %[[ARG1]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref +// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i32) -> index +// CHECK: %[[VAL_12:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_5]] : index +// CHECK: %[[VAL_13:.*]] = arith.select %[[VAL_12]], %[[VAL_11]], %[[VAL_5]] : index +// CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref +// CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i32) -> index +// CHECK: %[[VAL_16:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_5]] : index +// CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_16]], %[[VAL_15]], %[[VAL_5]] : index +// CHECK: %[[VAL_18:.*]] = fir.shape %[[VAL_13]], %[[VAL_17]] : (index, index) -> !fir.shape<2> +// CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_9]](%[[VAL_18]]) typeparams %[[VAL_8]]#1 dummy_scope %[[VAL_6]] {uniq_name = "_QFeoshift16cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_20:.*]]:2 = fir.unboxchar %[[ARG2]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +// CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]]#0 : (!fir.ref>) -> !fir.ref>> +// CHECK: %[[VAL_22:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref +// CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22]] : (i32) -> index +// CHECK: %[[VAL_24:.*]] = arith.cmpi sgt, %[[VAL_23]], %[[VAL_5]] : index +// CHECK: %[[VAL_25:.*]] = arith.select %[[VAL_24]], %[[VAL_23]], %[[VAL_5]] : index +// CHECK: %[[VAL_26:.*]] = fir.shape %[[VAL_25]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_21]](%[[VAL_26]]) typeparams %[[VAL_20]]#1 dummy_scope %[[VAL_6]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift16cEboundary"} : (!fir.ref>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) +// CHECK: %[[VAL_28:.*]] = fir.is_present %[[VAL_27]]#0 : (!fir.box>>) -> i1 +// CHECK: %[[VAL_29:.*]] = fir.shape %[[VAL_25]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_30:.*]] = fir.embox %[[VAL_27]]#1(%[[VAL_29]]) typeparams %[[VAL_20]]#1 : (!fir.ref>>, !fir.shape<1>, index) -> !fir.box>> +// CHECK: %[[VAL_31:.*]] = fir.absent !fir.box>> +// CHECK: %[[VAL_32:.*]] = arith.select %[[VAL_28]], %[[VAL_30]], %[[VAL_31]] : !fir.box>> +// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_13]] : (index) -> i64 +// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_4]] : (i32) -> i64 +// CHECK: %[[VAL_35:.*]] = fir.alloca !fir.char<1,0> {bindc_name = ".chrtmp"} +// CHECK: %[[VAL_36:.*]] = fir.emboxchar %[[VAL_35]], %[[VAL_5]] : (!fir.ref>, index) -> !fir.boxchar<1> +// CHECK: %[[VAL_37:.*]] = fir.is_present %[[VAL_32]] : (!fir.box>>) -> i1 +// CHECK: %[[VAL_38:.*]] = arith.select %[[VAL_37]], %[[VAL_2]], %[[VAL_3]] : i1 +// CHECK: %[[VAL_39:.*]] = hlfir.elemental %[[VAL_18]] typeparams %[[VAL_8]]#1 unordered : (!fir.shape<2>, index) -> !hlfir.expr> { +// CHECK: ^bb0(%[[VAL_40:.*]]: index, %[[VAL_41:.*]]: index): +// CHECK: %[[VAL_42:.*]] = fir.if %[[VAL_38]] -> (!fir.boxchar<1>) { +// CHECK: fir.result %[[VAL_36]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: %[[VAL_43:.*]] = fir.box_elesize %[[VAL_32]] : (!fir.box>>) -> index +// CHECK: %[[VAL_44:.*]]:3 = fir.box_dims %[[VAL_32]], %[[VAL_5]] : (!fir.box>>, index) -> (index, index, index) +// CHECK: %[[VAL_45:.*]] = arith.subi %[[VAL_44]]#0, %[[VAL_1]] overflow : index +// CHECK: %[[VAL_46:.*]] = arith.addi %[[VAL_41]], %[[VAL_45]] overflow : index +// CHECK: %[[VAL_47:.*]] = hlfir.designate %[[VAL_32]] (%[[VAL_46]]) typeparams %[[VAL_43]] : (!fir.box>>, index, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_47]] : !fir.boxchar<1> +// CHECK: } +// CHECK: %[[VAL_48:.*]] = fir.convert %[[VAL_40]] : (index) -> i64 +// CHECK: %[[VAL_49:.*]] = arith.addi %[[VAL_48]], %[[VAL_34]] overflow : i64 +// CHECK: %[[VAL_50:.*]] = arith.cmpi sge, %[[VAL_49]], %[[VAL_0]] : i64 +// CHECK: %[[VAL_51:.*]] = arith.cmpi sle, %[[VAL_49]], %[[VAL_33]] : i64 +// CHECK: %[[VAL_52:.*]] = arith.andi %[[VAL_50]], %[[VAL_51]] : i1 +// CHECK: %[[VAL_53:.*]] = fir.if %[[VAL_52]] -> (!fir.boxchar<1>) { +// CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_49]] : (i64) -> index +// CHECK: %[[VAL_55:.*]] = hlfir.designate %[[VAL_19]]#0 (%[[VAL_54]], %[[VAL_41]]) typeparams %[[VAL_8]]#1 : (!fir.box>>, index, index, index) -> !fir.boxchar<1> +// CHECK: fir.result %[[VAL_55]] : !fir.boxchar<1> +// CHECK: } else { +// CHECK: fir.result %[[VAL_42]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.yield_element %[[VAL_53]] : !fir.boxchar<1> +// CHECK: } +// CHECK: hlfir.assign %[[VAL_39]] to %[[VAL_19]]#0 : !hlfir.expr>, !fir.box>> +// CHECK: hlfir.destroy %[[VAL_39]] : !hlfir.expr> +// CHECK: return +// CHECK: } + +// ! TODO: ARRAY or/and BOUNDARY are expressions of CHARACTER type. +// ! Test contiguous 1D array with the array expression boundary. +// ! CHARACTER with constant length. +// subroutine eoshift17c(n, array) +// interface +// function charc_boundary(n) +// integer :: n +// character(10,1) :: charc_boundary(n) +// end function +// end interface +// integer :: n +// character(10,1) :: array(n,n) +// array = EOSHIFT(array//array, 2, charc_boundary(n)) +// end subroutine +func.func @_QPeoshift17c(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.boxchar<1> {fir.bindc_name = "array"}) { + %c20 = arith.constant 20 : index + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %c10 = arith.constant 10 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift17cEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = fir.unboxchar %arg1 : (!fir.boxchar<1>) -> (!fir.ref>, index) + %3 = fir.convert %2#0 : (!fir.ref>) -> !fir.ref>> + %4 = fir.load %1#0 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = arith.cmpi sgt, %5, %c0 : index + %7 = arith.select %6, %5, %c0 : index + %8 = fir.load %1#0 : !fir.ref + %9 = fir.convert %8 : (i32) -> index + %10 = arith.cmpi sgt, %9, %c0 : index + %11 = arith.select %10, %9, %c0 : index + %12 = fir.shape %7, %11 : (index, index) -> !fir.shape<2> + %13:2 = hlfir.declare %3(%12) typeparams %c10 dummy_scope %0 {uniq_name = "_QFeoshift17cEarray"} : (!fir.ref>>, !fir.shape<2>, index, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %14 = hlfir.elemental %12 typeparams %c20 unordered : (!fir.shape<2>, index) -> !hlfir.expr> { + ^bb0(%arg2: index, %arg3: index): + %23 = hlfir.designate %13#0 (%arg2, %arg3) typeparams %c10 : (!fir.box>>, index, index, index) -> !fir.ref> + %24 = hlfir.designate %13#0 (%arg2, %arg3) typeparams %c10 : (!fir.box>>, index, index, index) -> !fir.ref> + %25 = hlfir.concat %23, %24 len %c20 : (!fir.ref>, !fir.ref>, index) -> !hlfir.expr> + hlfir.yield_element %25 : !hlfir.expr> + } + %15:2 = hlfir.declare %1#0 {uniq_name = "_QFeoshift17cFcharc_boundaryEn"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %16 = fir.load %15#0 : !fir.ref + %17 = fir.convert %16 : (i32) -> index + %18 = arith.cmpi sgt, %17, %c0 : index + %19 = arith.select %18, %17, %c0 : index + %20 = fir.shape %19 : (index) -> !fir.shape<1> + %21 = hlfir.eval_in_mem shape %20 typeparams %c10 : (!fir.shape<1>, index) -> !hlfir.expr> { + ^bb0(%arg2: !fir.ref>>): + %23 = fir.call @_QPcharc_boundary(%1#0) fastmath : (!fir.ref) -> !fir.array> + fir.save_result %23 to %arg2(%20) typeparams %c10 : !fir.array>, !fir.ref>>, !fir.shape<1>, index + } + %22 = hlfir.eoshift %14 %c2_i32 boundary %21 : (!hlfir.expr>, i32, !hlfir.expr>) -> !hlfir.expr> + hlfir.assign %22 to %13#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %22 : !hlfir.expr> + hlfir.destroy %21 : !hlfir.expr> + hlfir.destroy %14 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift17c( +// CHECK: hlfir.eoshift + +// ! Tests for derived types. + +// ! TODO: selecting between !fir.ref> and !fir.box> +// ! is not implemented. +// ! Test contiguous 1D array with the scalar optional boundary. +// subroutine eoshift1d(n, array, boundary) +// use eoshift_types +// integer :: n +// type(t) :: array(n) +// type(t), optional :: boundary +// array = EOSHIFT(array, 2, boundary) +// end subroutine +func.func @_QPeoshift1d(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir.ref>> {fir.bindc_name = "array"}, %arg2: !fir.ref> {fir.bindc_name = "boundary", fir.optional}) { + %c2_i32 = arith.constant 2 : i32 + %c0 = arith.constant 0 : index + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift1dEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg2 dummy_scope %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift1dEboundary"} : (!fir.ref>, !fir.dscope) -> (!fir.ref>, !fir.ref>) + %3 = fir.load %1#0 : !fir.ref + %4 = fir.convert %3 : (i32) -> index + %5 = arith.cmpi sgt, %4, %c0 : index + %6 = arith.select %5, %4, %c0 : index + %7 = fir.shape %6 : (index) -> !fir.shape<1> + %8:2 = hlfir.declare %arg1(%7) dummy_scope %0 {uniq_name = "_QFeoshift1dEarray"} : (!fir.ref>>, !fir.shape<1>, !fir.dscope) -> (!fir.box>>, !fir.ref>>) + %9 = fir.is_present %2#0 : (!fir.ref>) -> i1 + %10 = fir.embox %2#0 : (!fir.ref>) -> !fir.box> + %11 = fir.absent !fir.box> + %12 = arith.select %9, %10, %11 : !fir.box> + %13 = hlfir.eoshift %8#0 %c2_i32 boundary %12 : (!fir.box>>, i32, !fir.box>) -> !hlfir.expr> + hlfir.assign %13 to %8#0 : !hlfir.expr>, !fir.box>> + hlfir.destroy %13 : !hlfir.expr> + return +} +// CHECK-LABEL: func.func @_QPeoshift1d( +// CHECK: hlfir.eoshift