Skip to content

Commit

Permalink
[flang] Lower F08 mask intrinsics
Browse files Browse the repository at this point in the history
Lower F08 maskl and maskr intrinsics.

Differential Revision: https://reviews.llvm.org/D129296
  • Loading branch information
Tarun Prabhu committed Jul 22, 2022
1 parent 72ac3e9 commit 71ee357
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 0 deletions.
25 changes: 25 additions & 0 deletions flang/lib/Lower/IntrinsicCall.cpp
Expand Up @@ -515,6 +515,8 @@ struct IntrinsicLibrary {
mlir::Value genLeadz(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genLen(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genLenTrim(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
template <typename Shift>
mlir::Value genMask(mlir::Type, llvm::ArrayRef<mlir::Value>);
fir::ExtendedValue genMatmul(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genMaxloc(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
fir::ExtendedValue genMaxval(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
Expand Down Expand Up @@ -813,6 +815,8 @@ static constexpr IntrinsicHandler handlers[]{
{"lgt", &I::genCharacterCompare<mlir::arith::CmpIPredicate::sgt>},
{"lle", &I::genCharacterCompare<mlir::arith::CmpIPredicate::sle>},
{"llt", &I::genCharacterCompare<mlir::arith::CmpIPredicate::slt>},
{"maskl", &I::genMask<mlir::arith::ShLIOp>},
{"maskr", &I::genMask<mlir::arith::ShRUIOp>},
{"matmul",
&I::genMatmul,
{{{"matrix_a", asAddr}, {"matrix_b", asAddr}}},
Expand Down Expand Up @@ -3314,6 +3318,27 @@ IntrinsicLibrary::genCharacterCompare(mlir::Type resultType,
fir::getBase(args[1]), fir::getLen(args[1]));
}

// MASKL, MASKR
template <typename Shift>
mlir::Value IntrinsicLibrary::genMask(mlir::Type resultType,
llvm::ArrayRef<mlir::Value> args) {
assert(args.size() == 2);

mlir::Value ones = builder.createIntegerConstant(loc, resultType, -1);
mlir::Value bitSize = builder.createIntegerConstant(
loc, resultType, resultType.getIntOrFloatBitWidth());
mlir::Value bitsToSet = builder.createConvert(loc, resultType, args[0]);

// The standard does not specify what to return if the number of bits to be
// set, I < 0 or I >= BIT_SIZE(KIND). The shift instruction used below will
// produce a poison value which may return a possibly platform-specific and/or
// non-deterministic result. Other compilers don't produce a consistent result
// in this case either, so we choose the most efficient implementation.
mlir::Value shift =
builder.create<mlir::arith::SubIOp>(loc, bitSize, bitsToSet);
return builder.create<Shift>(loc, ones, shift);
}

// MATMUL
fir::ExtendedValue
IntrinsicLibrary::genMatmul(mlir::Type resultType,
Expand Down
86 changes: 86 additions & 0 deletions flang/test/Lower/Intrinsics/maskl.f90
@@ -0,0 +1,86 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s

! CHECK-LABEL: maskl_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}
subroutine maskl_test(a, b)
integer :: a
integer :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskl(a)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i32
! CHECK: %[[BITS:.*]] = arith.constant 32 : i32
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_VAL]] : i32
! CHECK: %[[SHIFT:.*]] = arith.shli %[[C__1]], %[[LEN]] : i32
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i32>
end subroutine maskl_test

! CHECK-LABEL: maskl1_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i8>{{.*}}
subroutine maskl1_test(a, b)
integer :: a
integer(kind=1) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskl(a, 1)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i8
! CHECK: %[[BITS:.*]] = arith.constant 8 : i8
! CHECK: %[[A_CONV:.*]] = fir.convert %[[A_VAL]] : (i32) -> i8
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_CONV]] : i8
! CHECK: %[[SHIFT:.*]] = arith.shli %[[C__1]], %[[LEN]] : i8
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i8>
end subroutine maskl1_test

! CHECK-LABEL: maskl2_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i16>{{.*}}
subroutine maskl2_test(a, b)
integer :: a
integer(kind=2) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskl(a, 2)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i16
! CHECK: %[[BITS:.*]] = arith.constant 16 : i16
! CHECK: %[[A_CONV:.*]] = fir.convert %[[A_VAL]] : (i32) -> i16
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_CONV]] : i16
! CHECK: %[[SHIFT:.*]] = arith.shli %[[C__1]], %[[LEN]] : i16
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i16>
end subroutine maskl2_test

! CHECK-LABEL: maskl4_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}
subroutine maskl4_test(a, b)
integer :: a
integer(kind=4) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskl(a, 4)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i32
! CHECK: %[[BITS:.*]] = arith.constant 32 : i32
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_VAL]] : i32
! CHECK: %[[SHIFT:.*]] = arith.shli %[[C__1]], %[[LEN]] : i32
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i32>
end subroutine maskl4_test

