[flang-commits] [flang] 4840e75 - [flang] Lower shift intrinsics
Valentin Clement via flang-commits
flang-commits at lists.llvm.org
Wed Mar 16 09:17:05 PDT 2022
Author: Valentin Clement
Date: 2022-03-16T17:16:46+01:00
New Revision: 4840e7505d1a4caa7fe80f7adf530d2c9e8e91eb
URL: https://github.com/llvm/llvm-project/commit/4840e7505d1a4caa7fe80f7adf530d2c9e8e91eb
DIFF: https://github.com/llvm/llvm-project/commit/4840e7505d1a4caa7fe80f7adf530d2c9e8e91eb.diff
LOG: [flang] Lower shift intrinsics
This patch adds lowering for shift intrinsics:
- `ishft`
- `eoshift`
- `ishftc`
- `cshift`
This patch is part of the upstreaming effort from fir-dev branch.
Reviewed By: PeteSteinfeld
Differential Revision: https://reviews.llvm.org/D121808
Co-authored-by: V Donaldson <vdonaldson at nvidia.com>
Co-authored-by: Jean Perier <jperier at nvidia.com>
Co-authored-by: Peter Steinfeld <psteinfeld at nvidia.com>
Co-authored-by: AlexisPerry <aperry at lanl.gov>
Added:
flang/test/Lower/Intrinsics/eoshift.f90
flang/test/Lower/Intrinsics/ishft.f90
flang/test/Lower/Intrinsics/ishftc.f90
Modified:
flang/lib/Lower/IntrinsicCall.cpp
Removed:
################################################################################
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>);
fir::ExtendedValue genChar(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
- mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
- fir::ExtendedValue genDotProduct(mlir::Type,
- llvm::ArrayRef<fir::ExtendedValue>);
template <mlir::arith::CmpIPredicate pred>
fir::ExtendedValue genCharacterCompare(mlir::Type,
llvm::ArrayRef<fir::ExtendedValue>);
void genCpuTime(llvm::ArrayRef<fir::ExtendedValue>);
+ fir::ExtendedValue genCshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
void genDateAndTime(llvm::ArrayRef<fir::ExtendedValue>);
+ mlir::Value genDim(mlir::Type, llvm::ArrayRef<mlir::Value>);
+ fir::ExtendedValue genDotProduct(mlir::Type,
+ llvm::ArrayRef<fir::ExtendedValue>);
+ fir::ExtendedValue genEoshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
template <Extremum, ExtremumBehavior>
mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
/// 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>);
mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genIbset(mlir::Type, llvm::ArrayRef<mlir::Value>);
+ mlir::Value genIshft(mlir::Type, llvm::ArrayRef<mlir::Value>);
+ mlir::Value genIshftc(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genLen(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
@@ -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<fir::ExtendedValue> args) {
builder.create<fir::StoreOp>(loc, res2, *arg);
}
+// CSHIFT
+fir::ExtendedValue
+IntrinsicLibrary::genCshift(mlir::Type resultType,
+ llvm::ArrayRef<fir::ExtendedValue> 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<fir::LoadOp>(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<fir::ExtendedValue> 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<fir::ExtendedValue> 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<fir::AbsentOp>(
+ 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<fir::LoadOp>(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<mlir::Value> args) {
@@ -1816,6 +1924,99 @@ mlir::Value IntrinsicLibrary::genIbset(mlir::Type resultType,
return builder.create<mlir::arith::OrIOp>(loc, args[0], mask);
}
+// ISHFT
+mlir::Value IntrinsicLibrary::genIshft(mlir::Type resultType,
+ llvm::ArrayRef<mlir::Value> 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<mlir::IntegerType>().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<mlir::arith::ShLIOp>(loc, args[0], absShift);
+ auto right = builder.create<mlir::arith::ShRUIOp>(loc, args[0], absShift);
+ auto shiftIsLarge = builder.create<mlir::arith::CmpIOp>(
+ loc, mlir::arith::CmpIPredicate::sge, absShift, bitSize);
+ auto shiftIsNegative = builder.create<mlir::arith::CmpIOp>(
+ loc, mlir::arith::CmpIPredicate::slt, shift, zero);
+ auto sel =
+ builder.create<mlir::arith::SelectOp>(loc, shiftIsNegative, right, left);
+ return builder.create<mlir::arith::SelectOp>(loc, shiftIsLarge, zero, sel);
+}
+
+// ISHFTC
+mlir::Value IntrinsicLibrary::genIshftc(mlir::Type resultType,
+ llvm::ArrayRef<mlir::Value> 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<mlir::IntegerType>().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<mlir::arith::SubIOp>(loc, size, absShift);
+ auto shiftIsZero = builder.create<mlir::arith::CmpIOp>(
+ loc, mlir::arith::CmpIPredicate::eq, shift, zero);
+ auto shiftEqualsSize = builder.create<mlir::arith::CmpIOp>(
+ loc, mlir::arith::CmpIPredicate::eq, absShift, size);
+ auto shiftIsNop =
+ builder.create<mlir::arith::OrIOp>(loc, shiftIsZero, shiftEqualsSize);
+ auto shiftIsPositive = builder.create<mlir::arith::CmpIOp>(
+ loc, mlir::arith::CmpIPredicate::sgt, shift, zero);
+ auto leftSize = builder.create<mlir::arith::SelectOp>(loc, shiftIsPositive,
+ absShift, elseSize);
+ auto rightSize = builder.create<mlir::arith::SelectOp>(loc, shiftIsPositive,
+ elseSize, absShift);
+ auto hasUnchanged = builder.create<mlir::arith::CmpIOp>(
+ loc, mlir::arith::CmpIPredicate::ne, size, bitSize);
+ auto unchangedTmp1 = builder.create<mlir::arith::ShRUIOp>(loc, I, size);
+ auto unchangedTmp2 =
+ builder.create<mlir::arith::ShLIOp>(loc, unchangedTmp1, size);
+ auto unchanged = builder.create<mlir::arith::SelectOp>(loc, hasUnchanged,
+ unchangedTmp2, zero);
+ auto leftMaskShift =
+ builder.create<mlir::arith::SubIOp>(loc, bitSize, leftSize);
+ auto leftMask =
+ builder.create<mlir::arith::ShRUIOp>(loc, ones, leftMaskShift);
+ auto leftTmp = builder.create<mlir::arith::ShRUIOp>(loc, I, rightSize);
+ auto left = builder.create<mlir::arith::AndIOp>(loc, leftTmp, leftMask);
+ auto rightMaskShift =
+ builder.create<mlir::arith::SubIOp>(loc, bitSize, rightSize);
+ auto rightMask =
+ builder.create<mlir::arith::ShRUIOp>(loc, ones, rightMaskShift);
+ auto rightTmp = builder.create<mlir::arith::AndIOp>(loc, I, rightMask);
+ auto right = builder.create<mlir::arith::ShLIOp>(loc, rightTmp, leftSize);
+ auto resTmp = builder.create<mlir::arith::OrIOp>(loc, unchanged, left);
+ auto res = builder.create<mlir::arith::OrIOp>(loc, resTmp, right);
+ return builder.create<mlir::arith::SelectOp>(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<!fir.heap<!fir.array<?x!fir.logical<4>>>>
+ ! 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.array<3x!fir.logical<4>>>, !fir.shape<1>) -> !fir.array<3x!fir.logical<4>>
+ ! CHECK: %[[arr:.*]] = fir.embox %arg0({{.*}}) : (!fir.ref<!fir.array<3x!fir.logical<4>>>, !fir.shape<1>) -> !fir.box<!fir.array<3x!fir.logical<4>>>
+ ! CHECK: %[[bits:.*]] = fir.zero_bits !fir.heap<!fir.array<?x!fir.logical<4>>>
+ ! CHECK: %[[init:.*]] = fir.embox %[[bits]]({{.*}}) : (!fir.heap<!fir.array<?x!fir.logical<4>>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>
+ ! CHECK: fir.store %[[init]] to %[[resBox]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
+ ! CHECK: %[[boundBox:.*]] = fir.absent !fir.box<none>
+ ! CHECK: %[[shift:.*]] = fir.load %arg1 : !fir.ref<i32>
+
+ res = eoshift(arr, shift)
+
+ ! CHECK: %[[resIRBox:.*]] = fir.convert %[[resBox]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>) -> !fir.ref<!fir.box<none>>
+ ! CHECK: %[[arrBox:.*]] = fir.convert %[[arr]] : (!fir.box<!fir.array<3x!fir.logical<4>>>) -> !fir.box<none>
+ ! CHECK: %[[shiftBox:.*]] = fir.convert %[[shift]] : (i32) -> i64
+ ! CHECK: %[[tmp:.*]] = fir.call @_FortranAEoshiftVector(%[[resIRBox]], %[[arrBox]], %[[shiftBox]], %[[boundBox]], {{.*}}, {{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, i64, !fir.box<none>, !fir.ref<i8>, i32) -> none
+ ! CHECK: fir.array_merge_store %[[resLoad]], {{.*}} to %[[res]] : !fir.array<3x!fir.logical<4>>, !fir.array<3x!fir.logical<4>>, !fir.ref<!fir.array<3x!fir.logical<4>>>
+ 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<!fir.heap<!fir.array<?x?xi32>>>
+ ! CHECK: %[[res:.*]] = fir.alloca !fir.array<3x3xi32> {bindc_name = "res", uniq_name = "_QFeoshift_test2Eres"}
+ !CHECK: %[[resLoad:.*]] = fir.array_load %[[res]]({{.*}}) : (!fir.ref<!fir.array<3x3xi32>>, !fir.shape<2>) -> !fir.array<3x3xi32>
+
+ res = eoshift(arr, shift, bound, dim)
+
+ ! CHECK: %[[arr:.*]] = fir.embox %arg0({{.*}}) : (!fir.ref<!fir.array<3x3xi32>>, !fir.shape<2>) -> !fir.box<!fir.array<3x3xi32>>
+ ! CHECK: %[[boundBox:.*]] = fir.embox %arg2 : (!fir.ref<i32>) -> !fir.box<i32>
+ ! CHECK: %[[dim:.*]] = fir.load %arg3 : !fir.ref<i32>
+ ! CHECK: %[[shiftBox:.*]] = fir.embox %arg1({{.*}}) : (!fir.ref<!fir.array<3xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<3xi32>>
+ ! CHECK: %[[resIRBox:.*]] = fir.convert %[[resBox]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?xi32>>>>) -> !fir.ref<!fir.box<none>>
+ ! CHECK: %[[arrBox:.*]] = fir.convert %[[arr]] : (!fir.box<!fir.array<3x3xi32>>) -> !fir.box<none>
+ ! CHECK: %[[shiftBoxNone:.*]] = fir.convert %[[shiftBox]] : (!fir.box<!fir.array<3xi32>>) -> !fir.box<none>
+ ! CHECK: %[[boundBoxNone:.*]] = fir.convert %[[boundBox]] : (!fir.box<i32>) -> !fir.box<none>
+
+ ! CHECK: %[[tmp:.*]] = fir.call @_FortranAEoshift(%[[resIRBox]], %[[arrBox]], %[[shiftBoxNone]], %[[boundBoxNone]], %[[dim]], {{.*}}, {{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.box<none>, !fir.box<none>, i32, !fir.ref<i8>, i32) -> none
+ ! CHECK: fir.array_merge_store %[[resLoad]], {{.*}} to %[[res]] : !fir.array<3x3xi32>, !fir.array<3x3xi32>, !fir.ref<!fir.array<3x3xi32>>
+ 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<!fir.heap<!fir.array<?x?x!fir.char<1,4>>>>
+ ! CHECK: %[[arr:.*]]:2 = fir.unboxchar %arg0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
+ ! CHECK: %[[array:.*]] = fir.convert %[[arr]]#0 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<!fir.array<3x3x!fir.char<1,4>>>
+ ! 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.array<3x3x!fir.char<1,4>>>, !fir.shape<2>) -> !fir.array<3x3x!fir.char<1,4>>
+ ! CHECK: %[[arrayBox:.*]] = fir.embox %[[array]]({{.*}}) : (!fir.ref<!fir.array<3x3x!fir.char<1,4>>>, !fir.shape<2>) -> !fir.box<!fir.array<3x3x!fir.char<1,4>>>
+ ! CHECK: %[[dim:.*]] = fir.load %arg2 : !fir.ref<i32>
+
+ res = eoshift(arr, SHIFT=shift, DIM=dim)
+
+ ! CHECK: %[[boundBox:.*]] = fir.absent !fir.box<none>
+ ! CHECK: %[[shiftBox:.*]] = fir.embox %arg1 : (!fir.ref<i32>) -> !fir.box<i32>
+ ! CHECK: %[[resIRBox:.*]] = fir.convert %[[resBox]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.char<1,4>>>>>) -> !fir.ref<!fir.box<none>>
+ ! CHECK: %[[arrayBoxNone:.*]] = fir.convert %[[arrayBox]] : (!fir.box<!fir.array<3x3x!fir.char<1,4>>>) -> !fir.box<none>
+ ! CHECK: %[[shiftBoxNone:.*]] = fir.convert %[[shiftBox]] : (!fir.box<i32>) -> !fir.box<none>
+ ! CHECK: %[[tmp:.*]] = fir.call @_FortranAEoshift(%[[resIRBox]], %[[arrayBoxNone]], %[[shiftBoxNone]], %[[boundBox]], %[[dim]], {{.*}}, {{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.box<none>, !fir.box<none>, i32, !fir.ref<i8>, 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<!fir.array<3x3x!fir.char<1,4>>>
+ end subroutine eoshift_test3
+
+ ! CHECK-LABEL: func @_QPeoshift_test_dynamic_optional(
+ ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?x?xi32>>
+ ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i32>
+ ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<!fir.array<10xi32>>
+ 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<!fir.array<10xi32>>) -> i1
+ ! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
+ ! CHECK: %[[VAL_7:.*]] = fir.embox %[[VAL_2]](%[[VAL_6]]) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<10xi32>>
+ ! CHECK: %[[VAL_8:.*]] = fir.absent !fir.box<!fir.array<10xi32>>
+ ! CHECK: %[[VAL_9:.*]] = arith.select %[[VAL_5]], %[[VAL_7]], %[[VAL_8]] : !fir.box<!fir.array<10xi32>>
+ ! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_9]] : (!fir.box<!fir.array<10xi32>>) -> !fir.box<none>
+ ! CHECK: fir.call @_FortranAEoshift(%{{.*}}, %{{.*}}, %{{.*}}, %[[VAL_21]], %{{.*}}, %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.box<none>, !fir.box<none>, i32, !fir.ref<i8>, 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<i32>
+ ! CHECK-DAG: %[[j:.*]] = fir.load %arg1 : !fir.ref<i32>
+ ! 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<i32>
+ ! CHECK: %[[VAL_17:.*]] = fir.load %[[result]] : !fir.ref<i32>
+ ! 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<i32>
+ ! CHECK-DAG: %[[j:.*]] = fir.load %arg1 : !fir.ref<i32>
+ ! CHECK-DAG: %[[k:.*]] = fir.load %arg2 : !fir.ref<i32>
+ ! 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<i32>
+ ! CHECK: %[[VAL_36:.*]] = fir.load %[[result]] : !fir.ref<i32>
+ ! 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<i32> {fir.bindc_name = "i"},
+ ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i32> {fir.bindc_name = "shift"},
+ ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<i32> {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<i32>
+ ! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_1]] : !fir.ref<i32>
+ ! CHECK: %[[VAL_10:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref<i32>) -> i1
+ ! CHECK: %[[VAL_11:.*]] = fir.if %[[VAL_10]] -> (i32) {
+ ! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
+ ! 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.array<?xi32>> {fir.bindc_name = "i"},
+ ! CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "shift"},
+ ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<i32> {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<?xi32>>) -> !fir.array<?xi32>
+ ! CHECK: %[[VAL_11:.*]] = fir.array_load %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.array<?xi32>
+ ! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.ref<i32>) -> i1
+ ! CHECK: fir.do_loop %[[VAL_20:.*]] = %{{.*}} to %{{.*}}
+ ! CHECK: %[[VAL_22:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_20]] : (!fir.array<?xi32>, index) -> i32
+ ! CHECK: %[[VAL_23:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_20]] : (!fir.array<?xi32>, index) -> i32
+ ! CHECK: %[[VAL_24:.*]] = fir.if %[[VAL_12]] -> (i32) {
+ ! CHECK: %[[VAL_25:.*]] = fir.load %[[VAL_2]] : !fir.ref<i32>
+ ! 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.array<?xi32>> {fir.bindc_name = "i"},
+ ! CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "shift"},
+ ! CHECK-SAME: %[[VAL_2:.*]]: !fir.box<!fir.array<?xi32>> {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<?xi32>>) -> !fir.array<?xi32>
+ ! CHECK: %[[VAL_11:.*]] = fir.array_load %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.array<?xi32>
+ ! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_2]] : (!fir.box<!fir.array<?xi32>>) -> i1
+ ! CHECK: %[[VAL_17:.*]] = arith.select %[[VAL_12]], %[[VAL_2]], %{{.*}} : !fir.box<!fir.array<?xi32>>
+ ! CHECK: %[[VAL_18:.*]] = fir.array_load %[[VAL_17]] {fir.optional} : (!fir.box<!fir.array<?xi32>>) -> !fir.array<?xi32>
+ ! CHECK: fir.do_loop %[[VAL_26:.*]] = %{{.*}} to %{{.*}}
+ ! CHECK: %[[VAL_28:.*]] = fir.array_fetch %[[VAL_10]], %[[VAL_26]] : (!fir.array<?xi32>, index) -> i32
+ ! CHECK: %[[VAL_29:.*]] = fir.array_fetch %[[VAL_11]], %[[VAL_26]] : (!fir.array<?xi32>, index) -> i32
+ ! CHECK: %[[VAL_30:.*]] = fir.if %[[VAL_12]] -> (i32) {
+ ! CHECK: %[[VAL_31:.*]] = fir.array_fetch %[[VAL_18]], %[[VAL_26]] : (!fir.array<?xi32>, 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
More information about the flang-commits
mailing list