[flang-commits] [flang] 5c42807 - [flang][hlfir] Fixed byval passing for dynamically optional intrinsic args.
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Tue Jul 11 09:40:54 PDT 2023
Author: Slava Zakharin
Date: 2023-07-11T09:40:08-07:00
New Revision: 5c428079047b5ef35f6452c6cd2b3fc3d4323a17
URL: https://github.com/llvm/llvm-project/commit/5c428079047b5ef35f6452c6cd2b3fc3d4323a17
DIFF: https://github.com/llvm/llvm-project/commit/5c428079047b5ef35f6452c6cd2b3fc3d4323a17.diff
LOG: [flang][hlfir] Fixed byval passing for dynamically optional intrinsic args.
In the context of elemental operation a dynamically optional
intrinsic argument must be lowered such that the elemental
designator is generated under isPresent check.
Reviewed By: tblah
Differential Revision: https://reviews.llvm.org/D154897
Added:
Modified:
flang/lib/Lower/ConvertCall.cpp
flang/test/Lower/HLFIR/intrinsic-dynamically-optional.f90
Removed:
################################################################################
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 9d746fa6dd194a..60ad5bd2347734 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -1192,20 +1192,26 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
return extendedValueToHlfirEntity(loc, builder, result, ".tmp.func_result");
}
-/// Create an optional dummy argument value from \p entity that may be
-/// absent. This can only be called with numerical or logical scalar \p entity.
-/// If \p entity is considered absent according to 15.5.2.12 point 1., the
-/// returned value is zero (or false), otherwise it is the value of \p entity.
+/// Create an optional dummy argument value from an entity that may be
+/// absent. \p actualGetter callback returns hlfir::Entity denoting
+/// the lowered actual argument. \p actualGetter can only return numerical
+/// or logical scalar entity.
+/// If the entity is considered absent according to 15.5.2.12 point 1., the
+/// returned value is zero (or false), otherwise it is the value of the entity.
+/// \p eleType specifies the entity's Fortran element type.
+template <typename T>
static ExvAndCleanup genOptionalValue(fir::FirOpBuilder &builder,
- mlir::Location loc, hlfir::Entity entity,
- mlir::Value isPresent) {
- mlir::Type eleType = entity.getFortranElementType();
- assert(entity.isScalar() && fir::isa_trivial(eleType) &&
- "must be a numerical or logical scalar");
+ mlir::Location loc, mlir::Type eleType,
+ T actualGetter, mlir::Value isPresent) {
return {builder
.genIfOp(loc, {eleType}, isPresent,
/*withElseRegion=*/true)
.genThen([&]() {
+ hlfir::Entity entity = actualGetter(loc, builder);
+ assert(eleType == entity.getFortranElementType() &&
+ "result type mismatch in genOptionalValue");
+ assert(entity.isScalar() && fir::isa_trivial(eleType) &&
+ "must be a numerical or logical scalar");
mlir::Value val =
hlfir::loadTrivialScalar(loc, builder, entity);
builder.create<fir::ResultOp>(loc, val);
@@ -1288,9 +1294,9 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
operands.emplace_back(fir::getAbsentIntrinsicArgument());
continue;
}
- hlfir::Entity actual = arg.value()->getActual(loc, builder);
if (!argLowering) {
// No argument lowering instruction, lower by value.
+ hlfir::Entity actual = arg.value()->getActual(loc, builder);
operands.emplace_back(
Fortran::lower::convertToValue(loc, converter, actual, stmtCtx));
continue;
@@ -1316,24 +1322,40 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
mlir::Value isPresent = arg.value()->getIsPresent();
switch (argRules.lowerAs) {
case fir::LowerIntrinsicArgAs::Value: {
- auto [exv, cleanup] = genOptionalValue(builder, loc, actual, isPresent);
+ // In case of elemental call, getActual() may produce
+ // a designator denoting the array element to be passed
+ // to the subprogram. If the actual array is dynamically
+ // optional the designator must be generated under
+ // isPresent check, because the box bounds reads will be
+ // generated in the codegen. These reads are illegal,
+ // if the dynamically optional argument is absent.
+ auto getActualCb = [&](mlir::Location loc,
+ fir::FirOpBuilder &builder) -> hlfir::Entity {
+ return arg.value()->getActual(loc, builder);
+ };
+ auto [exv, cleanup] =
+ genOptionalValue(builder, loc, getActualFortranElementType(),
+ getActualCb, isPresent);
addToCleanups(std::move(cleanup));
operands.emplace_back(exv);
continue;
}
case fir::LowerIntrinsicArgAs::Addr: {
+ hlfir::Entity actual = arg.value()->getActual(loc, builder);
auto [exv, cleanup] = genOptionalAddr(builder, loc, actual, isPresent);
addToCleanups(std::move(cleanup));
operands.emplace_back(exv);
continue;
}
case fir::LowerIntrinsicArgAs::Box: {
+ hlfir::Entity actual = arg.value()->getActual(loc, builder);
auto [exv, cleanup] = genOptionalBox(builder, loc, actual, isPresent);
addToCleanups(std::move(cleanup));
operands.emplace_back(exv);
continue;
}
case fir::LowerIntrinsicArgAs::Inquired: {
+ hlfir::Entity actual = arg.value()->getActual(loc, builder);
auto [exv, cleanup] =
hlfir::translateToExtendedValue(loc, builder, actual);
addToCleanups(std::move(cleanup));
@@ -1343,6 +1365,8 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
}
llvm_unreachable("bad switch");
}
+
+ hlfir::Entity actual = arg.value()->getActual(loc, builder);
switch (argRules.lowerAs) {
case fir::LowerIntrinsicArgAs::Value:
operands.emplace_back(
diff --git a/flang/test/Lower/HLFIR/intrinsic-dynamically-optional.f90 b/flang/test/Lower/HLFIR/intrinsic-dynamically-optional.f90
index 923d7735f3ec46..39671d7931a17a 100644
--- a/flang/test/Lower/HLFIR/intrinsic-dynamically-optional.f90
+++ b/flang/test/Lower/HLFIR/intrinsic-dynamically-optional.f90
@@ -153,5 +153,50 @@ subroutine test_optional_as_addr
! CHECK: return
! CHECK: }
+! imaginary component is dyamically optional, lowered as a value
+! Test placement of the designator under isPresent check.
+function test_elemental_optional_as_value(real, imaginary)
+ real :: real(3)
+ real, optional :: imaginary(3)
+ complex :: test_elemental_optional_as_value(3)
+ test_elemental_optional_as_value = cmplx(real, imaginary)
+end function
+! CHECK-LABEL: func.func @_QPtest_elemental_optional_as_value(
+! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.array<3xf32>> {fir.bindc_name = "real"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.array<3xf32>> {fir.bindc_name = "imaginary", fir.optional}) -> !fir.array<3x!fir.complex<4>> {
+! CHECK: %[[VAL_2:.*]] = arith.constant 3 : index
+! CHECK: %[[VAL_3:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_3]]) {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QFtest_elemental_optional_as_valueEimaginary"} : (!fir.ref<!fir.array<3xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3xf32>>, !fir.ref<!fir.array<3xf32>>)
+! CHECK: %[[VAL_5:.*]] = arith.constant 3 : index
+! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_0]](%[[VAL_6]]) {uniq_name = "_QFtest_elemental_optional_as_valueEreal"} : (!fir.ref<!fir.array<3xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3xf32>>, !fir.ref<!fir.array<3xf32>>)
+! CHECK: %[[VAL_8:.*]] = arith.constant 3 : index
+! CHECK: %[[VAL_9:.*]] = fir.alloca !fir.array<3x!fir.complex<4>> {bindc_name = "test_elemental_optional_as_value", uniq_name = "_QFtest_elemental_optional_as_valueEtest_elemental_optional_as_value"}
+! CHECK: %[[VAL_10:.*]] = fir.shape %[[VAL_8]] : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_9]](%[[VAL_10]]) {uniq_name = "_QFtest_elemental_optional_as_valueEtest_elemental_optional_as_value"} : (!fir.ref<!fir.array<3x!fir.complex<4>>>, !fir.shape<1>) -> (!fir.ref<!fir.array<3x!fir.complex<4>>>, !fir.ref<!fir.array<3x!fir.complex<4>>>)
+! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_4]]#0 : (!fir.ref<!fir.array<3xf32>>) -> i1
+! CHECK: %[[VAL_13:.*]] = hlfir.elemental %[[VAL_6]] unordered : (!fir.shape<1>) -> !hlfir.expr<3x!fir.complex<4>> {
+! CHECK: ^bb0(%[[VAL_14:.*]]: index):
+! CHECK: %[[VAL_15:.*]] = hlfir.designate %[[VAL_7]]#0 (%[[VAL_14]]) : (!fir.ref<!fir.array<3xf32>>, index) -> !fir.ref<f32>
+! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_15]] : !fir.ref<f32>
+! CHECK: %[[VAL_17:.*]] = fir.if %[[VAL_12]] -> (f32) {
+! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_4]]#0 (%[[VAL_14]]) : (!fir.ref<!fir.array<3xf32>>, index) -> !fir.ref<f32>
+! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_18]] : !fir.ref<f32>
+! CHECK: fir.result %[[VAL_19]] : f32
+! CHECK: } else {
+! CHECK: %[[VAL_20:.*]] = arith.constant 0.000000e+00 : f32
+! CHECK: fir.result %[[VAL_20]] : f32
+! CHECK: }
+! CHECK: %[[VAL_21:.*]] = fir.undefined !fir.complex<4>
+! CHECK: %[[VAL_22:.*]] = fir.insert_value %[[VAL_21]], %[[VAL_16]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+! CHECK: %[[VAL_23:.*]] = fir.insert_value %[[VAL_22]], %[[VAL_17]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
+! CHECK: hlfir.yield_element %[[VAL_23]] : !fir.complex<4>
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_11]]#0 : !hlfir.expr<3x!fir.complex<4>>, !fir.ref<!fir.array<3x!fir.complex<4>>>
+! CHECK: hlfir.destroy %[[VAL_13]] : !hlfir.expr<3x!fir.complex<4>>
+! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_11]]#1 : !fir.ref<!fir.array<3x!fir.complex<4>>>
+! CHECK: return %[[VAL_24]] : !fir.array<3x!fir.complex<4>>
+! CHECK: }
+
! TODO: there seem to be no intrinsics with dynamically optional arguments lowered asInquired
More information about the flang-commits
mailing list