[flang] Lower relational to HLFIR

Differential Revision: https://reviews.llvm.org/D139176
This commit is contained in:
Jean Perier 2022-12-02 14:17:55 +01:00
parent 63150f4639
commit 12530711fc
2 changed files with 198 additions and 0 deletions

View File

@ -20,6 +20,7 @@
#include "flang/Lower/IntrinsicCall.h"
#include "flang/Lower/StatementContext.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Optimizer/Builder/Runtime/Character.h"
#include "flang/Optimizer/Builder/Todo.h"
#include "flang/Optimizer/HLFIR/HLFIROps.h"
@ -341,6 +342,121 @@ struct BinaryOp<
}
};
/// Convert parser's INTEGER relational operators to MLIR.
static mlir::arith::CmpIPredicate
translateRelational(Fortran::common::RelationalOperator rop) {
switch (rop) {
case Fortran::common::RelationalOperator::LT:
return mlir::arith::CmpIPredicate::slt;
case Fortran::common::RelationalOperator::LE:
return mlir::arith::CmpIPredicate::sle;
case Fortran::common::RelationalOperator::EQ:
return mlir::arith::CmpIPredicate::eq;
case Fortran::common::RelationalOperator::NE:
return mlir::arith::CmpIPredicate::ne;
case Fortran::common::RelationalOperator::GT:
return mlir::arith::CmpIPredicate::sgt;
case Fortran::common::RelationalOperator::GE:
return mlir::arith::CmpIPredicate::sge;
}
llvm_unreachable("unhandled INTEGER relational operator");
}
/// Convert parser's REAL relational operators to MLIR.
/// The choice of order (O prefix) vs unorder (U prefix) follows Fortran 2018
/// requirements in the IEEE context (table 17.1 of F2018). This choice is
/// also applied in other contexts because it is easier and in line with
/// other Fortran compilers.
/// FIXME: The signaling/quiet aspect of the table 17.1 requirement is not
/// fully enforced. FIR and LLVM `fcmp` instructions do not give any guarantee
/// whether the comparison will signal or not in case of quiet NaN argument.
static mlir::arith::CmpFPredicate
translateFloatRelational(Fortran::common::RelationalOperator rop) {
switch (rop) {
case Fortran::common::RelationalOperator::LT:
return mlir::arith::CmpFPredicate::OLT;
case Fortran::common::RelationalOperator::LE:
return mlir::arith::CmpFPredicate::OLE;
case Fortran::common::RelationalOperator::EQ:
return mlir::arith::CmpFPredicate::OEQ;
case Fortran::common::RelationalOperator::NE:
return mlir::arith::CmpFPredicate::UNE;
case Fortran::common::RelationalOperator::GT:
return mlir::arith::CmpFPredicate::OGT;
case Fortran::common::RelationalOperator::GE:
return mlir::arith::CmpFPredicate::OGE;
}
llvm_unreachable("unhandled REAL relational operator");
}
template <int KIND>
struct BinaryOp<Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>> {
using Op = Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>;
static hlfir::EntityWithAttributes gen(mlir::Location loc,
fir::FirOpBuilder &builder,
const Op &op, hlfir::Entity lhs,
hlfir::Entity rhs) {
auto cmp = builder.create<mlir::arith::CmpIOp>(
loc, translateRelational(op.opr), lhs, rhs);
return hlfir::EntityWithAttributes{cmp};
}
};
template <int KIND>
struct BinaryOp<Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>> {
using Op = Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>;
static hlfir::EntityWithAttributes gen(mlir::Location loc,
fir::FirOpBuilder &builder,
const Op &op, hlfir::Entity lhs,
hlfir::Entity rhs) {
auto cmp = builder.create<mlir::arith::CmpFOp>(
loc, translateFloatRelational(op.opr), lhs, rhs);
return hlfir::EntityWithAttributes{cmp};
}
};
template <int KIND>
struct BinaryOp<Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> {
using Op = Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>;
static hlfir::EntityWithAttributes gen(mlir::Location loc,
fir::FirOpBuilder &builder,
const Op &op, hlfir::Entity lhs,
hlfir::Entity rhs) {
auto cmp = builder.create<fir::CmpcOp>(
loc, translateFloatRelational(op.opr), lhs, rhs);
return hlfir::EntityWithAttributes{cmp};
}
};
template <int KIND>
struct BinaryOp<Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>> {
using Op = Fortran::evaluate::Relational<
Fortran::evaluate::Type<Fortran::common::TypeCategory::Character, KIND>>;
static hlfir::EntityWithAttributes gen(mlir::Location loc,
fir::FirOpBuilder &builder,
const Op &op, hlfir::Entity lhs,
hlfir::Entity rhs) {
auto [lhsExv, lhsCleanUp] =
hlfir::translateToExtendedValue(loc, builder, lhs);
auto [rhsExv, rhsCleanUp] =
hlfir::translateToExtendedValue(loc, builder, rhs);
auto cmp = fir::runtime::genCharCompare(
builder, loc, translateRelational(op.opr), lhsExv, rhsExv);
if (lhsCleanUp)
lhsCleanUp.value()();
if (rhsCleanUp)
rhsCleanUp.value()();
return hlfir::EntityWithAttributes{cmp};
}
};
/// Lower Expr to HLFIR.
class HlfirBuilder {
public:

View File

@ -207,3 +207,85 @@ end subroutine
! CHECK: %[[VAL_12:.*]] = fir.load %{{.*}} : !fir.ref<i64>
! CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_12]] : i64
! CHECK: arith.select %[[VAL_13]], %[[VAL_11]], %[[VAL_12]] : i64
subroutine cmp_int(l, x, y)
logical :: l
integer :: x, y
l = x .eq. y
end subroutine
! CHECK-LABEL: func.func @_QPcmp_int(
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}x"
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}y"
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_8:.*]] = arith.cmpi eq, %[[VAL_6]], %[[VAL_7]] : i32
subroutine cmp_int_2(l, x, y)
logical :: l
integer :: x, y
l = x .ne. y
! CHECK: arith.cmpi ne
l = x .gt. y
! CHECK: arith.cmpi sgt
l = x .ge. y
! CHECK: arith.cmpi sge
l = x .lt. y
! CHECK: arith.cmpi slt
l = x .le. y
! CHECK: arith.cmpi sle
end subroutine
subroutine cmp_real(l, x, y)
logical :: l
real :: x, y
l = x .eq. y
end subroutine
! CHECK-LABEL: func.func @_QPcmp_real(
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}x"
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}y"
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<f32>
! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<f32>
! CHECK: %[[VAL_8:.*]] = arith.cmpf oeq, %[[VAL_6]], %[[VAL_7]] : f32
subroutine cmp_real_2(l, x, y)
logical :: l
real :: x, y
l = x .ne. y
! CHECK: arith.cmpf une
l = x .gt. y
! CHECK: arith.cmpf ogt
l = x .ge. y
! CHECK: arith.cmpf oge
l = x .lt. y
! CHECK: arith.cmpf olt
l = x .le. y
! CHECK: arith.cmpf ole
end subroutine
subroutine cmp_cmplx(l, x, y)
logical :: l
complex :: x, y
l = x .eq. y
end subroutine
! CHECK-LABEL: func.func @_QPcmp_cmplx(
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare {{.*}}x"
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare {{.*}}y"
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<!fir.complex<4>>
! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<!fir.complex<4>>
! CHECK: %[[VAL_8:.*]] = fir.cmpc "oeq", %[[VAL_6]], %[[VAL_7]] : !fir.complex<4>
subroutine cmp_char(l, x, y)
logical :: l
character(*) :: x, y
l = x .eq. y
end subroutine
! CHECK-LABEL: func.func @_QPcmp_char(
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_4:.*]]#1 {uniq_name = "_QFcmp_charEx"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %{{.*}} typeparams %[[VAL_6:.*]]#1 {uniq_name = "_QFcmp_charEy"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_5]]#1 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_7]]#1 : (!fir.ref<!fir.char<1,?>>) -> !fir.ref<i8>
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_4]]#1 : (index) -> i64
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_6]]#1 : (index) -> i64
! CHECK: %[[VAL_12:.*]] = fir.call @_FortranACharacterCompareScalar1(%[[VAL_8]], %[[VAL_9]], %[[VAL_10]], %[[VAL_11]]) fastmath<contract> : (!fir.ref<i8>, !fir.ref<i8>, i64, i64) -> i32
! CHECK: %[[VAL_13:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_14:.*]] = arith.cmpi eq, %[[VAL_12]], %[[VAL_13]] : i32