diff --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -130,6 +130,33 @@ 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 @@ return createCompareOp(pred, left, genval(ex.right())); } + template + 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(getLoc(), pred, *lhs, *rhs); + fir::emitFatalError(getLoc(), "array compare should be handled in genarr"); + } + template + mlir::Value createFltCmpOp(const A &ex, mlir::arith::CmpFPredicate pred) { + ExtValue left = genval(ex.left()); + return createFltCmpOp(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 @@ template ExtValue genval(const Fortran::evaluate::Relational> &op) { - TODO(getLoc(), "genval real comparison"); + return createFltCmpOp( + op, translateFloatRelational(op.opr)); } template ExtValue genval(const Fortran::evaluate::Relational + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 + ! CHECK-DAG: %[[v2:.+]] = fir.load %arg1 : !fir.ref + ! 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 --- /dev/null +++ b/flang/test/Lower/real-operations-2.f90 @@ -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