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
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) {
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<
--- /dev/null
+! 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
--- /dev/null
+! 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