[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