diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -244,6 +244,46 @@ mlir::Location loc; }; +//===--------------------------------------------------------------------===// +// Binary Operation implementation +//===--------------------------------------------------------------------===// + +template +struct BinaryOp { + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, + hlfir::Entity lhs, hlfir::Entity rhs) { + TODO(loc, "binary op implementation in HLFIR"); + } +}; + +#undef GENBIN +#define GENBIN(GenBinEvOp, GenBinTyCat, GenBinFirOp) \ + template \ + struct BinaryOp>> { \ + static hlfir::EntityWithAttributes gen(mlir::Location loc, \ + fir::FirOpBuilder &builder, \ + hlfir::Entity lhs, \ + hlfir::Entity rhs) { \ + return hlfir::EntityWithAttributes{ \ + builder.create(loc, lhs, rhs)}; \ + } \ + }; + +GENBIN(Add, Integer, mlir::arith::AddIOp) +GENBIN(Add, Real, mlir::arith::AddFOp) +GENBIN(Add, Complex, fir::AddcOp) +GENBIN(Subtract, Integer, mlir::arith::SubIOp) +GENBIN(Subtract, Real, mlir::arith::SubFOp) +GENBIN(Subtract, Complex, fir::SubcOp) +GENBIN(Multiply, Integer, mlir::arith::MulIOp) +GENBIN(Multiply, Real, mlir::arith::MulFOp) +GENBIN(Multiply, Complex, fir::MulcOp) +GENBIN(Divide, Integer, mlir::arith::DivSIOp) +GENBIN(Divide, Real, mlir::arith::DivFOp) +GENBIN(Divide, Complex, fir::DivcOp) + /// Lower Expr to HLFIR. class HlfirBuilder { public: @@ -339,7 +379,13 @@ template hlfir::EntityWithAttributes gen(const Fortran::evaluate::Operation &op) { - TODO(getLoc(), "lowering binary op to HLFIR"); + auto &builder = getBuilder(); + mlir::Location loc = getLoc(); + if (op.Rank() != 0) + TODO(loc, "elemental operations in HLFIR"); + auto left = hlfir::loadTrivialScalar(loc, builder, gen(op.left())); + auto right = hlfir::loadTrivialScalar(loc, builder, gen(op.right())); + return BinaryOp::gen(loc, builder, left, right); } template diff --git a/flang/test/Lower/HLFIR/binary-ops.f90 b/flang/test/Lower/HLFIR/binary-ops.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/HLFIR/binary-ops.f90 @@ -0,0 +1,134 @@ +! Test lowering of binary intrinsic operations to HLFIR +! RUN: bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s + +subroutine int_add(x, y, z) + integer :: x, y, z + x = y + z +end subroutine +! CHECK-LABEL: func.func @_QPint_add( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.addi %[[VAL_6]], %[[VAL_7]] : i32 + +subroutine real_add(x, y, z) + real :: x, y, z + x = y + z +end subroutine +! CHECK-LABEL: func.func @_QPreal_add( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.addf %[[VAL_6]], %[[VAL_7]] fastmath : f32 + +subroutine complex_add(x, y, z) + complex :: x, y, z + x = y + z +end subroutine +! CHECK-LABEL: func.func @_QPcomplex_add( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref> +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.addc %[[VAL_6]], %[[VAL_7]] : !fir.complex<4> + +subroutine int_sub(x, y, z) + integer :: x, y, z + x = y - z +end subroutine +! CHECK-LABEL: func.func @_QPint_sub( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.subi %[[VAL_6]], %[[VAL_7]] : i32 + +subroutine real_sub(x, y, z) + real :: x, y, z + x = y - z +end subroutine +! CHECK-LABEL: func.func @_QPreal_sub( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.subf %[[VAL_6]], %[[VAL_7]] fastmath : f32 + +subroutine complex_sub(x, y, z) + complex :: x, y, z + x = y - z +end subroutine +! CHECK-LABEL: func.func @_QPcomplex_sub( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref> +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.subc %[[VAL_6]], %[[VAL_7]] : !fir.complex<4> + +subroutine int_mul(x, y, z) + integer :: x, y, z + x = y * z +end subroutine +! CHECK-LABEL: func.func @_QPint_mul( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.muli %[[VAL_6]], %[[VAL_7]] : i32 + +subroutine real_mul(x, y, z) + real :: x, y, z + x = y * z +end subroutine +! CHECK-LABEL: func.func @_QPreal_mul( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.mulf %[[VAL_6]], %[[VAL_7]] fastmath : f32 + +subroutine complex_mul(x, y, z) + complex :: x, y, z + x = y * z +end subroutine +! CHECK-LABEL: func.func @_QPcomplex_mul( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref> +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.mulc %[[VAL_6]], %[[VAL_7]] : !fir.complex<4> + +subroutine int_div(x, y, z) + integer :: x, y, z + x = y / z +end subroutine +! CHECK-LABEL: func.func @_QPint_div( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.divsi %[[VAL_6]], %[[VAL_7]] : i32 + +subroutine real_div(x, y, z) + real :: x, y, z + x = y / z +end subroutine +! CHECK-LABEL: func.func @_QPreal_div( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.divf %[[VAL_6]], %[[VAL_7]] fastmath : f32 + +subroutine complex_div(x, y, z) + complex :: x, y, z + x = y / z +end subroutine +! CHECK-LABEL: func.func @_QPcomplex_div( +! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %{{.*}}y"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %{{.*}}z"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref> +! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref> +! CHECK: %[[VAL_8:.*]] = fir.divc %[[VAL_6]], %[[VAL_7]] : !fir.complex<4>