! CHECK-LABEL: maskl8_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i64>{{.*}}
subroutine maskl8_test(a, b)
integer :: a
integer(kind=8) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskl(a, 8)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i64
! CHECK: %[[BITS:.*]] = arith.constant 64 : i64
! CHECK: %[[A_CONV:.*]] = fir.convert %[[A_VAL]] : (i32) -> i64
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_CONV]] : i64
! CHECK: %[[SHIFT:.*]] = arith.shli %[[C__1]], %[[LEN]] : i64
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i64>
end subroutine maskl8_test

! TODO: Code containing 128-bit integer literals current breaks. This is
! probably related to the issue linked below. When that is fixed, a test
! for kind=16 should be added here.
!
! https://github.com/llvm/llvm-project/issues/56446
86 changes: 86 additions & 0 deletions flang/test/Lower/Intrinsics/maskr.f90
@@ -0,0 +1,86 @@
! RUN: bbc -emit-fir %s -o - | FileCheck %s
! RUN: %flang_fc1 -emit-fir %s -o - | FileCheck %s

! CHECK-LABEL: maskr_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}
subroutine maskr_test(a, b)
integer :: a
integer :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskr(a)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i32
! CHECK: %[[BITS:.*]] = arith.constant 32 : i32
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_VAL]] : i32
! CHECK: %[[SHIFT:.*]] = arith.shrui %[[C__1]], %[[LEN]] : i32
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i32>
end subroutine maskr_test

! CHECK-LABEL: maskr1_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i8>{{.*}}
subroutine maskr1_test(a, b)
integer :: a
integer(kind=1) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskr(a, 1)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i8
! CHECK: %[[BITS:.*]] = arith.constant 8 : i8
! CHECK: %[[A_CONV:.*]] = fir.convert %[[A_VAL]] : (i32) -> i8
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_CONV]] : i8
! CHECK: %[[SHIFT:.*]] = arith.shrui %[[C__1]], %[[LEN]] : i8
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i8>
end subroutine maskr1_test

! CHECK-LABEL: maskr2_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i16>{{.*}}
subroutine maskr2_test(a, b)
integer :: a
integer(kind=2) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskr(a, 2)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i16
! CHECK: %[[BITS:.*]] = arith.constant 16 : i16
! CHECK: %[[A_CONV:.*]] = fir.convert %[[A_VAL]] : (i32) -> i16
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_CONV]] : i16
! CHECK: %[[SHIFT:.*]] = arith.shrui %[[C__1]], %[[LEN]] : i16
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i16>
end subroutine maskr2_test

! CHECK-LABEL: maskr4_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i32>{{.*}}
subroutine maskr4_test(a, b)
integer :: a
integer(kind=4) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskr(a, 4)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i32
! CHECK: %[[BITS:.*]] = arith.constant 32 : i32
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_VAL]] : i32
! CHECK: %[[SHIFT:.*]] = arith.shrui %[[C__1]], %[[LEN]] : i32
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i32>
end subroutine maskr4_test

! CHECK-LABEL: maskr8_test
! CHECK-SAME: %[[A:.*]]: !fir.ref<i32>{{.*}}, %[[B:.*]]: !fir.ref<i64>{{.*}}
subroutine maskr8_test(a, b)
integer :: a
integer(kind=8) :: b

! CHECK: %[[A_VAL:.*]] = fir.load %[[A]] : !fir.ref<i32>
b = maskr(a, 8)
! CHECK: %[[C__1:.*]] = arith.constant -1 : i64
! CHECK: %[[BITS:.*]] = arith.constant 64 : i64
! CHECK: %[[A_CONV:.*]] = fir.convert %[[A_VAL]] : (i32) -> i64
! CHECK: %[[LEN:.*]] = arith.subi %[[BITS]], %[[A_CONV]] : i64
! CHECK: %[[SHIFT:.*]] = arith.shrui %[[C__1]], %[[LEN]] : i64
! CHECK: fir.store %[[SHIFT]] to %[[B]] : !fir.ref<i64>
end subroutine maskr8_test

! TODO: Code containing 128-bit integer literals current breaks. This is
! probably related to the issue linked below. When that is fixed, a test
! for kind=16 should be added here.
!
! https://github.com/llvm/llvm-project/issues/56446

0 comments on commit 71ee357

Please sign in to comment.