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 @@ -506,6 +506,91 @@ } }; +//===--------------------------------------------------------------------===// +// Unary Operation implementation +//===--------------------------------------------------------------------===// + +template +struct UnaryOp {}; + +template +struct UnaryOp> { + using Op = Fortran::evaluate::Not; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, + const Op &op, hlfir::Entity lhs) { + mlir::Value one = builder.createBool(loc, true); + mlir::Value val = builder.createConvert(loc, builder.getI1Type(), lhs); + return hlfir::EntityWithAttributes{ + builder.create(loc, val, one)}; + } +}; + +template +struct UnaryOp>> { + using Op = Fortran::evaluate::Negate< + Fortran::evaluate::Type>; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, + const Op &op, hlfir::Entity lhs) { + // Like LLVM, integer negation is the binary op "0 - value" + mlir::Type type = Fortran::lower::getFIRType( + builder.getContext(), Fortran::common::TypeCategory::Integer, KIND, + /*params=*/llvm::None); + mlir::Value zero = builder.createIntegerConstant(loc, type, 0); + return hlfir::EntityWithAttributes{ + builder.create(loc, zero, lhs)}; + } +}; + +template +struct UnaryOp>> { + using Op = Fortran::evaluate::Negate< + Fortran::evaluate::Type>; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, + const Op &op, hlfir::Entity lhs) { + return hlfir::EntityWithAttributes{ + builder.create(loc, lhs)}; + } +}; + +template +struct UnaryOp>> { + using Op = Fortran::evaluate::Negate< + Fortran::evaluate::Type>; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, + const Op &op, hlfir::Entity lhs) { + return hlfir::EntityWithAttributes{builder.create(loc, lhs)}; + } +}; + +template +struct UnaryOp> { + using Op = Fortran::evaluate::ComplexComponent; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, + const Op &op, hlfir::Entity lhs) { + mlir::Value res = fir::factory::Complex{builder, loc}.extractComplexPart( + lhs, op.isImaginaryPart); + return hlfir::EntityWithAttributes{res}; + } +}; + +template +struct UnaryOp> { + using Op = Fortran::evaluate::Parentheses; + static hlfir::EntityWithAttributes gen(mlir::Location loc, + fir::FirOpBuilder &builder, + const Op &op, hlfir::Entity lhs) { + TODO(loc, "Parentheses lowering to HLFIR"); + } +}; + /// Lower Expr to HLFIR. class HlfirBuilder { public: @@ -595,7 +680,12 @@ template hlfir::EntityWithAttributes gen(const Fortran::evaluate::Operation &op) { - TODO(getLoc(), "lowering unary 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())); + return UnaryOp::gen(loc, builder, op.derived(), left); } template diff --git a/flang/test/Lower/HLFIR/unary-ops.f90 b/flang/test/Lower/HLFIR/unary-ops.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/HLFIR/unary-ops.f90 @@ -0,0 +1,61 @@ +! Test lowering of unary intrinsic operations to HLFIR +! RUN: bbc -emit-fir -hlfir -o - %s 2>&1 | FileCheck %s + +subroutine test_not(l, x) + logical :: l, x + l = .not.x +end subroutine +! CHECK-LABEL: func.func @_QPtest_not( +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}x"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref> +! CHECK: %[[VAL_5:.*]] = arith.constant true +! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_4]] : (!fir.logical<4>) -> i1 +! CHECK: %[[VAL_7:.*]] = arith.xori %[[VAL_6]], %[[VAL_5]] : i1 + +subroutine test_negate_int(res, x) + integer :: res, x + res = -x +end subroutine +! CHECK-LABEL: func.func @_QPtest_negate_int( +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}x"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_5:.*]] = arith.constant 0 : i32 +! CHECK: %[[VAL_6:.*]] = arith.subi %[[VAL_5]], %[[VAL_4]] : i32 + +subroutine test_negate_real(res, x) + real :: res, x + res = -x +end subroutine +! CHECK-LABEL: func.func @_QPtest_negate_real( +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}x"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! CHECK: %[[VAL_5:.*]] = arith.negf %[[VAL_4]] fastmath : f32 + +subroutine test_negate_complex(res, x) + complex :: res, x + res = -x +end subroutine +! CHECK-LABEL: func.func @_QPtest_negate_complex( +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}x"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref> +! CHECK: %[[VAL_5:.*]] = fir.negc %[[VAL_4]] : !fir.complex<4> + +subroutine test_complex_component_real(res, x) + real :: res + complex :: x + res = real(x) +end subroutine +! CHECK-LABEL: func.func @_QPtest_complex_component_real( +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}x"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref> +! CHECK: %[[VAL_5:.*]] = fir.extract_value %[[VAL_4]], [0 : index] : (!fir.complex<4>) -> f32 + +subroutine test_complex_component_imag(res, x) + real :: res + complex :: x + res = aimag(x) +end subroutine +! CHECK-LABEL: func.func @_QPtest_complex_component_imag( +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %{{.*}}x"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref> +! CHECK: %[[VAL_5:.*]] = fir.extract_value %[[VAL_4]], [1 : index] : (!fir.complex<4>) -> f32