From b668de2de2c2216a744454dd5144b35a68698031 Mon Sep 17 00:00:00 2001 From: Jean Perier Date: Tue, 20 Sep 2022 10:15:15 +0200 Subject: [PATCH] [flang] fix optional pointer TARGET argument lowering in ASSOCIATED The TARGET argument of ASSOCIATED has a special lowering to deal with POINTER and ALLOCATABLE optional actual arguments because they may be dynamically absent. The previous code was doing a ternary (mlir::SelectOp) to deal with this case, but generated invalid code for the unused argument (loading a nullptr fir.ref). This was not detected until D133779 was merged and modified how fir.load are lowered to LLVM for fir.box types. Replace the select by a proper if to prevent the fir.load from being reachable in context where it should not. Differential Revision: https://reviews.llvm.org/D134174 --- flang/lib/Lower/IntrinsicCall.cpp | 23 +++++++++--- flang/test/Lower/Intrinsics/associated.f90 | 58 +++++++++++++++++++----------- 2 files changed, 56 insertions(+), 25 deletions(-) diff --git a/flang/lib/Lower/IntrinsicCall.cpp b/flang/lib/Lower/IntrinsicCall.cpp index aa86215..cd5c1bb 100644 --- a/flang/lib/Lower/IntrinsicCall.cpp +++ b/flang/lib/Lower/IntrinsicCall.cpp @@ -2404,7 +2404,7 @@ IntrinsicLibrary::genAssociated(mlir::Type resultType, if (isStaticallyAbsent(target)) return fir::factory::genIsAllocatedOrAssociatedTest(builder, loc, *pointer); - mlir::Value targetBox = builder.createBox(loc, target); + mlir::Value targetBox; if (fir::valueHasFirAttribute(fir::getBase(target), fir::getOptionalAttrName())) { // Subtle: contrary to other intrinsic optional arguments, disassociated @@ -2416,11 +2416,26 @@ IntrinsicLibrary::genAssociated(mlir::Type resultType, // to rerun false. The runtime deals with the disassociated/unallocated // case. Simply ensures that TARGET that are OPTIONAL get conditionally // emboxed here to convey the optional aspect to the runtime. + mlir::Type boxType = fir::BoxType::get(builder.getNoneType()); auto isPresent = builder.create(loc, builder.getI1Type(), fir::getBase(target)); - auto absentBox = builder.create(loc, targetBox.getType()); - targetBox = builder.create(loc, isPresent, targetBox, - absentBox); + targetBox = builder + .genIfOp(loc, {boxType}, isPresent, + /*withElseRegion=*/true) + .genThen([&]() { + mlir::Value box = builder.createBox(loc, target); + mlir::Value cast = + builder.createConvert(loc, boxType, box); + builder.create(loc, cast); + }) + .genElse([&]() { + mlir::Value absentBox = + builder.create(loc, boxType); + builder.create(loc, absentBox); + }) + .getResults()[0]; + } else { + targetBox = builder.createBox(loc, target); } mlir::Value pointerBoxRef = fir::factory::getMutableIRBox(builder, loc, *pointer); diff --git a/flang/test/Lower/Intrinsics/associated.f90 b/flang/test/Lower/Intrinsics/associated.f90 index 5c78457..ae55a0a 100644 --- a/flang/test/Lower/Intrinsics/associated.f90 +++ b/flang/test/Lower/Intrinsics/associated.f90 @@ -47,15 +47,19 @@ subroutine associated_test(scalar, array) real, optional, target :: optionales_ziel(10) print *, associated(p, optionales_ziel) ! CHECK: %[[VAL_2:.*]] = arith.constant 10 : index - ! CHECK: %[[VAL_8:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> - ! CHECK: %[[VAL_9:.*]] = fir.embox %[[VAL_1]](%[[VAL_8]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> - ! CHECK: %[[VAL_10:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 - ! CHECK: %[[VAL_11:.*]] = fir.absent !fir.box> - ! CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_10]], %[[VAL_9]], %[[VAL_11]] : !fir.box> + ! CHECK: %[[VAL_3:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>) -> i1 + ! CHECK: %[[VAL_4:.*]] = fir.if %[[VAL_3]] -> (!fir.box) { + ! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1> + ! CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_1]](%[[VAL_5]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> + ! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.box>) -> !fir.box + ! CHECK: fir.result %[[VAL_7]] : !fir.box + ! CHECK: } else { + ! CHECK: %[[VAL_8:.*]] = fir.absent !fir.box + ! CHECK: fir.result %[[VAL_8]] : !fir.box + ! CHECK: } ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_0]] : !fir.ref>>> ! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.box>>) -> !fir.box - ! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_12]] : (!fir.box>) -> !fir.box - ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_14]], %[[VAL_15]]) : (!fir.box, !fir.box) -> i1 + ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_14]], %[[VAL_4]]) : (!fir.box, !fir.box) -> i1 end subroutine ! CHECK-LABEL: func @_QPtest_optional_target_2( @@ -66,12 +70,16 @@ subroutine associated_test(scalar, array) real, optional, target :: optionales_ziel(:) print *, associated(p, optionales_ziel) ! CHECK: %[[VAL_7:.*]] = fir.is_present %[[VAL_1]] : (!fir.box>) -> i1 - ! CHECK: %[[VAL_8:.*]] = fir.absent !fir.box> - ! CHECK: %[[VAL_9:.*]] = arith.select %[[VAL_7]], %[[VAL_1]], %[[VAL_8]] : !fir.box> + ! CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_7]] -> (!fir.box) { + ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_1]] : (!fir.box>) -> !fir.box + ! CHECK: fir.result %[[VAL_9]] : !fir.box + ! CHECK: } else { + ! CHECK: %[[VAL_10:.*]] = fir.absent !fir.box + ! CHECK: fir.result %[[VAL_10]] : !fir.box + ! CHECK: } ! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_0]] : !fir.ref>>> ! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.box>>) -> !fir.box - ! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_9]] : (!fir.box>) -> !fir.box - ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_11]], %[[VAL_12]]) : (!fir.box, !fir.box) -> i1 + ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_11]], %[[VAL_8]]) : (!fir.box, !fir.box) -> i1 end subroutine ! CHECK-LABEL: func @_QPtest_optional_target_3( @@ -81,14 +89,18 @@ subroutine associated_test(scalar, array) real, pointer :: p(:) real, optional, pointer :: optionales_ziel(:) print *, associated(p, optionales_ziel) - ! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_1]] : !fir.ref>>> ! CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>>>) -> i1 - ! CHECK: %[[VAL_9:.*]] = fir.absent !fir.box>> - ! CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_8]], %[[VAL_7]], %[[VAL_9]] : !fir.box>> + ! CHECK: %[[VAL_9:.*]] = fir.if %[[VAL_8]] -> (!fir.box) { + ! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_1]] : !fir.ref>>> + ! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.box>>) -> !fir.box + ! CHECK: fir.result %[[VAL_11]] : !fir.box + ! CHECK: } else { + ! CHECK: %[[VAL_12:.*]] = fir.absent !fir.box + ! CHECK: fir.result %[[VAL_12]] : !fir.box + ! CHECK: } ! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_0]] : !fir.ref>>> ! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.box>>) -> !fir.box - ! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (!fir.box>>) -> !fir.box - ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_12]], %[[VAL_13]]) : (!fir.box, !fir.box) -> i1 + ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_12]], %[[VAL_9]]) : (!fir.box, !fir.box) -> i1 end subroutine ! CHECK-LABEL: func @_QPtest_optional_target_4( @@ -98,14 +110,18 @@ subroutine associated_test(scalar, array) real, pointer :: p(:) real, optional, allocatable, target :: optionales_ziel(:) print *, associated(p, optionales_ziel) - ! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_1]] : !fir.ref>>> ! CHECK: %[[VAL_8:.*]] = fir.is_present %[[VAL_1]] : (!fir.ref>>>) -> i1 - ! CHECK: %[[VAL_9:.*]] = fir.absent !fir.box>> - ! CHECK: %[[VAL_10:.*]] = arith.select %[[VAL_8]], %[[VAL_7]], %[[VAL_9]] : !fir.box>> + ! CHECK: %[[VAL_9:.*]] = fir.if %[[VAL_8]] -> (!fir.box) { + ! CHECK: %[[VAL_10:.*]] = fir.load %[[VAL_1]] : !fir.ref>>> + ! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.box>>) -> !fir.box + ! CHECK: fir.result %[[VAL_11]] : !fir.box + ! CHECK: } else { + ! CHECK: %[[VAL_12:.*]] = fir.absent !fir.box + ! CHECK: fir.result %[[VAL_12]] : !fir.box + ! CHECK: } ! CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_0]] : !fir.ref>>> ! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.box>>) -> !fir.box - ! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_10]] : (!fir.box>>) -> !fir.box - ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_12]], %[[VAL_13]]) : (!fir.box, !fir.box) -> i1 + ! CHECK: fir.call @_FortranAPointerIsAssociatedWith(%[[VAL_12]], %[[VAL_9]]) : (!fir.box, !fir.box) -> i1 end subroutine ! CHECK-LABEL: func @_QPtest_pointer_target( -- 2.7.4