[flang-commits] [flang] ec2c0e0 - [flang][hlfir] Generate explicit HLFIR type cast for implicit logical<->integer conversion.
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Thu May 4 09:19:20 PDT 2023
Author: Slava Zakharin
Date: 2023-05-04T09:19:13-07:00
New Revision: ec2c0e0f55637209d1901c73f162dd8625034a56
URL: https://github.com/llvm/llvm-project/commit/ec2c0e0f55637209d1901c73f162dd8625034a56
DIFF: https://github.com/llvm/llvm-project/commit/ec2c0e0f55637209d1901c73f162dd8625034a56.diff
LOG: [flang][hlfir] Generate explicit HLFIR type cast for implicit logical<->integer conversion.
hlfir.assign, in general, ends up calling the Assign runtime that asserts
that the types of LHS and RHS match. In case of implicit logical<->integer
conversions (allowed as an extension) the operands of hlfir.assign
have non-matching types. This change makes sure that the lowering
produces explicit type cast (either as a scalar fir.convert or
as a hlfir.elemental producing array expression).
Reviewed By: jeanPerier
Differential Revision: https://reviews.llvm.org/D149765
Added:
flang/test/Lower/HLFIR/implicit-type-conversion.f90
Modified:
flang/lib/Lower/Bridge.cpp
flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
flang/test/Lower/HLFIR/assignment-intrinsics.f90
flang/test/Lower/HLFIR/expr-as-inquired.f90
Removed:
################################################################################
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index f5b581c881c1..fdc664997247 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2983,6 +2983,42 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
}
+ /// Given converted LHS and RHS of the assignment, generate
+ /// explicit type conversion for implicit Logical<->Integer
+ /// conversion. Return Value representing the converted RHS,
+ /// if the implicit Logical<->Integer is detected, otherwise,
+ /// return nullptr. The caller is responsible for inserting
+ /// DestroyOp in case the returned value has hlfir::ExprType.
+ mlir::Value
+ genImplicitLogicalConvert(const Fortran::evaluate::Assignment &assign,
+ hlfir::Entity lhs, hlfir::Entity rhs) {
+ mlir::Type fromTy = rhs.getFortranElementType();
+ mlir::Type toTy = lhs.getFortranElementType();
+ if (fromTy == toTy)
+ return nullptr;
+
+ if (!fromTy.isa<mlir::IntegerType, fir::LogicalType>())
+ return nullptr;
+ if (!toTy.isa<mlir::IntegerType, fir::LogicalType>())
+ return nullptr;
+
+ mlir::Location loc = toLocation();
+ auto &builder = getFirOpBuilder();
+ if (assign.rhs.Rank() == 0)
+ return builder.createConvert(loc, toTy, rhs);
+
+ mlir::Value shape = hlfir::genShape(loc, builder, rhs);
+ auto genKernel =
+ [&rhs, &toTy](mlir::Location loc, fir::FirOpBuilder &builder,
+ mlir::ValueRange oneBasedIndices) -> hlfir::Entity {
+ auto elementPtr = hlfir::getElementAt(loc, builder, rhs, oneBasedIndices);
+ auto val = hlfir::loadTrivialScalar(loc, builder, elementPtr);
+ return hlfir::EntityWithAttributes{builder.createConvert(loc, toTy, val)};
+ };
+ return hlfir::genElementalOp(loc, builder, toTy, shape, /*typeParams=*/{},
+ genKernel);
+ }
+
/// Shared for both assignments and pointer assignments.
void genAssignment(const Fortran::evaluate::Assignment &assign) {
mlir::Location loc = toLocation();
@@ -3020,9 +3056,24 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// Dereference pointer LHS: the target is being assigned to.
lhs = hlfir::derefPointersAndAllocatables(loc, builder, lhs);
}
+
+ // Logical<->Integer assignments are allowed as an extension,
+ // but there is no explicit Convert expression for the RHS.
+ // Recognize the type mismatch here and insert explicit
+ // scalar convert or ElementalOp for array assignment.
+ mlir::Value logicalConvert =
+ genImplicitLogicalConvert(assign, lhs, rhs);
+ if (logicalConvert)
+ rhs = hlfir::EntityWithAttributes{logicalConvert};
+
builder.create<hlfir::AssignOp>(
loc, rhs, lhs, isWholeAllocatableAssignment,
keepLhsLengthInAllocatableAssignment);
+
+ // Mark the end of life range of the ElementalOp's result.
+ if (logicalConvert &&
+ logicalConvert.getType().isa<hlfir::ExprType>())
+ builder.create<hlfir::DestroyOp>(loc, rhs);
},
// [2] User defined assignment. If the context is a scalar
// expression then call the procedure.
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 7bff80557115..0225ac3631b9 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -105,7 +105,6 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
rhsType = fir::LogicalType::get(builder.getContext(), 4);
rhsVal = builder.createConvert(loc, rhsType, rhsVal);
}
-
mlir::Value temp = builder.create<fir::AllocaOp>(loc, rhsType);
builder.create<fir::StoreOp>(loc, rhsVal, temp);
rhsExv = temp;
diff --git a/flang/test/Lower/HLFIR/assignment-intrinsics.f90 b/flang/test/Lower/HLFIR/assignment-intrinsics.f90
index 78b708385721..169e5fa4b702 100644
--- a/flang/test/Lower/HLFIR/assignment-intrinsics.f90
+++ b/flang/test/Lower/HLFIR/assignment-intrinsics.f90
@@ -74,7 +74,8 @@ subroutine scalar_logical_2(x)
! CHECK-LABEL: func.func @_QPscalar_logical_2(
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFscalar_logical_2Ex"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
! CHECK: %[[VAL_2:.*]] = arith.constant true
-! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_1]]#0 : i1, !fir.ref<!fir.logical<4>>
+! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (i1) -> !fir.logical<4>
+! CHECK: hlfir.assign %[[VAL_3]] to %[[VAL_1]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
subroutine scalar_real_2(x)
real :: x
diff --git a/flang/test/Lower/HLFIR/expr-as-inquired.f90 b/flang/test/Lower/HLFIR/expr-as-inquired.f90
index 9dac1006649e..8543921ca242 100644
--- a/flang/test/Lower/HLFIR/expr-as-inquired.f90
+++ b/flang/test/Lower/HLFIR/expr-as-inquired.f90
@@ -16,7 +16,8 @@ subroutine test_isAllocated(x, l)
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (!fir.heap<!fir.array<?xf32>>) -> i64
! CHECK: %[[VAL_7:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_8:.*]] = arith.cmpi ne, %[[VAL_6]], %[[VAL_7]] : i64
-! CHECK: hlfir.assign %[[VAL_8]] to %[[VAL_2]]#0 : i1, !fir.ref<!fir.logical<4>>
+! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4>
+! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_2]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
! CHECK: return
! CHECK: }
diff --git a/flang/test/Lower/HLFIR/implicit-type-conversion.f90 b/flang/test/Lower/HLFIR/implicit-type-conversion.f90
new file mode 100644
index 000000000000..66bf7f81f78d
--- /dev/null
+++ b/flang/test/Lower/HLFIR/implicit-type-conversion.f90
@@ -0,0 +1,137 @@
+! RUN: bbc -emit-fir -hlfir %s -o - | FileCheck %s
+
+! CHECK-LABEL: func.func @_QPtest1(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest1Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest1Ey"} : (!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:.*]] = fir.convert %[[VAL_4]] : (!fir.logical<4>) -> i32
+! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_2]]#0 : i32, !fir.ref<i32>
+! CHECK: return
+! CHECK: }
+subroutine test1(x, y)
+ integer :: x
+ logical :: y
+ x = y
+end subroutine test1
+
+! CHECK-LABEL: func.func @_QPtest2(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest2Ey"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref<i32>
+! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i32) -> !fir.logical<4>
+! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_3]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+! CHECK: return
+! CHECK: }
+subroutine test2(x, y)
+ integer :: x
+ logical :: y
+ y = x
+end subroutine test2
+
+! CHECK-LABEL: func.func @_QPtest3(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i32> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest3Ex"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest3Ey"} : (!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 1 : i32
+! CHECK: %[[VAL_6:.*]] = arith.cmpi eq, %[[VAL_4]], %[[VAL_5]] : i32
+! CHECK: %[[VAL_7:.*]] = hlfir.no_reassoc %[[VAL_6]] : i1
+! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i1) -> !fir.logical<4>
+! CHECK: hlfir.assign %[[VAL_8]] to %[[VAL_2]]#0 : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+! CHECK: return
+! CHECK: }
+subroutine test3(x, y)
+ logical :: x
+ integer :: y
+ x = (y.eq.1)
+end subroutine test3
+
+! CHECK-LABEL: func.func @_QPtest4(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i32> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest4Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest4Ey"} : (!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 1 : i32
+! CHECK: %[[VAL_6:.*]] = arith.cmpi eq, %[[VAL_4]], %[[VAL_5]] : i32
+! CHECK: %[[VAL_7:.*]] = hlfir.no_reassoc %[[VAL_6]] : i1
+! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i1) -> i32
+! CHECK: hlfir.assign %[[VAL_8]] to %[[VAL_2]]#0 : i32, !fir.ref<i32>
+! CHECK: return
+! CHECK: }
+subroutine test4(x, y)
+ integer :: x
+ integer :: y
+ x = (y.eq.1)
+end subroutine test4
+
+! CHECK-LABEL: func.func @_QPtest5(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.logical<4>> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest5Ex"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest5Ey"} : (!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:.*]] = fir.convert %[[VAL_4]] : (!fir.logical<4>) -> i32
+! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_2]]#0 : i32, !fir.box<!fir.array<?xi32>>
+! CHECK: return
+! CHECK: }
+subroutine test5(x, y)
+ integer :: x(:)
+ logical :: y
+ x = y
+end subroutine test5
+
+! CHECK-LABEL: func.func @_QPtest6(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?x!fir.logical<4>>> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest6Ex"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest6Ey"} : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> (!fir.box<!fir.array<?x!fir.logical<4>>>, !fir.box<!fir.array<?x!fir.logical<4>>>)
+! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_4]] : (!fir.box<!fir.array<?x!fir.logical<4>>>, index) -> (index, index, index)
+! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_7:.*]] = hlfir.elemental %[[VAL_6]] : (!fir.shape<1>) -> !hlfir.expr<?xi32> {
+! CHECK: ^bb0(%[[VAL_8:.*]]: index):
+! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_8]]) : (!fir.box<!fir.array<?x!fir.logical<4>>>, index) -> !fir.ref<!fir.logical<4>>
+! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_9]] : !fir.ref<!fir.logical<4>>
+! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.logical<4>) -> i32
+! CHECK: hlfir.yield_element %[[VAL_11]] : i32
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_12:.*]] to %[[VAL_2]]#0 : !hlfir.expr<?xi32>, !fir.box<!fir.array<?xi32>>
+! CHECK: hlfir.destroy %[[VAL_12]] : !hlfir.expr<?xi32>
+! CHECK: return
+! CHECK: }
+subroutine test6(x, y)
+ integer :: x(:)
+ logical :: y(:)
+ x = y
+end subroutine test6
+
+! CHECK-LABEL: func.func @_QPtest7(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?x!fir.logical<4>>> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "y"}) {
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest7Ex"} : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> (!fir.box<!fir.array<?x!fir.logical<4>>>, !fir.box<!fir.array<?x!fir.logical<4>>>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest7Ey"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_4]] : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
+! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_7:.*]] = hlfir.elemental %[[VAL_6]] : (!fir.shape<1>) -> !hlfir.expr<?x!fir.logical<4>> {
+! CHECK: ^bb0(%[[VAL_8:.*]]: index):
+! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_8]]) : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_9]] : !fir.ref<i32>
+! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i32) -> !fir.logical<4>
+! CHECK: hlfir.yield_element %[[VAL_11]] : !fir.logical<4>
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_12:.*]] to %[[VAL_2]]#0 : !hlfir.expr<?x!fir.logical<4>>, !fir.box<!fir.array<?x!fir.logical<4>>>
+! CHECK: hlfir.destroy %[[VAL_12]] : !hlfir.expr<?x!fir.logical<4>>
+! CHECK: return
+! CHECK: }
+subroutine test7(x, y)
+ logical :: x(:)
+ integer :: y(:)
+ x = y
+end subroutine test7
More information about the flang-commits
mailing list