diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp index b1d31d7927da8..856e8716a5767 100644 --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -29,6 +29,7 @@ #include "flang/Optimizer/Builder/Runtime/Numeric.h" #include "flang/Optimizer/Builder/Runtime/RTBuilder.h" #include "flang/Optimizer/Builder/Runtime/Reduction.h" +#include "flang/Optimizer/Builder/Runtime/Transformational.h" #include "flang/Optimizer/Dialect/FIROpsSupport.h" #include "flang/Optimizer/Support/FatalError.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" @@ -441,14 +442,16 @@ struct IntrinsicLibrary { llvm::ArrayRef); fir::ExtendedValue genChar(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genCount(mlir::Type, llvm::ArrayRef); - mlir::Value genDim(mlir::Type, llvm::ArrayRef); - fir::ExtendedValue genDotProduct(mlir::Type, - llvm::ArrayRef); template fir::ExtendedValue genCharacterCompare(mlir::Type, llvm::ArrayRef); void genCpuTime(llvm::ArrayRef); + fir::ExtendedValue genCshift(mlir::Type, llvm::ArrayRef); void genDateAndTime(llvm::ArrayRef); + mlir::Value genDim(mlir::Type, llvm::ArrayRef); + fir::ExtendedValue genDotProduct(mlir::Type, + llvm::ArrayRef); + fir::ExtendedValue genEoshift(mlir::Type, llvm::ArrayRef); template mlir::Value genExtremum(mlir::Type, llvm::ArrayRef); /// Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments @@ -456,6 +459,8 @@ struct IntrinsicLibrary { mlir::Value genIand(mlir::Type, llvm::ArrayRef); mlir::Value genIbits(mlir::Type, llvm::ArrayRef); mlir::Value genIbset(mlir::Type, llvm::ArrayRef); + mlir::Value genIshft(mlir::Type, llvm::ArrayRef); + mlir::Value genIshftc(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLen(mlir::Type, llvm::ArrayRef); @@ -604,6 +609,10 @@ static constexpr IntrinsicHandler handlers[]{ &I::genCpuTime, {{{"time", asAddr}}}, /*isElemental=*/false}, + {"cshift", + &I::genCshift, + {{{"array", asAddr}, {"shift", asAddr}, {"dim", asValue}}}, + /*isElemental=*/false}, {"date_and_time", &I::genDateAndTime, {{{"date", asAddr, handleDynamicOptional}, @@ -616,9 +625,18 @@ static constexpr IntrinsicHandler handlers[]{ &I::genDotProduct, {{{"vector_a", asBox}, {"vector_b", asBox}}}, /*isElemental=*/false}, + {"eoshift", + &I::genEoshift, + {{{"array", asBox}, + {"shift", asAddr}, + {"boundary", asBox, handleDynamicOptional}, + {"dim", asValue}}}, + /*isElemental=*/false}, {"iand", &I::genIand}, {"ibits", &I::genIbits}, {"ibset", &I::genIbset}, + {"ishft", &I::genIshft}, + {"ishftc", &I::genIshftc}, {"len", &I::genLen, {{{"string", asInquired}, {"kind", asValue}}}, @@ -1724,6 +1742,47 @@ void IntrinsicLibrary::genCpuTime(llvm::ArrayRef args) { builder.create(loc, res2, *arg); } +// CSHIFT +fir::ExtendedValue +IntrinsicLibrary::genCshift(mlir::Type resultType, + llvm::ArrayRef args) { + assert(args.size() == 3); + + // Handle required ARRAY argument + fir::BoxValue arrayBox = builder.createBox(loc, args[0]); + mlir::Value array = fir::getBase(arrayBox); + unsigned arrayRank = arrayBox.rank(); + + // Create mutable fir.box to be passed to the runtime for the result. + mlir::Type resultArrayType = builder.getVarLenSeqTy(resultType, arrayRank); + fir::MutableBoxValue resultMutableBox = + fir::factory::createTempMutableBox(builder, loc, resultArrayType); + mlir::Value resultIrBox = + fir::factory::getMutableIRBox(builder, loc, resultMutableBox); + + if (arrayRank == 1) { + // Vector case + // Handle required SHIFT argument as a scalar + const mlir::Value *shiftAddr = args[1].getUnboxed(); + assert(shiftAddr && "nonscalar CSHIFT argument"); + auto shift = builder.create(loc, *shiftAddr); + + fir::runtime::genCshiftVector(builder, loc, resultIrBox, array, shift); + } else { + // Non-vector case + // Handle required SHIFT argument as an array + mlir::Value shift = builder.createBox(loc, args[1]); + + // Handle optional DIM argument + mlir::Value dim = + isAbsent(args[2]) + ? builder.createIntegerConstant(loc, builder.getIndexType(), 1) + : fir::getBase(args[2]); + fir::runtime::genCshift(builder, loc, resultIrBox, array, shift, dim); + } + return readAndAddCleanUp(resultMutableBox, resultType, "CSHIFT"); +} + // DATE_AND_TIME void IntrinsicLibrary::genDateAndTime(llvm::ArrayRef args) { assert(args.size() == 4 && "date_and_time has 4 args"); @@ -1768,6 +1827,55 @@ IntrinsicLibrary::genDotProduct(mlir::Type resultType, stmtCtx, args); } +// EOSHIFT +fir::ExtendedValue +IntrinsicLibrary::genEoshift(mlir::Type resultType, + llvm::ArrayRef args) { + assert(args.size() == 4); + + // Handle required ARRAY argument + fir::BoxValue arrayBox = builder.createBox(loc, args[0]); + mlir::Value array = fir::getBase(arrayBox); + unsigned arrayRank = arrayBox.rank(); + + // Create mutable fir.box to be passed to the runtime for the result. + mlir::Type resultArrayType = builder.getVarLenSeqTy(resultType, arrayRank); + fir::MutableBoxValue resultMutableBox = + fir::factory::createTempMutableBox(builder, loc, resultArrayType); + mlir::Value resultIrBox = + fir::factory::getMutableIRBox(builder, loc, resultMutableBox); + + // Handle optional BOUNDARY argument + mlir::Value boundary = + isAbsent(args[2]) ? builder.create( + loc, fir::BoxType::get(builder.getNoneType())) + : builder.createBox(loc, args[2]); + + if (arrayRank == 1) { + // Vector case + // Handle required SHIFT argument as a scalar + const mlir::Value *shiftAddr = args[1].getUnboxed(); + assert(shiftAddr && "nonscalar EOSHIFT SHIFT argument"); + auto shift = builder.create(loc, *shiftAddr); + fir::runtime::genEoshiftVector(builder, loc, resultIrBox, array, shift, + boundary); + } else { + // Non-vector case + // Handle required SHIFT argument as an array + mlir::Value shift = builder.createBox(loc, args[1]); + + // Handle optional DIM argument + mlir::Value dim = + isAbsent(args[3]) + ? builder.createIntegerConstant(loc, builder.getIndexType(), 1) + : fir::getBase(args[3]); + fir::runtime::genEoshift(builder, loc, resultIrBox, array, shift, boundary, + dim); + } + return readAndAddCleanUp(resultMutableBox, resultType, + "unexpected result for EOSHIFT"); +} + // IAND mlir::Value IntrinsicLibrary::genIand(mlir::Type resultType, llvm::ArrayRef args) { @@ -1816,6 +1924,99 @@ mlir::Value IntrinsicLibrary::genIbset(mlir::Type resultType, return builder.create(loc, args[0], mask); } +// ISHFT +mlir::Value IntrinsicLibrary::genIshft(mlir::Type resultType, + llvm::ArrayRef args) { + // A conformant ISHFT(I,SHIFT) call satisfies: + // abs(SHIFT) <= BIT_SIZE(I) + // Return: abs(SHIFT) >= BIT_SIZE(I) + // ? 0 + // : SHIFT < 0 + // ? I >> abs(SHIFT) + // : I << abs(SHIFT) + assert(args.size() == 2); + mlir::Value bitSize = builder.createIntegerConstant( + loc, resultType, resultType.cast().getWidth()); + mlir::Value zero = builder.createIntegerConstant(loc, resultType, 0); + mlir::Value shift = builder.createConvert(loc, resultType, args[1]); + mlir::Value absShift = genAbs(resultType, {shift}); + auto left = builder.create(loc, args[0], absShift); + auto right = builder.create(loc, args[0], absShift); + auto shiftIsLarge = builder.create( + loc, mlir::arith::CmpIPredicate::sge, absShift, bitSize); + auto shiftIsNegative = builder.create( + loc, mlir::arith::CmpIPredicate::slt, shift, zero); + auto sel = + builder.create(loc, shiftIsNegative, right, left); + return builder.create(loc, shiftIsLarge, zero, sel); +} + +// ISHFTC +mlir::Value IntrinsicLibrary::genIshftc(mlir::Type resultType, + llvm::ArrayRef args) { + // A conformant ISHFTC(I,SHIFT,SIZE) call satisfies: + // SIZE > 0 + // SIZE <= BIT_SIZE(I) + // abs(SHIFT) <= SIZE + // if SHIFT > 0 + // leftSize = abs(SHIFT) + // rightSize = SIZE - abs(SHIFT) + // else [if SHIFT < 0] + // leftSize = SIZE - abs(SHIFT) + // rightSize = abs(SHIFT) + // unchanged = SIZE == BIT_SIZE(I) ? 0 : (I >> SIZE) << SIZE + // leftMaskShift = BIT_SIZE(I) - leftSize + // rightMaskShift = BIT_SIZE(I) - rightSize + // left = (I >> rightSize) & (-1 >> leftMaskShift) + // right = (I & (-1 >> rightMaskShift)) << leftSize + // Return: SHIFT == 0 || SIZE == abs(SHIFT) ? I : (unchanged | left | right) + assert(args.size() == 3); + mlir::Value bitSize = builder.createIntegerConstant( + loc, resultType, resultType.cast().getWidth()); + mlir::Value I = args[0]; + mlir::Value shift = builder.createConvert(loc, resultType, args[1]); + mlir::Value size = + args[2] ? builder.createConvert(loc, resultType, args[2]) : bitSize; + mlir::Value zero = builder.createIntegerConstant(loc, resultType, 0); + mlir::Value ones = builder.createIntegerConstant(loc, resultType, -1); + mlir::Value absShift = genAbs(resultType, {shift}); + auto elseSize = builder.create(loc, size, absShift); + auto shiftIsZero = builder.create( + loc, mlir::arith::CmpIPredicate::eq, shift, zero); + auto shiftEqualsSize = builder.create( + loc, mlir::arith::CmpIPredicate::eq, absShift, size); + auto shiftIsNop = + builder.create(loc, shiftIsZero, shiftEqualsSize); + auto shiftIsPositive = builder.create( + loc, mlir::arith::CmpIPredicate::sgt, shift, zero); + auto leftSize = builder.create(loc, shiftIsPositive, + absShift, elseSize); + auto rightSize = builder.create(loc, shiftIsPositive, + elseSize, absShift); + auto hasUnchanged = builder.create( + loc, mlir::arith::CmpIPredicate::ne, size, bitSize); + auto unchangedTmp1 = builder.create(loc, I, size); + auto unchangedTmp2 = + builder.create(loc, unchangedTmp1, size); + auto unchanged = builder.create(loc, hasUnchanged, + unchangedTmp2, zero); + auto leftMaskShift = + builder.create(loc, bitSize, leftSize); + auto leftMask = + builder.create(loc, ones, leftMaskShift); + auto leftTmp = builder.create(loc, I, rightSize); + auto left = builder.create(loc, leftTmp, leftMask); + auto rightMaskShift = + builder.create(loc, bitSize, rightSize); + auto rightMask = + builder.create(loc, ones, rightMaskShift); + auto rightTmp = builder.create(loc, I, rightMask); + auto right = builder.create(loc, rightTmp, leftSize); + auto resTmp = builder.create(loc, unchanged, left); + auto res = builder.create(loc, resTmp, right); + return builder.create(loc, shiftIsNop, I, res); +} + // LEN // Note that this is only used for an unrestricted intrinsic LEN call. // Other uses of LEN are rewritten as descriptor inquiries by the front-end. diff --git a/flang/test/Lower/Intrinsics/eoshift.f90 b/flang/test/Lower/Intrinsics/eoshift.f90 new file mode 100644 index 0000000000000..4354dd9718247 --- /dev/null +++ b/flang/test/Lower/Intrinsics/eoshift.f90 @@ -0,0 +1,94 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: eoshift_test1 +subroutine eoshift_test1(arr, shift) + logical, dimension(3) :: arr, res + integer :: shift + ! CHECK: %[[resBox:.*]] = fir.alloca !fir.box>>> + ! CHECK: %[[res:.*]] = fir.alloca !fir.array<3x!fir.logical<4>> {bindc_name = "res", uniq_name = "_QFeoshift_test1Eres"} + ! CHECK: %[[resLoad:.*]] = fir.array_load %[[res]]({{.*}}) : (!fir.ref>>, !fir.shape<1>) -> !fir.array<3x!fir.logical<4>> + ! CHECK: %[[arr:.*]] = fir.embox %arg0({{.*}}) : (!fir.ref>>, !fir.shape<1>) -> !fir.box>> + ! CHECK: %[[bits:.*]] = fir.zero_bits !fir.heap>> + ! CHECK: %[[init:.*]] = fir.embox %[[bits]]({{.*}}) : (!fir.heap>>, !fir.shape<1>) -> !fir.box>>> + ! CHECK: fir.store %[[init]] to %[[resBox]] : !fir.ref>>>> + ! CHECK: %[[boundBox:.*]] = fir.absent !fir.box + ! CHECK: %[[shift:.*]] = fir.load %arg1 : !fir.ref + + res = eoshift(arr, shift) + + ! CHECK: %[[resIRBox:.*]] = fir.convert %[[resBox]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: %[[arrBox:.*]] = fir.convert %[[arr]] : (!fir.box>>) -> !fir.box + ! CHECK: %[[shiftBox:.*]] = fir.convert %[[shift]] : (i32) -> i64 + ! CHECK: %[[tmp:.*]] = fir.call @_FortranAEoshiftVector(%[[resIRBox]], %[[arrBox]], %[[shiftBox]], %[[boundBox]], {{.*}}, {{.*}}) : (!fir.ref>, !fir.box, i64, !fir.box, !fir.ref, i32) -> none + ! CHECK: fir.array_merge_store %[[resLoad]], {{.*}} to %[[res]] : !fir.array<3x!fir.logical<4>>, !fir.array<3x!fir.logical<4>>, !fir.ref>> + end subroutine eoshift_test1 + + ! CHECK-LABEL: eoshift_test2 + subroutine eoshift_test2(arr, shift, bound, dim) + integer, dimension(3,3) :: arr, res + integer, dimension(3) :: shift + integer :: bound, dim + ! CHECK: %[[resBox:.*]] = fir.alloca !fir.box>> + ! CHECK: %[[res:.*]] = fir.alloca !fir.array<3x3xi32> {bindc_name = "res", uniq_name = "_QFeoshift_test2Eres"} + !CHECK: %[[resLoad:.*]] = fir.array_load %[[res]]({{.*}}) : (!fir.ref>, !fir.shape<2>) -> !fir.array<3x3xi32> + + res = eoshift(arr, shift, bound, dim) + + ! CHECK: %[[arr:.*]] = fir.embox %arg0({{.*}}) : (!fir.ref>, !fir.shape<2>) -> !fir.box> + ! CHECK: %[[boundBox:.*]] = fir.embox %arg2 : (!fir.ref) -> !fir.box + ! CHECK: %[[dim:.*]] = fir.load %arg3 : !fir.ref + ! CHECK: %[[shiftBox:.*]] = fir.embox %arg1({{.*}}) : (!fir.ref>, !fir.shape<1>) -> !fir.box> + ! CHECK: %[[resIRBox:.*]] = fir.convert %[[resBox]] : (!fir.ref>>>) -> !fir.ref> + ! CHECK: %[[arrBox:.*]] = fir.convert %[[arr]] : (!fir.box>) -> !fir.box + ! CHECK: %[[shiftBoxNone:.*]] = fir.convert %[[shiftBox]] : (!fir.box>) -> !fir.box + ! CHECK: %[[boundBoxNone:.*]] = fir.convert %[[boundBox]] : (!fir.box) -> !fir.box + + ! CHECK: %[[tmp:.*]] = fir.call @_FortranAEoshift(%[[resIRBox]], %[[arrBox]], %[[shiftBoxNone]], %[[boundBoxNone]], %[[dim]], {{.*}}, {{.*}}) : (!fir.ref>, !fir.box, !fir.box, !fir.box, i32, !fir.ref, i32) -> none + ! CHECK: fir.array_merge_store %[[resLoad]], {{.*}} to %[[res]] : !fir.array<3x3xi32>, !fir.array<3x3xi32>, !fir.ref> + end subroutine eoshift_test2 + + ! CHECK-LABEL: eoshift_test3 + subroutine eoshift_test3(arr, shift, dim) + character(4), dimension(3,3) :: arr, res + integer :: shift, dim + + ! CHECK: %[[resBox:.*]] = fir.alloca !fir.box>>> + ! CHECK: %[[arr:.*]]:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref>, index) + ! CHECK: %[[array:.*]] = fir.convert %[[arr]]#0 : (!fir.ref>) -> !fir.ref>> + ! CHECK: %[[res:.*]] = fir.alloca !fir.array<3x3x!fir.char<1,4>> {bindc_name = "res", uniq_name = "_QFeoshift_test3Eres"} + ! CHECK: %[[resLoad:.*]] = fir.array_load %[[res]]({{.*}}) : (!fir.ref>>, !fir.shape<2>) -> !fir.array<3x3x!fir.char<1,4>> + ! CHECK: %[[arrayBox:.*]] = fir.embox %[[array]]({{.*}}) : (!fir.ref>>, !fir.shape<2>) -> !fir.box>> + ! CHECK: %[[dim:.*]] = fir.load %arg2 : !fir.ref + + res = eoshift(arr, SHIFT=shift, DIM=dim) + + ! CHECK: %[[boundBox:.*]] = fir.absent !fir.box + ! CHECK: %[[shiftBox:.*]] = fir.embox %arg1 : (!fir.ref) -> !fir.box + ! CHECK: %[[resIRBox:.*]] = fir.convert %[[resBox]] : (!fir.ref>>>>) -> !fir.ref> + ! CHECK: %[[arrayBoxNone:.*]] = fir.convert %[[arrayBox]] : (!fir.box>>) -> !fir.box + ! CHECK: %[[shiftBoxNone:.*]] = fir.convert %[[shiftBox]] : (!fir.box) -> !fir.box + ! CHECK: %[[tmp:.*]] = fir.call @_FortranAEoshift(%[[resIRBox]], %[[arrayBoxNone]], %[[shiftBoxNone]], %[[boundBox]], %[[dim]], {{.*}}, {{.*}}) : (!fir.ref>, !fir.box, !fir.box, !fir.box, i32, !fir.ref, i32) -> none + ! CHECK: fir.array_merge_store %[[resLoad]], {{.*}} to %[[res]] : !fir.array<3x3x!fir.char<1,4>>, !fir.array<3x3x!fir.char<1,4>>, !fir.ref>> + end subroutine eoshift_test3 + + ! CHECK-LABEL: func @_QPeoshift_test_dynamic_optional( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref> + subroutine eoshift_test_dynamic_optional(array, shift, boundary) + type t + integer :: i + end type + integer :: array(:, :) + integer :: shift + integer, optional :: boundary(10) + call next(eoshift(array, shift, boundary)) + ! CHECK: %[[VAL_4:.*]] = arith.constant 10 : index + ! CHECK: %[[VAL_5:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1> + ! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_2]](%[[VAL_6]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> + ! CHECK: %[[VAL_8:.*]] = fir.absent !fir.box> + ! CHECK: %[[VAL_9:.*]] = arith.select %[[VAL_5]], %[[VAL_7]], %[[VAL_8]] : !fir.box> + ! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_9]] : (!fir.box>) -> !fir.box + ! CHECK: fir.call @_FortranAEoshift(%{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_21]], %{{.*}}, %{{.*}}, %{{.*}}) : (!fir.ref>, !fir.box, !fir.box, !fir.box, i32, !fir.ref, i32) -> none + end subroutine diff --git a/flang/test/Lower/Intrinsics/ishft.f90 b/flang/test/Lower/Intrinsics/ishft.f90 new file mode 100644 index 0000000000000..ea9fd268d7bfe --- /dev/null +++ b/flang/test/Lower/Intrinsics/ishft.f90 @@ -0,0 +1,24 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: ishft_test +function ishft_test(i, j) + ! CHECK-DAG: %[[result:.*]] = fir.alloca i32 {bindc_name = "ishft_test" + ! CHECK-DAG: %[[i:.*]] = fir.load %arg0 : !fir.ref + ! CHECK-DAG: %[[j:.*]] = fir.load %arg1 : !fir.ref + ! CHECK-DAG: %[[VAL_5:.*]] = arith.constant 32 : i32 + ! CHECK-DAG: %[[VAL_6:.*]] = arith.constant 0 : i32 + ! CHECK-DAG: %[[VAL_7:.*]] = arith.constant 31 : i32 + ! CHECK: %[[VAL_8:.*]] = arith.shrsi %[[j]], %[[VAL_7]] : i32 + ! CHECK: %[[VAL_9:.*]] = arith.xori %[[j]], %[[VAL_8]] : i32 + ! CHECK: %[[VAL_10:.*]] = arith.subi %[[VAL_9]], %[[VAL_8]] : i32 + ! CHECK: %[[VAL_11:.*]] = arith.shli %[[i]], %[[VAL_10]] : i32 + ! CHECK: %[[VAL_12:.*]] = arith.shrui %[[i]], %[[VAL_10]] : i32 + ! CHECK: %[[VAL_13:.*]] = arith.cmpi sge, %[[VAL_10]], %[[VAL_5]] : i32 + ! CHECK: %[[VAL_14:.*]] = arith.cmpi slt, %[[j]], %[[VAL_6]] : i32 + ! CHECK: %[[VAL_15:.*]] = arith.select %[[VAL_14]], %[[VAL_12]], %[[VAL_11]] : i32 + ! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_13]], %[[VAL_6]], %[[VAL_15]] : i32 + ! CHECK: fir.store %[[VAL_16]] to %[[result]] : !fir.ref + ! CHECK: %[[VAL_17:.*]] = fir.load %[[result]] : !fir.ref + ! CHECK: return %[[VAL_17]] : i32 + ishft_test = ishft(i, j) + end diff --git a/flang/test/Lower/Intrinsics/ishftc.f90 b/flang/test/Lower/Intrinsics/ishftc.f90 new file mode 100644 index 0000000000000..4a7f8e9561f07 --- /dev/null +++ b/flang/test/Lower/Intrinsics/ishftc.f90 @@ -0,0 +1,138 @@ +! RUN: bbc -emit-fir %s -o - | FileCheck %s + +! CHECK-LABEL: ishftc_test +function ishftc_test(i, j, k) + ! CHECK-DAG: %[[result:.*]] = fir.alloca i32 {bindc_name = "ishftc_test" + ! CHECK-DAG: %[[i:.*]] = fir.load %arg0 : !fir.ref + ! CHECK-DAG: %[[j:.*]] = fir.load %arg1 : !fir.ref + ! CHECK-DAG: %[[k:.*]] = fir.load %arg2 : !fir.ref + ! CHECK-DAG: %[[VAL_7:.*]] = arith.constant 32 : i32 + ! CHECK-DAG: %[[VAL_8:.*]] = arith.constant 0 : i32 + ! CHECK-DAG: %[[VAL_9:.*]] = arith.constant -1 : i32 + ! CHECK-DAG: %[[VAL_10:.*]] = arith.constant 31 : i32 + ! CHECK: %[[VAL_11:.*]] = arith.shrsi %[[j]], %[[VAL_10]] : i32 + ! CHECK: %[[VAL_12:.*]] = arith.xori %[[j]], %[[VAL_11]] : i32 + ! CHECK: %[[VAL_13:.*]] = arith.subi %[[VAL_12]], %[[VAL_11]] : i32 + ! CHECK: %[[VAL_14:.*]] = arith.subi %[[k]], %[[VAL_13]] : i32 + ! CHECK: %[[VAL_15:.*]] = arith.cmpi eq, %[[j]], %[[VAL_8]] : i32 + ! CHECK: %[[VAL_16:.*]] = arith.cmpi eq, %[[VAL_13]], %[[k]] : i32 + ! CHECK: %[[VAL_17:.*]] = arith.ori %[[VAL_15]], %[[VAL_16]] : i1 + ! CHECK: %[[VAL_18:.*]] = arith.cmpi sgt, %[[j]], %[[VAL_8]] : i32 + ! CHECK: %[[VAL_19:.*]] = arith.select %[[VAL_18]], %[[VAL_13]], %[[VAL_14]] : i32 + ! CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_18]], %[[VAL_14]], %[[VAL_13]] : i32 + ! CHECK: %[[VAL_21:.*]] = arith.cmpi ne, %[[k]], %[[VAL_7]] : i32 + ! CHECK: %[[VAL_22:.*]] = arith.shrui %[[i]], %[[k]] : i32 + ! CHECK: %[[VAL_23:.*]] = arith.shli %[[VAL_22]], %[[k]] : i32 + ! CHECK: %[[VAL_24:.*]] = arith.select %[[VAL_21]], %[[VAL_23]], %[[VAL_8]] : i32 + ! CHECK: %[[VAL_25:.*]] = arith.subi %[[VAL_7]], %[[VAL_19]] : i32 + ! CHECK: %[[VAL_26:.*]] = arith.shrui %[[VAL_9]], %[[VAL_25]] : i32 + ! CHECK: %[[VAL_27:.*]] = arith.shrui %[[i]], %[[VAL_20]] : i32 + ! CHECK: %[[VAL_28:.*]] = arith.andi %[[VAL_27]], %[[VAL_26]] : i32 + ! CHECK: %[[VAL_29:.*]] = arith.subi %[[VAL_7]], %[[VAL_20]] : i32 + ! CHECK: %[[VAL_30:.*]] = arith.shrui %[[VAL_9]], %[[VAL_29]] : i32 + ! CHECK: %[[VAL_31:.*]] = arith.andi %[[i]], %[[VAL_30]] : i32 + ! CHECK: %[[VAL_32:.*]] = arith.shli %[[VAL_31]], %[[VAL_19]] : i32 + ! CHECK: %[[VAL_33:.*]] = arith.ori %[[VAL_24]], %[[VAL_28]] : i32 + ! CHECK: %[[VAL_34:.*]] = arith.ori %[[VAL_33]], %[[VAL_32]] : i32 + ! CHECK: %[[VAL_35:.*]] = arith.select %[[VAL_17]], %[[i]], %[[VAL_34]] : i32 + ! CHECK: fir.store %[[VAL_35]] to %[[result]] : !fir.ref + ! CHECK: %[[VAL_36:.*]] = fir.load %[[result]] : !fir.ref + ! CHECK: return %[[VAL_36]] : i32 + ishftc_test = ishftc(i, j, k) + end + + ! Test cases where the size argument presence can only be know at runtime + module test_ishftc + contains + ! CHECK-LABEL: func @_QMtest_ishftcPdyn_optional_scalar( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref {fir.bindc_name = "i"}, + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "shift"}, + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "size", fir.optional}) { + subroutine dyn_optional_scalar(i, shift, size) + integer, optional :: size + integer :: i, shift + print *, ishftc(i, shift, size) + ! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_0]] : !fir.ref + ! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_1]] : !fir.ref + ! CHECK: %[[VAL_10:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref) -> i1 + ! CHECK: %[[VAL_11:.*]] = fir.if %[[VAL_10]] -> (i32) { + ! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_2]] : !fir.ref + ! CHECK: fir.result %[[VAL_12]] : i32 + ! CHECK: } else { + ! CHECK: %[[VAL_13:.*]] = arith.constant 32 : i32 + ! CHECK: fir.result %[[VAL_13]] : i32 + ! CHECK: } + ! CHECK: %[[VAL_17:.*]] = arith.constant 31 : i32 + ! CHECK: %[[VAL_18:.*]] = arith.shrsi %[[VAL_9]], %[[VAL_17]] : i32 + ! CHECK: %[[VAL_19:.*]] = arith.xori %[[VAL_9]], %[[VAL_18]] : i32 + ! CHECK: %[[VAL_20:.*]] = arith.subi %[[VAL_19]], %[[VAL_18]] : i32 + ! CHECK: %[[VAL_21:.*]] = arith.subi %[[VAL_11]], %[[VAL_20]] : i32 + ! ... as in non optional case + end subroutine + + ! CHECK-LABEL: func @_QMtest_ishftcPdyn_optional_array_scalar( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "i"}, + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "shift"}, + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref {fir.bindc_name = "size", fir.optional}) { + subroutine dyn_optional_array_scalar(i, shift, size) + integer, optional :: size + integer :: i(:), shift(:) + ! CHECK: %[[VAL_10:.*]] = fir.array_load %[[VAL_0]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_11:.*]] = fir.array_load %[[VAL_1]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref) -> i1 + ! CHECK: fir.do_loop %[[VAL_20:.*]] = %{{.*}} to %{{.*}} + ! CHECK: %[[VAL_22:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_20]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_23:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_20]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_24:.*]] = fir.if %[[VAL_12]] -> (i32) { + ! CHECK: %[[VAL_25:.*]] = fir.load %[[VAL_2]] : !fir.ref + ! CHECK: fir.result %[[VAL_25]] : i32 + ! CHECK: } else { + ! CHECK: %[[VAL_26:.*]] = arith.constant 32 : i32 + ! CHECK: fir.result %[[VAL_26]] : i32 + ! CHECK: } + ! ... as in non optional case + ! CHECK: } + print *, ishftc(i, shift, size) + end subroutine + + ! CHECK-LABEL: func @_QMtest_ishftcPdyn_optional_array( + ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box> {fir.bindc_name = "i"}, + ! CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "shift"}, + ! CHECK-SAME: %[[VAL_2:.*]]: !fir.box> {fir.bindc_name = "size", fir.optional}) { + subroutine dyn_optional_array(i, shift, size) + integer, optional :: size(:) + integer :: i(:), shift(:) + ! CHECK: %[[VAL_10:.*]] = fir.array_load %[[VAL_0]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_11:.*]] = fir.array_load %[[VAL_1]] : (!fir.box>) -> !fir.array + ! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.box>) -> i1 + ! CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_12]], %[[VAL_2]], %{{.*}} : !fir.box> + ! CHECK: %[[VAL_18:.*]] = fir.array_load %[[VAL_17]] {fir.optional} : (!fir.box>) -> !fir.array + ! CHECK: fir.do_loop %[[VAL_26:.*]] = %{{.*}} to %{{.*}} + ! CHECK: %[[VAL_28:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_26]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_29:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_26]] : (!fir.array, index) -> i32 + ! CHECK: %[[VAL_30:.*]] = fir.if %[[VAL_12]] -> (i32) { + ! CHECK: %[[VAL_31:.*]] = fir.array_fetch %[[VAL_18]], %[[VAL_26]] : (!fir.array, index) -> i32 + ! CHECK: fir.result %[[VAL_31]] : i32 + ! CHECK: } else { + ! CHECK: %[[VAL_32:.*]] = arith.constant 32 : i32 + ! CHECK: fir.result %[[VAL_32]] : i32 + ! CHECK: } + ! ... as in non optional case + ! CHECK: } + print *, ishftc(i, shift, size) + end subroutine + end module + + use test_ishftc + integer :: i(4) = [333, 334, 335, 336] + integer :: shift(4) = [2, 1, -1, -2] + integer :: size(4) = [2, 4, 8, 16] + call dyn_optional_scalar(i(1), shift(1)) + call dyn_optional_scalar(i(1), shift(1), size(1)) + + call dyn_optional_array_scalar(i, shift) + call dyn_optional_array_scalar(i, shift, size(1)) + + call dyn_optional_array(i, shift) + call dyn_optional_array(i, shift, size) + end