diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -2983,6 +2983,42 @@ } } + /// 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()) + return nullptr; + if (!toTy.isa()) + 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 @@ // 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( loc, rhs, lhs, isWholeAllocatableAssignment, keepLhsLengthInAllocatableAssignment); + + // Mark the end of life range of the ElementalOp's result. + if (logicalConvert && + logicalConvert.getType().isa()) + builder.create(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 --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -105,7 +105,6 @@ rhsType = fir::LogicalType::get(builder.getContext(), 4); rhsVal = builder.createConvert(loc, rhsType, rhsVal); } - mlir::Value temp = builder.create(loc, rhsType); builder.create(loc, rhsVal, temp); rhsExv = temp; diff --git a/flang/test/Lower/HLFIR/assignment-intrinsics.f90 b/flang/test/Lower/HLFIR/assignment-intrinsics.f90 --- a/flang/test/Lower/HLFIR/assignment-intrinsics.f90 +++ b/flang/test/Lower/HLFIR/assignment-intrinsics.f90 @@ -74,7 +74,8 @@ ! CHECK-LABEL: func.func @_QPscalar_logical_2( ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFscalar_logical_2Ex"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_2:.*]] = arith.constant true -! CHECK: hlfir.assign %[[VAL_2]] to %[[VAL_1]]#0 : i1, !fir.ref> +! 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> 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 --- a/flang/test/Lower/HLFIR/expr-as-inquired.f90 +++ b/flang/test/Lower/HLFIR/expr-as-inquired.f90 @@ -16,7 +16,8 @@ ! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (!fir.heap>) -> 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> +! 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> ! 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 --- /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 {fir.bindc_name = "x"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest1Ex"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest1Ey"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref> +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.logical<4>) -> i32 +! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_2]]#0 : i32, !fir.ref +! 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 {fir.bindc_name = "x"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest2Ex"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest2Ey"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_2]]#0 : !fir.ref +! 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> +! 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.bindc_name = "x"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "y"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest3Ex"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest3Ey"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! 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> +! 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 {fir.bindc_name = "x"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "y"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest4Ex"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest4Ey"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref +! 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 +! 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.bindc_name = "x"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest5Ex"} : (!fir.box>) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest5Ey"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref> +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.logical<4>) -> i32 +! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_2]]#0 : i32, !fir.box> +! 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.bindc_name = "x"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.box>> {fir.bindc_name = "y"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest6Ex"} : (!fir.box>) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest6Ey"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) +! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_4]] : (!fir.box>>, 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 { +! CHECK: ^bb0(%[[VAL_8:.*]]: index): +! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_8]]) : (!fir.box>>, index) -> !fir.ref> +! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_9]] : !fir.ref> +! 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, !fir.box> +! CHECK: hlfir.destroy %[[VAL_12]] : !hlfir.expr +! 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.bindc_name = "x"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.box> {fir.bindc_name = "y"}) { +! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest7Ex"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFtest7Ey"} : (!fir.box>) -> (!fir.box>, !fir.box>) +! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_4]] : (!fir.box>, 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> { +! CHECK: ^bb0(%[[VAL_8:.*]]: index): +! CHECK: %[[VAL_9:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_8]]) : (!fir.box>, index) -> !fir.ref +! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_9]] : !fir.ref +! 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>, !fir.box>> +! CHECK: hlfir.destroy %[[VAL_12]] : !hlfir.expr> +! CHECK: return +! CHECK: } +subroutine test7(x, y) + logical :: x(:) + integer :: y(:) + x = y +end subroutine test7