[flang] Lower real comparison operations
authorValentin Clement <clementval@gmail.com>
Fri, 25 Feb 2022 20:02:53 +0000 (21:02 +0100)
committerValentin Clement <clementval@gmail.com>
Fri, 25 Feb 2022 20:03:39 +0000 (21:03 +0100)
This patch handles the lowering of real
comparison operations. The real comparison operations
are lowered to `arith.cmpf` operation.

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

Reviewed By: PeteSteinfeld, schweitz

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

Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
Co-authored-by: Jean Perier <jperier@nvidia.com>
flang/lib/Lower/ConvertExpr.cpp
flang/test/Lower/real-operations-1.f90 [new file with mode: 0644]
flang/test/Lower/real-operations-2.f90 [new file with mode: 0644]

index ff5ae13..3f02d72 100644 (file)
@@ -130,6 +130,33 @@ translateRelational(Fortran::common::RelationalOperator rop) {
   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");
+}
+
 /// Place \p exv in memory if it is not already a memory reference. If
 /// \p forceValueType is provided, the value is first casted to the provided
 /// type before being stored (this is mainly intended for logicals whose value
@@ -373,6 +400,20 @@ public:
     return createCompareOp<OpTy>(pred, left, genval(ex.right()));
   }
 
+  template <typename OpTy>
+  mlir::Value createFltCmpOp(mlir::arith::CmpFPredicate pred,
+                             const ExtValue &left, const ExtValue &right) {
+    if (const fir::UnboxedValue *lhs = left.getUnboxed())
+      if (const fir::UnboxedValue *rhs = right.getUnboxed())
+        return builder.create<OpTy>(getLoc(), pred, *lhs, *rhs);
+    fir::emitFatalError(getLoc(), "array compare should be handled in genarr");
+  }
+  template <typename OpTy, typename A>
+  mlir::Value createFltCmpOp(const A &ex, mlir::arith::CmpFPredicate pred) {
+    ExtValue left = genval(ex.left());
+    return createFltCmpOp<OpTy>(pred, left, genval(ex.right()));
+  }
+
   /// Returns a reference to a symbol or its box/boxChar descriptor if it has
   /// one.
   ExtValue gen(Fortran::semantics::SymbolRef sym) {
@@ -535,7 +576,8 @@ public:
   template <int KIND>
   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
                       Fortran::common::TypeCategory::Real, KIND>> &op) {
-    TODO(getLoc(), "genval real comparison");
+    return createFltCmpOp<mlir::arith::CmpFOp>(
+        op, translateFloatRelational(op.opr));
   }
   template <int KIND>
   ExtValue genval(const Fortran::evaluate::Relational<Fortran::evaluate::Type<
diff --git a/flang/test/Lower/real-operations-1.f90 b/flang/test/Lower/real-operations-1.f90
new file mode 100644 (file)
index 0000000..67de090
--- /dev/null
@@ -0,0 +1,104 @@
+! RUN: bbc %s -o - | FileCheck %s
+
+! Test real add on real kinds.
+
+! CHECK-LABEL: real2
+REAL(2) FUNCTION real2(x0, x1)
+  REAL(2) :: x0
+  REAL(2) :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f16>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f16>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f16
+  real2 = x0 + x1
+  ! CHECK: return %{{.*}} : f16
+END FUNCTION real2
+
+! CHECK-LABEL: real3
+REAL(3) FUNCTION real3(x0, x1)
+  REAL(3) :: x0
+  REAL(3) :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<bf16>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<bf16>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : bf16
+  real3 = x0 + x1
+  ! CHECK: return %{{.*}} : bf16
+END FUNCTION real3
+
+! CHECK-LABEL: real4
+REAL(4) FUNCTION real4(x0, x1)
+  REAL(4) :: x0
+  REAL(4) :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f32>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f32>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f32
+  real4 = x0 + x1
+  ! CHECK: return %{{.*}} : f32
+END FUNCTION real4
+
+! CHECK-LABEL: defreal
+REAL FUNCTION defreal(x0, x1)
+  REAL :: x0
+  REAL :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f32>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f32>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f32
+  defreal = x0 + x1
+  ! CHECK: return %{{.*}} : f32
+END FUNCTION defreal
+
+! CHECK-LABEL: real8
+REAL(8) FUNCTION real8(x0, x1)
+  REAL(8) :: x0
+  REAL(8) :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f64>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f64>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f64
+  real8 = x0 + x1
+  ! CHECK: return %{{.*}} : f64
+END FUNCTION real8
+
+! CHECK-LABEL: doubleprec
+DOUBLE PRECISION FUNCTION doubleprec(x0, x1)
+  DOUBLE PRECISION :: x0
+  DOUBLE PRECISION :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f64>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f64>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f64
+  doubleprec = x0 + x1
+  ! CHECK: return %{{.*}} : f64
+END FUNCTION doubleprec
+
+! CHECK-LABEL: real10
+REAL(10) FUNCTION real10(x0, x1)
+  REAL(10) :: x0
+  REAL(10) :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f80>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f80>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f80
+  real10 = x0 + x1
+  ! CHECK: return %{{.*}} : f80
+END FUNCTION real10
+
+! CHECK-LABEL: real16
+REAL(16) FUNCTION real16(x0, x1)
+  REAL(16) :: x0
+  REAL(16) :: x1
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f128>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f128>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f128
+  real16 = x0 + x1
+  ! CHECK: return %{{.*}} : f128
+END FUNCTION real16
+
+! CHECK-LABEL: real16b
+REAL(16) FUNCTION real16b(x0, x1)
+  REAL(16) :: x0
+  REAL(16) :: x1
+  ! CHECK-DAG: %[[v0:.+]] = arith.constant 4.0{{.*}} : f128
+  ! CHECK-DAG: %[[v1:.+]] = fir.load %arg0 : !fir.ref<f128>
+  ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref<f128>
+  ! CHECK: %[[v3:.+]] = arith.addf %[[v1]], %[[v2]] : f128
+  ! CHECK: %[[v4:.+]] = arith.subf %[[v3]], %[[v0]] : f128
+  real16b = x0 + x1 - 4.0_16
+  ! CHECK: return %{{.*}} : f128
+END FUNCTION real16b
diff --git a/flang/test/Lower/real-operations-2.f90 b/flang/test/Lower/real-operations-2.f90
new file mode 100644 (file)
index 0000000..c8b09a0
--- /dev/null
@@ -0,0 +1,109 @@
+! RUN: bbc %s -o "-" | FileCheck %s
+
+! Test real intrinsic operation lowering to FIR.
+
+! CHECK-LABEL:eq0_test
+LOGICAL FUNCTION eq0_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:[[reg3:%[0-9]+]] = arith.cmpf oeq, [[reg1]], [[reg2]] : f32
+! CHECK:fir.convert [[reg3]] {{.*}} -> !fir.logical<4>
+eq0_test = x0 .EQ. x1
+END FUNCTION
+
+! CHECK-LABEL:ne1_test
+LOGICAL FUNCTION ne1_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:[[reg3:%[0-9]+]] = arith.cmpf une, [[reg1]], [[reg2]] : f32
+! CHECK:fir.convert [[reg3]] {{.*}} -> !fir.logical<4>
+ne1_test = x0 .NE. x1
+END FUNCTION
+
+! CHECK-LABEL:lt2_test
+LOGICAL FUNCTION lt2_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:[[reg3:%[0-9]+]] = arith.cmpf olt, [[reg1]], [[reg2]] : f32
+! CHECK:fir.convert [[reg3]] {{.*}} -> !fir.logical<4>
+lt2_test = x0 .LT. x1
+END FUNCTION
+
+! CHECK-LABEL:le3_test
+LOGICAL FUNCTION le3_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:[[reg3:%[0-9]+]] = arith.cmpf ole, [[reg1]], [[reg2]] : f32
+! CHECK:fir.convert [[reg3]] {{.*}} -> !fir.logical<4>
+le3_test = x0 .LE. x1
+END FUNCTION
+
+! CHECK-LABEL:gt4_test
+LOGICAL FUNCTION gt4_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:[[reg3:%[0-9]+]] = arith.cmpf ogt, [[reg1]], [[reg2]] : f32
+! CHECK:fir.convert [[reg3]] {{.*}} -> !fir.logical<4>
+gt4_test = x0 .GT. x1
+END FUNCTION
+
+! CHECK-LABEL:ge5_test
+LOGICAL FUNCTION ge5_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:[[reg3:%[0-9]+]] = arith.cmpf oge, [[reg1]], [[reg2]] : f32
+! CHECK:fir.convert [[reg3]] {{.*}} -> !fir.logical<4>
+ge5_test = x0 .GE. x1
+END FUNCTION
+
+! CHECK-LABEL:add6_test
+REAL(4) FUNCTION add6_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:addf [[reg1]], [[reg2]] : f32
+add6_test = x0 + x1
+END FUNCTION
+
+! CHECK-LABEL:sub7_test
+REAL(4) FUNCTION sub7_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:subf [[reg1]], [[reg2]] : f32
+sub7_test = x0 - x1
+END FUNCTION
+
+! CHECK-LABEL:mult8_test
+REAL(4) FUNCTION mult8_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:mulf [[reg1]], [[reg2]] : f32
+mult8_test = x0 * x1
+END FUNCTION
+
+! CHECK-LABEL:div9_test
+REAL(4) FUNCTION div9_test(x0, x1)
+REAL(4) :: x0
+REAL(4) :: x1
+! CHECK-DAG:[[reg1:%[0-9]+]] = fir.load %arg0
+! CHECK-DAG:[[reg2:%[0-9]+]] = fir.load %arg1
+! CHECK:divf [[reg1]], [[reg2]] : f32
+div9_test = x0 / x1
+END FUNCTION