[flang][lowering] Add support for lowering of the `ibits` intrinsic

This patch adds support for lowering of the `ibits` intrinsic from Fortran
to the FIR dialect of MLIR.

This is part of the upstreaming effort from the `fir-dev` branch in [1].

[1] https://github.com/flang-compiler/f18-llvm-project

Differential Revision: https://reviews.llvm.org/D121693

Co-authored-by: Jean Perier <jperier@nvidia.com>
Co-authored-by: Valentin Clement <clementval@gmail.com>
Co-authored-by: V Donaldson <vdonaldson@nvidia.com>
This commit is contained in:
Andrzej Warzynski 2022-03-15 13:16:47 +00:00
parent b783e5c203
commit be6e84e252
2 changed files with 52 additions and 0 deletions

View File

@ -275,6 +275,7 @@ struct IntrinsicLibrary {
/// Lowering for the IAND intrinsic. The IAND intrinsic expects two arguments
/// in the llvm::ArrayRef.
mlir::Value genIand(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genIbits(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genSize(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genSum(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
@ -387,6 +388,7 @@ static constexpr IntrinsicHandler handlers[]{
{{{"vector_a", asBox}, {"vector_b", asBox}}},
/*isElemental=*/false},
{"iand", &I::genIand},
{"ibits", &I::genIbits},
{"min", &I::genExtremum<Extremum::Min, ExtremumBehavior::MinMaxss>},
{"sum",
&I::genSum,
@ -1295,6 +1297,33 @@ mlir::Value IntrinsicLibrary::genIand(mlir::Type resultType,
return builder.create<mlir::arith::AndIOp>(loc, args[0], args[1]);
}
// IBITS
mlir::Value IntrinsicLibrary::genIbits(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
// A conformant IBITS(I,POS,LEN) call satisfies:
// POS >= 0
// LEN >= 0
// POS + LEN <= BIT_SIZE(I)
// Return: LEN == 0 ? 0 : (I >> POS) & (-1 >> (BIT_SIZE(I) - LEN))
// For a conformant call, implementing (I >> POS) with a signed or an
// unsigned shift produces the same result. For a nonconformant call,
// the two choices may produce different results.
assert(args.size() == 3);
mlir::Value pos = builder.createConvert(loc, resultType, args[1]);
mlir::Value len = builder.createConvert(loc, resultType, args[2]);
mlir::Value bitSize = builder.createIntegerConstant(
loc, resultType, resultType.cast<mlir::IntegerType>().getWidth());
auto shiftCount = builder.create<mlir::arith::SubIOp>(loc, bitSize, len);
mlir::Value zero = builder.createIntegerConstant(loc, resultType, 0);
mlir::Value ones = builder.createIntegerConstant(loc, resultType, -1);
auto mask = builder.create<mlir::arith::ShRUIOp>(loc, ones, shiftCount);
auto res1 = builder.create<mlir::arith::ShRSIOp>(loc, args[0], pos);
auto res2 = builder.create<mlir::arith::AndIOp>(loc, res1, mask);
auto lenIsZero = builder.create<mlir::arith::CmpIOp>(
loc, mlir::arith::CmpIPredicate::eq, len, zero);
return builder.create<mlir::arith::SelectOp>(loc, lenIsZero, zero, res2);
}
// Compare two FIR values and return boolean result as i1.
template <Extremum extremum, ExtremumBehavior behavior>
static mlir::Value createExtremumCompare(mlir::Location loc,

View File

@ -0,0 +1,23 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s
! CHECK-LABEL: ibits_test
function ibits_test(i, j, k)
! CHECK-DAG: %[[result:.*]] = fir.alloca i32 {bindc_name = "ibits_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.subi %[[VAL_7]], %[[k]] : i32
! CHECK-DAG: %[[VAL_9:.*]] = arith.constant 0 : i32
! CHECK-DAG: %[[VAL_10:.*]] = arith.constant -1 : i32
! CHECK: %[[VAL_11:.*]] = arith.shrui %[[VAL_10]], %[[VAL_8]] : i32
! CHECK: %[[VAL_12:.*]] = arith.shrsi %[[i]], %[[j]] : i32
! CHECK: %[[VAL_13:.*]] = arith.andi %[[VAL_12]], %[[VAL_11]] : i32
! CHECK: %[[VAL_14:.*]] = arith.cmpi eq, %[[k]], %[[VAL_9]] : i32
! CHECK: %[[VAL_15:.*]] = arith.select %[[VAL_14]], %[[VAL_9]], %[[VAL_13]] : i32
! CHECK: fir.store %[[VAL_15]] to %[[result]] : !fir.ref<i32>
! CHECK: %[[VAL_16:.*]] = fir.load %[[result]] : !fir.ref<i32>
! CHECK: return %[[VAL_16]] : i32
ibits_test = ibits(i, j, k)
end