diff --git a/flang/lib/Lower/HlfirIntrinsics.cpp b/flang/lib/Lower/HlfirIntrinsics.cpp index 6e1d06a25924..39595d6f519a 100644 --- a/flang/lib/Lower/HlfirIntrinsics.cpp +++ b/flang/lib/Lower/HlfirIntrinsics.cpp @@ -170,6 +170,17 @@ protected: mlir::Type stmtResultType) override; }; +class HlfirEOShiftLowering : public HlfirTransformationalIntrinsic { +public: + using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic; + +protected: + mlir::Value + lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals, + const fir::IntrinsicArgumentLoweringRules *argLowering, + mlir::Type stmtResultType) override; +}; + class HlfirReshapeLowering : public HlfirTransformationalIntrinsic { public: using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic; @@ -430,6 +441,46 @@ mlir::Value HlfirCShiftLowering::lowerImpl( return createOp(resultType, operands); } +mlir::Value HlfirEOShiftLowering::lowerImpl( + const Fortran::lower::PreparedActualArguments &loweredActuals, + const fir::IntrinsicArgumentLoweringRules *argLowering, + mlir::Type stmtResultType) { + auto operands = getOperandVector(loweredActuals, argLowering); + assert(operands.size() == 4); + mlir::Value array = operands[0]; + mlir::Value shift = operands[1]; + mlir::Value boundary = operands[2]; + mlir::Value dim = operands[3]; + // If DIM is present, then dereference it if it is a ref. + if (dim) + dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim}); + + mlir::Type resultType = computeResultType(array, stmtResultType); + + if (boundary && fir::isa_trivial(boundary.getType())) { + mlir::Type elementType = hlfir::getFortranElementType(resultType); + if (auto logicalTy = mlir::dyn_cast(elementType)) { + // Scalar logical constant boundary might be represented using i1, i2, ... + // type. We need to cast it to fir.logical type of the ARRAY/result. + if (boundary.getType() != logicalTy) + boundary = builder.createConvert(loc, logicalTy, boundary); + } else { + // When the boundary is a constant like '1u', the lowering converts + // it into a signless arith.constant value (which is a requirement + // of the Arith dialect). If the ARRAY/RESULT is also UNSIGNED, + // we have to cast the boundary to the same unsigned type. + auto resultIntTy = mlir::dyn_cast(elementType); + auto boundaryIntTy = + mlir::dyn_cast(boundary.getType()); + if (resultIntTy && boundaryIntTy && + resultIntTy.getSignedness() != boundaryIntTy.getSignedness()) + boundary = builder.createConvert(loc, resultIntTy, boundary); + } + } + + return createOp(resultType, array, shift, boundary, dim); +} + mlir::Value HlfirReshapeLowering::lowerImpl( const Fortran::lower::PreparedActualArguments &loweredActuals, const fir::IntrinsicArgumentLoweringRules *argLowering, @@ -489,6 +540,9 @@ std::optional Fortran::lower::lowerHlfirIntrinsic( if (name == "cshift") return HlfirCShiftLowering{builder, loc}.lower(loweredActuals, argLowering, stmtResultType); + if (name == "eoshift") + return HlfirEOShiftLowering{builder, loc}.lower(loweredActuals, argLowering, + stmtResultType); if (name == "reshape") return HlfirReshapeLowering{builder, loc}.lower(loweredActuals, argLowering, stmtResultType); diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index b6baefb67b4b..99533690018e 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -147,8 +147,20 @@ mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc, assert((cst >= 0 || mlir::isa(ty) || mlir::cast(ty).getWidth() <= 64) && "must use APint"); - return mlir::arith::ConstantOp::create(*this, loc, ty, - getIntegerAttr(ty, cst)); + + mlir::Type cstType = ty; + if (auto intType = mlir::dyn_cast(ty)) { + // Signed and unsigned constants must be encoded as signless + // arith.constant followed by fir.convert cast. + if (intType.isUnsigned()) + cstType = mlir::IntegerType::get(getContext(), intType.getWidth()); + else if (intType.isSigned()) + TODO(loc, "signed integer constant"); + } + + mlir::Value cstValue = mlir::arith::ConstantOp::create( + *this, loc, cstType, getIntegerAttr(cstType, cst)); + return createConvert(loc, ty, cstValue); } mlir::Value fir::FirOpBuilder::createAllOnesInteger(mlir::Location loc, diff --git a/flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir b/flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir index 88191d517c2b..d8975c974128 100644 --- a/flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir +++ b/flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir @@ -697,6 +697,33 @@ func.func @_QPeoshift7(%arg0: !fir.ref {fir.bindc_name = "n"}, %arg1: !fir. // CHECK: return // CHECK: } +// Test UNSIGNED data type. +// The default value of the BOUNDARY must be an integer 0 +// converted to ui32 type. +// subroutine eoshift8(array) +// unsigned :: array(:,:) +// array = EOSHIFT(array, shift=1, dim=2) +// end subroutine +func.func @_QPeoshift8(%arg0: !fir.box> {fir.bindc_name = "array"}) { + %c2_i32 = arith.constant 2 : i32 + %c1_i32 = arith.constant 1 : i32 + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift8Earray"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) + %2 = hlfir.eoshift %1#0 %c1_i32 dim %c2_i32 : (!fir.box>, i32, i32) -> !hlfir.expr + hlfir.assign %2 to %1#0 : !hlfir.expr, !fir.box> + hlfir.destroy %2 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @_QPeoshift8( +// CHECK-DAG: hlfir.elemental %{{.*}} unordered : (!fir.shape<2>) -> !hlfir.expr { +// CHECK-DAG: %[[VAL_24:.*]] = fir.load %{{.*}} : !fir.ref +// CHECK-DAG: fir.result %[[VAL_24]] : ui32 +// CHECK-DAG: } else { +// CHECK-DAG: fir.result %[[VAL_12:.*]] : ui32 +// CHECK-DAG: } +// CHECK-DAG: %[[VAL_12]] = fir.convert %[[VAL_1:.*]] : (i32) -> ui32 +// CHECK-DAG: %[[VAL_1]] = arith.constant 0 : i32 + // ! Tests for CHARACTER type (lowered via hlfir.elemental). // ! Test contiguous 1D array with statically absent boundary. diff --git a/flang/test/Lower/HLFIR/eoshift.f90 b/flang/test/Lower/HLFIR/eoshift.f90 new file mode 100644 index 000000000000..e7fb98c2b040 --- /dev/null +++ b/flang/test/Lower/HLFIR/eoshift.f90 @@ -0,0 +1,271 @@ +! Test lowering of EOSHIFT intrinsic to HLFIR +! RUN: bbc -emit-hlfir -o - -I nowhere %s 2>&1 | FileCheck %s + +module eoshift_types + type t + end type t +end module eoshift_types + +! 1d shift by scalar +subroutine eoshift1(a, s) + integer :: a(:), s + a = EOSHIFT(a, 2) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift1( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_5:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_6:.*]] = hlfir.eoshift %[[VAL_3]]#0 %[[VAL_5]] : (!fir.box>, i32) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_3]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_6]] : !hlfir.expr +! CHECK: return +! CHECK: } + +! 1d shift by scalar with dim +subroutine eoshift2(a, s) + integer :: a(:), s + a = EOSHIFT(a, 2, dim=1) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift2( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_5:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_6:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_7:.*]] = hlfir.eoshift %[[VAL_3]]#0 %[[VAL_5]] dim %[[VAL_6]] : (!fir.box>, i32, i32) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_7]] to %[[VAL_3]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_7]] : !hlfir.expr +! CHECK: return +! CHECK: } + +! 2d shift by scalar +subroutine eoshift3(a, s) + integer :: a(:,:), s + a = EOSHIFT(a, 2) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift3( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_5:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_6:.*]] = hlfir.eoshift %[[VAL_3]]#0 %[[VAL_5]] : (!fir.box>, i32) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_3]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_6]] : !hlfir.expr +! CHECK: return +! CHECK: } + +! 2d shift by scalar with dim +subroutine eoshift4(a, s) + integer :: a(:,:), s + a = EOSHIFT(a, 2, dim=2) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift4( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_5:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_6:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_7:.*]] = hlfir.eoshift %[[VAL_3]]#0 %[[VAL_5]] dim %[[VAL_6]] : (!fir.box>, i32, i32) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_7]] to %[[VAL_3]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_7]] : !hlfir.expr +! CHECK: return +! CHECK: } + +! 2d shift by array +subroutine eoshift5(a, s) + integer :: a(:,:), s(:) + a = EOSHIFT(a, s) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift5( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_5:.*]] = hlfir.eoshift %[[VAL_3]]#0 %[[VAL_4]]#0 : (!fir.box>, !fir.box>) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_3]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_5]] : !hlfir.expr +! CHECK: return +! CHECK: } + +! 2d shift by array expr +subroutine eoshift6(a, s) + integer :: a(:,:), s(:) + a = EOSHIFT(a, s + 1) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift6( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_5:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_6:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_7:.*]]:3 = fir.box_dims %[[VAL_4]]#0, %[[VAL_6]] : (!fir.box>, index) -> (index, index, index) +! CHECK: %[[VAL_8:.*]] = fir.shape %[[VAL_7]]#1 : (index) -> !fir.shape<1> +! CHECK: %[[VAL_9:.*]] = hlfir.elemental %[[VAL_8]] unordered : (!fir.shape<1>) -> !hlfir.expr +! CHECK: %[[VAL_14:.*]] = hlfir.eoshift %[[VAL_3]]#0 %[[VAL_9]] : (!fir.box>, !hlfir.expr) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_14]] to %[[VAL_3]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_14]] : !hlfir.expr +! CHECK: hlfir.destroy %[[VAL_9]] : !hlfir.expr +! CHECK: return +! CHECK: } + +! 1d character(10,2) shift by scalar +subroutine eoshift7(a, s) + character(10,2) :: a(:) + a = EOSHIFT(a, 2) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift7( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_6:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_7:.*]] = hlfir.eoshift %[[VAL_4]]#0 %[[VAL_6]] : (!fir.box>>, i32) -> !hlfir.expr> +! CHECK: hlfir.assign %[[VAL_7]] to %[[VAL_4]]#0 : !hlfir.expr>, !fir.box>> +! CHECK: hlfir.destroy %[[VAL_7]] : !hlfir.expr> +! CHECK: return +! CHECK: } + +! 1d character(*) shift by scalar +subroutine eoshift8(a, s) + character(*) :: a(:) + a = EOSHIFT(a, 2) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift8( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] +! CHECK: %[[VAL_5:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_6:.*]] = hlfir.eoshift %[[VAL_3]]#0 %[[VAL_5]] : (!fir.box>>, i32) -> !hlfir.expr> +! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_3]]#0 : !hlfir.expr>, !fir.box>> +! CHECK: hlfir.destroy %[[VAL_6]] : !hlfir.expr> +! CHECK: return +! CHECK: } + +! 1d type(t) shift by scalar +subroutine eoshift9(a, s) + use eoshift_types + type(t) :: a(:) + a = EOSHIFT(a, 2, boundary=t()) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift9( +! CHECK-SAME: %[[ARG0:.*]]: !fir.box>> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[ARG1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFeoshift9Ea"} : (!fir.box>>, !fir.dscope) -> (!fir.box>>, !fir.box>>) +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %[[VAL_0]] {uniq_name = "_QFeoshift9Es"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QQro._QMeoshift_typesTt.0) : !fir.ref> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQro._QMeoshift_typesTt.0"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = hlfir.eoshift %[[VAL_1]]#0 %[[VAL_3]] boundary %[[VAL_5]]#0 : (!fir.box>>, i32, !fir.ref>) -> !hlfir.expr> +! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_1]]#0 : !hlfir.expr>, !fir.box>> +! CHECK: hlfir.destroy %[[VAL_6]] : !hlfir.expr> +! CHECK: return +! CHECK: } + +! 1d class(t) shift by scalar +subroutine eoshift10(a, s) + use eoshift_types + class(t), allocatable :: a(:) + a = EOSHIFT(a, 2, boundary=t()) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift10( +! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>>> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[ARG1:.*]]: !fir.ref {fir.bindc_name = "s"}) { +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift10Ea"} : (!fir.ref>>>>, !fir.dscope) -> (!fir.ref>>>>, !fir.ref>>>>) +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %[[VAL_0]] {uniq_name = "_QFeoshift10Es"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QQro._QMeoshift_typesTt.1) : !fir.ref> +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QQro._QMeoshift_typesTt.1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>>> +! CHECK: %[[VAL_7:.*]] = hlfir.eoshift %[[VAL_6]] %[[VAL_3]] boundary %[[VAL_5]]#0 : (!fir.class>>>, i32, !fir.ref>) -> !hlfir.expr?> +! CHECK: hlfir.assign %[[VAL_7]] to %[[VAL_1]]#0 realloc : !hlfir.expr?>, !fir.ref>>>> +! CHECK: hlfir.destroy %[[VAL_7]] : !hlfir.expr?> +! CHECK: return +! CHECK: } + +! 1d shift by scalar with variable dim +subroutine eoshift11(a, s, d) + integer :: a(:), s, d + a = EOSHIFT(a, 2, dim=d) +end subroutine +! CHECK-LABEL: func.func @_QPeoshift11( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "a"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "s"}, +! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "d"}) { +! CHECK: %[[VAL_3:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift11Ea"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_2]] dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift11Ed"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %[[VAL_3]] {uniq_name = "_QFeoshift11Es"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_7:.*]] = arith.constant 2 : i32 +! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_9:.*]] = hlfir.eoshift %[[VAL_4]]#0 %[[VAL_7]] dim %[[VAL_8]] : (!fir.box>, i32, i32) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_9]] : !hlfir.expr +! CHECK: return +! CHECK: } + +subroutine eoshift12(array, shift, boundary, dim) + real :: array(:,:) + real, optional :: boundary + integer :: shift(:), dim + array = EOSHIFT(array, shift, boundary, dim) +end subroutine eoshift12 +! CHECK-LABEL: func.func @_QPeoshift12( +! CHECK-SAME: %[[ARG0:.*]]: !fir.box> {fir.bindc_name = "array"}, +! CHECK-SAME: %[[ARG1:.*]]: !fir.box> {fir.bindc_name = "shift"}, +! CHECK-SAME: %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "boundary", fir.optional}, +! CHECK-SAME: %[[ARG3:.*]]: !fir.ref {fir.bindc_name = "dim"}) { +! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFeoshift12Earray"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFeoshift12Eboundary"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[ARG3]] dummy_scope %[[VAL_0]] {uniq_name = "_QFeoshift12Edim"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %[[VAL_0]] {uniq_name = "_QFeoshift12Eshift"} : (!fir.box>, !fir.dscope) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_5:.*]] = fir.is_present %[[VAL_2]]#0 : (!fir.ref) -> i1 +! CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_2]]#0 : (!fir.ref) -> !fir.box +! CHECK: %[[VAL_7:.*]] = fir.absent !fir.box +! CHECK: %[[VAL_8:.*]] = arith.select %[[VAL_5]], %[[VAL_6]], %[[VAL_7]] : !fir.box +! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_10:.*]] = hlfir.eoshift %[[VAL_1]]#0 %[[VAL_4]]#0 boundary %[[VAL_8]] dim %[[VAL_9]] : (!fir.box>, !fir.box>, !fir.box, i32) -> !hlfir.expr +! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_1]]#0 : !hlfir.expr, !fir.box> +! CHECK: hlfir.destroy %[[VAL_10]] : !hlfir.expr +! CHECK: return +! CHECK: } + +! Test scalar logical boundary. +! CHECK-LABEL: func.func @_QPeoshift13( +subroutine eoshift13(array) + logical(1) :: array(:) + array = EOSHIFT(array, -1, .true._1) +! CHECK: %[[VAL_5:.*]] = hlfir.eoshift %{{.*}} %{{.*}} boundary %{{.*}} : (!fir.box>>, i32, !fir.logical<1>) -> !hlfir.expr> + array = EOSHIFT(array.EQV..false., -1, .true.) +! CHECK: %[[VAL_24:.*]] = hlfir.eoshift %{{.*}} %{{.*}} boundary %{{.*}} : (!hlfir.expr>, i32, !fir.logical<4>) -> !hlfir.expr> +end subroutine eoshift13 + +! Test scalar constant BOUNDARY value of UNSIGNED type. +! The BOUNDARY operand of hlfir.eoshift must have ui32 type +! (i.e. consistent with the array/result type). +! CHECK-LABEL: func.func @_QPeoshift14( +subroutine eoshift14(array) + unsigned :: array(:) + array = EOSHIFT(array, shift=1, boundary=1u) +! CHECK-DAG: %[[VAL_4:.*]] = fir.convert %[[VAL_3:.*]] : (i32) -> ui32 +! CHECK-DAG: %[[VAL_3]] = arith.constant 1 : i32 +! CHECK: %[[VAL_5:.*]] = hlfir.eoshift{{.*}}boundary %[[VAL_4]] : (!fir.box>, i32, ui32) -> !hlfir.expr +end subroutine eoshift14