diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp index e43f3a3a5fb15..f8bc373ddcb8c 100644 --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -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 genIbits(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genLbound(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genSize(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genSum(mlir::Type, llvm::ArrayRef); @@ -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}, {"sum", &I::genSum, @@ -1295,6 +1297,33 @@ mlir::Value IntrinsicLibrary::genIand(mlir::Type resultType, return builder.create(loc, args[0], args[1]); } +// IBITS +mlir::Value IntrinsicLibrary::genIbits(mlir::Type resultType, + llvm::ArrayRef 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().getWidth()); + auto shiftCount = builder.create(loc, bitSize, len); + mlir::Value zero = builder.createIntegerConstant(loc, resultType, 0); + mlir::Value ones = builder.createIntegerConstant(loc, resultType, -1); + auto mask = builder.create(loc, ones, shiftCount); + auto res1 = builder.create(loc, args[0], pos); + auto res2 = builder.create(loc, res1, mask); + auto lenIsZero = builder.create( + loc, mlir::arith::CmpIPredicate::eq, len, zero); + return builder.create(loc, lenIsZero, zero, res2); +} + // Compare two FIR values and return boolean result as i1. template static mlir::Value createExtremumCompare(mlir::Location loc, diff --git a/flang/test/Lower/Intrinsics/ibits.f90 b/flang/test/Lower/Intrinsics/ibits.f90 new file mode 100644 index 0000000000000..9702aa346d663 --- /dev/null +++ b/flang/test/Lower/Intrinsics/ibits.f90 @@ -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 + ! 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.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 + ! CHECK: %[[VAL_16:.*]] = fir.load %[[result]] : !fir.ref + ! CHECK: return %[[VAL_16]] : i32 + ibits_test = ibits(i, j, k) +end