[flang] Lower misc intrinsics

This patch adds lowering for couple of intrinsics:
- `btest`
- `ceiling`
- `nearest`
- `scale`

This patch is part of the upstreaming effort from fir-dev branch.

Reviewed By: jeanPerier

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

Co-authored-by: Jean Perier <jperier@nvidia.com>
Co-authored-by: V Donaldson <vdonaldson@nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
Co-authored-by: AlexisPerry <aperry@lanl.gov>
This commit is contained in:
Valentin Clement 2022-03-17 13:20:13 +01:00
parent 96fd54c964
commit 51cf471dc1
No known key found for this signature in database
GPG Key ID: 086D54783C928776
5 changed files with 230 additions and 0 deletions

View File

@ -442,6 +442,8 @@ struct IntrinsicLibrary {
fir::ExtendedValue genAny(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genAssociated(mlir::Type,
llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genBtest(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genCeiling(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genChar(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genCount(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
template <mlir::arith::CmpIPredicate pred>
@ -481,6 +483,7 @@ struct IntrinsicLibrary {
fir::ExtendedValue genMinval(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genMod(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
mlir::Value genNot(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genNull(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
@ -491,6 +494,7 @@ struct IntrinsicLibrary {
void genRandomNumber(llvm::ArrayRef<fir::ExtendedValue>);
void genRandomSeed(llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genReshape(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genScale(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genScan(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
mlir::Value genSetExponent(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args);
@ -623,6 +627,8 @@ static constexpr IntrinsicHandler handlers[]{
&I::genAssociated,
{{{"pointer", asInquired}, {"target", asInquired}}},
/*isElemental=*/false},
{"btest", &I::genBtest},
{"ceiling", &I::genCeiling},
{"char", &I::genChar},
{"count",
&I::genCount,
@ -718,6 +724,7 @@ static constexpr IntrinsicHandler handlers[]{
/*isElemental=*/false},
{"mod", &I::genMod},
{"modulo", &I::genModulo},
{"nearest", &I::genNearest},
{"nint", &I::genNint},
{"not", &I::genNot},
{"null", &I::genNull, {{{"mold", asInquired}}}, /*isElemental=*/false},
@ -756,6 +763,10 @@ static constexpr IntrinsicHandler handlers[]{
{"pad", asBox, handleDynamicOptional},
{"order", asBox, handleDynamicOptional}}},
/*isElemental=*/false},
{"scale",
&I::genScale,
{{{"x", asValue}, {"i", asValue}}},
/*isElemental=*/true},
{"scan",
&I::genScan,
{{{"string", asAddr},
@ -896,6 +907,9 @@ static mlir::FunctionType genIntF32FuncType(mlir::MLIRContext *context) {
static constexpr RuntimeFunction llvmIntrinsics[] = {
{"abs", "llvm.fabs.f32", genF32F32FuncType},
{"abs", "llvm.fabs.f64", genF64F64FuncType},
// ceil is used for CEILING but is different, it returns a real.
{"ceil", "llvm.ceil.f32", genF32F32FuncType},
{"ceil", "llvm.ceil.f64", genF64F64FuncType},
// llvm.floor is used for FLOOR, but returns real.
{"floor", "llvm.floor.f32", genF32F32FuncType},
{"floor", "llvm.floor.f64", genF64F64FuncType},
@ -1769,6 +1783,35 @@ IntrinsicLibrary::genAssociated(mlir::Type resultType,
return Fortran::lower::genAssociated(builder, loc, pointerBox, targetBox);
}
// BTEST
mlir::Value IntrinsicLibrary::genBtest(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
// A conformant BTEST(I,POS) call satisfies:
// POS >= 0
// POS < BIT_SIZE(I)
// Return: (I >> POS) & 1
assert(args.size() == 2);
mlir::Type argType = args[0].getType();
mlir::Value pos = builder.createConvert(loc, argType, args[1]);
auto shift = builder.create<mlir::arith::ShRUIOp>(loc, args[0], pos);
mlir::Value one = builder.createIntegerConstant(loc, argType, 1);
auto res = builder.create<mlir::arith::AndIOp>(loc, shift, one);
return builder.createConvert(loc, resultType, res);
}
// CEILING
mlir::Value IntrinsicLibrary::genCeiling(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
// Optional KIND argument.
assert(args.size() >= 1);
mlir::Value arg = args[0];
// Use ceil that is not an actual Fortran intrinsic but that is
// an llvm intrinsic that does the same, but return a floating
// point.
mlir::Value ceil = genRuntimeCall("ceil", arg.getType(), {arg});
return builder.createConvert(loc, resultType, ceil);
}
// CHAR
fir::ExtendedValue
IntrinsicLibrary::genChar(mlir::Type type,
@ -2502,6 +2545,18 @@ mlir::Value IntrinsicLibrary::genModulo(mlir::Type resultType,
remainder);
}
// NEAREST
mlir::Value IntrinsicLibrary::genNearest(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
mlir::Value realX = fir::getBase(args[0]);
mlir::Value realS = fir::getBase(args[1]);
return builder.createConvert(
loc, resultType, fir::runtime::genNearest(builder, loc, realX, realS));
}
// NINT
mlir::Value IntrinsicLibrary::genNint(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
@ -2657,6 +2712,18 @@ IntrinsicLibrary::genReshape(mlir::Type resultType,
"unexpected result for RESHAPE");
}
// SCALE
mlir::Value IntrinsicLibrary::genScale(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);
mlir::Value realX = fir::getBase(args[0]);
mlir::Value intI = fir::getBase(args[1]);
return builder.createConvert(
loc, resultType, fir::runtime::genScale(builder, loc, realX, intI));
}
// SCAN
fir::ExtendedValue
IntrinsicLibrary::genScan(mlir::Type resultType,

View File

@ -0,0 +1,18 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s
! CHECK-LABEL: btest_test
function btest_test(i, j)
logical btest_test
! CHECK-DAG: %[[result:[0-9]+]] = fir.alloca !fir.logical<4> {bindc_name = "btest_test"
! CHECK-DAG: %[[i:[0-9]+]] = fir.load %arg0 : !fir.ref<i32>
! CHECK-DAG: %[[j:[0-9]+]] = fir.load %arg1 : !fir.ref<i32>
! CHECK-DAG: %[[VAL_5:.*]] = arith.shrui %[[i]], %[[j]] : i32
! CHECK-DAG: %[[VAL_6:.*]] = arith.constant 1 : i32
! CHECK: %[[VAL_7:.*]] = arith.andi %[[VAL_5]], %[[VAL_6]] : i32
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> !fir.logical<4>
! CHECK: fir.store %[[VAL_8]] to %[[result]] : !fir.ref<!fir.logical<4>>
! CHECK: %[[VAL_9:.*]] = fir.load %[[result]] : !fir.ref<!fir.logical<4>>
! CHECK: return %[[VAL_9]] : !fir.logical<4>
btest_test = btest(i, j)
end

View File

@ -0,0 +1,20 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s
! CHECK-LABEL: ceiling_test1
subroutine ceiling_test1(i, a)
integer :: i
real :: a
i = ceiling(a)
! CHECK: %[[f:.*]] = fir.call @llvm.ceil.f32
! CHECK: fir.convert %[[f]] : (f32) -> i32
end subroutine
! CHECK-LABEL: ceiling_test2
subroutine ceiling_test2(i, a)
integer(8) :: i
real :: a
i = ceiling(a, 8)
! CHECK: %[[f:.*]] = fir.call @llvm.ceil.f32
! CHECK: fir.convert %[[f]] : (f32) -> i64
end subroutine

View File

@ -0,0 +1,72 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s
! CHECK-LABEL: nearest_test1
subroutine nearest_test1(x, s)
real :: x, s, res
! CHECK: %[[res:.*]] = fir.alloca f32 {bindc_name = "res", uniq_name = "_QFnearest_test1Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f32>
! CHECK: %[[s:.*]] = fir.load %arg1 : !fir.ref<f32>
! CHECK: %[[zero:.*]] = arith.constant 0.000000e+00 : f32
! CHECK: %[[cmp:.*]] = arith.cmpf ogt, %[[s]], %[[zero]] : f32
! CHECK: %[[pos:.*]] = arith.select %[[cmp]], %true, %false : i1
res = nearest(x, s)
! CHECK: %[[tmp:.*]] = fir.call @_FortranANearest4(%[[x]], %[[pos]]) : (f32, i1) -> f32
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f32>
end subroutine nearest_test1
! CHECK-LABEL: nearest_test2
subroutine nearest_test2(x, s)
real(kind=8) :: x, s, res
! CHECK: %[[res:.*]] = fir.alloca f64 {bindc_name = "res", uniq_name = "_QFnearest_test2Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f64>
! CHECK: %[[s:.*]] = fir.load %arg1 : !fir.ref<f64>
! CHECK: %[[zero:.*]] = arith.constant 0.000000e+00 : f64
! CHECK: %[[cmp:.*]] = arith.cmpf ogt, %[[s]], %[[zero]] : f64
! CHECK: %[[pos:.*]] = arith.select %[[cmp]], %true, %false : i1
res = nearest(x, s)
! CHECK: %[[tmp:.*]] = fir.call @_FortranANearest8(%[[x]], %[[pos]]) : (f64, i1) -> f64
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f64>
end subroutine nearest_test2
! CHECK-LABEL: nearest_test3
subroutine nearest_test3(x, s)
real(kind=10) :: x, s, res
! CHECK: %[[res:.*]] = fir.alloca f80 {bindc_name = "res", uniq_name = "_QFnearest_test3Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f80>
! CHECK: %[[s:.*]] = fir.load %arg1 : !fir.ref<f80>
! CHECK: %[[zero:.*]] = arith.constant 0.000000e+00 : f80
! CHECK: %[[cmp:.*]] = arith.cmpf ogt, %[[s]], %[[zero]] : f80
! CHECK: %[[pos:.*]] = arith.select %[[cmp]], %true, %false : i1
res = nearest(x, s)
! CHECK: %[[tmp:.*]] = fir.call @_FortranANearest10(%[[x]], %[[pos]]) : (f80, i1) -> f80
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f80>
end subroutine nearest_test3
! CHECK-LABEL: nearest_test4
subroutine nearest_test4(x, s)
real(kind=16) :: x, s, res
! CHECK: %[[res:.*]] = fir.alloca f128 {bindc_name = "res", uniq_name = "_QFnearest_test4Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f128>
! CHECK: %[[s:.*]] = fir.load %arg1 : !fir.ref<f128>
! CHECK: %[[zero:.*]] = arith.constant 0.000000e+00 : f128
! CHECK: %[[cmp:.*]] = arith.cmpf ogt, %[[s]], %[[zero]] : f128
! CHECK: %[[pos:.*]] = arith.select %[[cmp]], %true, %false : i1
res = nearest(x, s)
! CHECK: %[[tmp:.*]] = fir.call @_FortranANearest16(%[[x]], %[[pos]]) : (f128, i1) -> f128
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f128>
end subroutine nearest_test4
! CHECK-LABEL: nearest_test5
subroutine nearest_test5(x, s)
real(kind=16) :: x, res
! CHECK: %[[res:.*]] = fir.alloca f128 {bindc_name = "res", uniq_name = "_QFnearest_test5Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f128>
real :: s
! CHECK: %[[s:.*]] = fir.load %arg1 : !fir.ref<f32>
! CHECK: %[[zero:.*]] = arith.constant 0.000000e+00 : f32
! CHECK: %[[cmp:.*]] = arith.cmpf ogt, %[[s]], %[[zero]] : f32
! CHECK: %[[pos:.*]] = arith.select %[[cmp]], %true, %false : i1
res = nearest(x, s)
! CHECK: %[[tmp:.*]] = fir.call @_FortranANearest16(%[[x]], %[[pos]]) : (f128, i1) -> f128
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f128>
end subroutine nearest_test5

View File

@ -0,0 +1,53 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s
! CHECK-LABEL: scale_test1
subroutine scale_test1(x, i)
real :: x, res
! CHECK: %[[res:.*]] = fir.alloca f32 {bindc_name = "res", uniq_name = "_QFscale_test1Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f32>
integer :: i
! CHECK: %[[i0:.*]] = fir.load %arg1 : !fir.ref<i32>
res = scale(x, i)
! CHECK: %[[i1:.*]] = fir.convert %[[i0]] : (i32) -> i64
! CHECK: %[[tmp:.*]] = fir.call @_FortranAScale4(%[[x]], %[[i1]]) : (f32, i64) -> f32
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f32>
end subroutine scale_test1
! CHECK-LABEL: scale_test2
subroutine scale_test2(x, i)
real(kind=8) :: x, res
! CHECK: %[[res:.*]] = fir.alloca f64 {bindc_name = "res", uniq_name = "_QFscale_test2Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f64>
integer :: i
! CHECK: %[[i0:.*]] = fir.load %arg1 : !fir.ref<i32>
res = scale(x, i)
! CHECK: %[[i1:.*]] = fir.convert %[[i0]] : (i32) -> i64
! CHECK: %[[tmp:.*]] = fir.call @_FortranAScale8(%[[x]], %[[i1]]) : (f64, i64) -> f64
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f64>
end subroutine scale_test2
! CHECK-LABEL: scale_test3
subroutine scale_test3(x, i)
real(kind=10) :: x, res
! CHECK: %[[res:.*]] = fir.alloca f80 {bindc_name = "res", uniq_name = "_QFscale_test3Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f80>
integer :: i
! CHECK: %[[i0:.*]] = fir.load %arg1 : !fir.ref<i32>
res = scale(x, i)
! CHECK: %[[i1:.*]] = fir.convert %[[i0]] : (i32) -> i64
! CHECK: %[[tmp:.*]] = fir.call @_FortranAScale10(%[[x]], %[[i1]]) : (f80, i64) -> f80
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f80>
end subroutine scale_test3
! CHECK-LABEL: scale_test4
subroutine scale_test4(x, i)
real(kind=16) :: x, res
! CHECK: %[[res:.*]] = fir.alloca f128 {bindc_name = "res", uniq_name = "_QFscale_test4Eres"}
! CHECK: %[[x:.*]] = fir.load %arg0 : !fir.ref<f128>
integer :: i
! CHECK: %[[i0:.*]] = fir.load %arg1 : !fir.ref<i32>
res = scale(x, i)
! CHECK: %[[i1:.*]] = fir.convert %[[i0]] : (i32) -> i64
! CHECK: %[[tmp:.*]] = fir.call @_FortranAScale16(%[[x]], %[[i1]]) : (f128, i64) -> f128
! CHECK: fir.store %[[tmp]] to %[[res]] : !fir.ref<f128>
end subroutine scale_test4