[flang-commits] [flang] 12c8797 - [flang] Lower unary operation to HLFIR
Jean Perier via flang-commits
flang-commits at lists.llvm.org
Fri Dec 2 05:23:07 PST 2022
Author: Jean Perier
Date: 2022-12-02T14:22:41+01:00
New Revision: 12c8797fc4ed5a4068034c50af734f06d00c90ab
URL: https://github.com/llvm/llvm-project/commit/12c8797fc4ed5a4068034c50af734f06d00c90ab
DIFF: https://github.com/llvm/llvm-project/commit/12c8797fc4ed5a4068034c50af734f06d00c90ab.diff
LOG: [flang] Lower unary operation to HLFIR
Lower not, negate, and complex component to HLFIR.
Parentheses is the only remaining operation, but needs some
care/thinking to properly deal with character/derived variables.
Differential Revision: https://reviews.llvm.org/D139186
Added:
flang/test/Lower/HLFIR/unary-ops.f90
Modified:
flang/lib/Lower/ConvertExprToHLFIR.cpp
Removed:
################################################################################
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index f2e47ee96070..6eeafffe7942 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -506,6 +506,91 @@ struct BinaryOp<Fortran::evaluate::SetLength<KIND>> {
}
};
+//===--------------------------------------------------------------------===//
+// Unary Operation implementation
+//===--------------------------------------------------------------------===//
+
+template <typename T>
+struct UnaryOp {};
+
+template <int KIND>
+struct UnaryOp<Fortran::evaluate::Not<KIND>> {
+ using Op = Fortran::evaluate::Not<KIND>;
+ 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<mlir::arith::XOrIOp>(loc, val, one)};
+ }
+};
+
+template <int KIND>
+struct UnaryOp<Fortran::evaluate::Negate<
+ Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>> {
+ using Op = Fortran::evaluate::Negate<
+ Fortran::evaluate::Type<Fortran::common::TypeCategory::Integer, KIND>>;
+ 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<mlir::arith::SubIOp>(loc, zero, lhs)};
+ }
+};
+
+template <int KIND>
+struct UnaryOp<Fortran::evaluate::Negate<
+ Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>> {
+ using Op = Fortran::evaluate::Negate<
+ Fortran::evaluate::Type<Fortran::common::TypeCategory::Real, KIND>>;
+ static hlfir::EntityWithAttributes gen(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ const Op &op, hlfir::Entity lhs) {
+ return hlfir::EntityWithAttributes{
+ builder.create<mlir::arith::NegFOp>(loc, lhs)};
+ }
+};
+
+template <int KIND>
+struct UnaryOp<Fortran::evaluate::Negate<
+ Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>> {
+ using Op = Fortran::evaluate::Negate<
+ Fortran::evaluate::Type<Fortran::common::TypeCategory::Complex, KIND>>;
+ static hlfir::EntityWithAttributes gen(mlir::Location loc,
+ fir::FirOpBuilder &builder,
+ const Op &op, hlfir::Entity lhs) {
+ return hlfir::EntityWithAttributes{builder.create<fir::NegcOp>(loc, lhs)};
+ }
+};
+
+template <int KIND>
+struct UnaryOp<Fortran::evaluate::ComplexComponent<KIND>> {
+ using Op = Fortran::evaluate::ComplexComponent<KIND>;
+ 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 <typename T>
+struct UnaryOp<Fortran::evaluate::Parentheses<T>> {
+ using Op = Fortran::evaluate::Parentheses<T>;
+ 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 @@ class HlfirBuilder {
template <typename D, typename R, typename O>
hlfir::EntityWithAttributes
gen(const Fortran::evaluate::Operation<D, R, O> &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<D>::gen(loc, builder, op.derived(), left);
}
template <typename D, typename R, typename LO, typename RO>
diff --git a/flang/test/Lower/HLFIR/unary-ops.f90 b/flang/test/Lower/HLFIR/unary-ops.f90
new file mode 100644
index 000000000000..148491c6ebd9
--- /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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.logical<4>>
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
+! 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<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<f32>
+! CHECK: %[[VAL_5:.*]] = arith.negf %[[VAL_4]] fastmath<contract> : 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.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.complex<4>>
+! 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.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.complex<4>>
+! 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.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.complex<4>>
+! CHECK: %[[VAL_5:.*]] = fir.extract_value %[[VAL_4]], [1 : index] : (!fir.complex<4>) -> f32
More information about the flang-commits
mailing list