Skip to content

Commit 6f7e715

Browse files
authored
[flang] Don't inject possibly invalid conversions while folding (#100842)
A couple of intrinsic functions have optional arguments. Don't insert type conversions on those arguments when the actual arguments may not be present at execution time, due to being OPTIONAL, allocatables, or pointers.
1 parent ed5a78a commit 6f7e715

File tree

5 files changed

+68
-27
lines changed

5 files changed

+68
-27
lines changed

flang/lib/Evaluate/fold-character.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
9797
return Expr<T>{Constant<T>{CharacterUtils<KIND>::NEW_LINE()}};
9898
} else if (name == "repeat") { // not elemental
9999
if (auto scalars{GetScalarConstantArguments<T, SubscriptInteger>(
100-
context, funcRef.arguments())}) {
100+
context, funcRef.arguments(), /*hasOptionalArgument=*/false)}) {
101101
auto str{std::get<Scalar<T>>(*scalars)};
102102
auto n{std::get<Scalar<SubscriptInteger>>(*scalars).ToInt64()};
103103
if (n < 0) {
@@ -117,8 +117,8 @@ Expr<Type<TypeCategory::Character, KIND>> FoldIntrinsicFunction(
117117
}
118118
}
119119
} else if (name == "trim") { // not elemental
120-
if (auto scalar{
121-
GetScalarConstantArguments<T>(context, funcRef.arguments())}) {
120+
if (auto scalar{GetScalarConstantArguments<T>(
121+
context, funcRef.arguments(), /*hasOptionalArgument=*/false)}) {
122122
return Expr<T>{Constant<T>{
123123
CharacterUtils<KIND>::TRIM(std::get<Scalar<T>>(*scalar))}};
124124
}

flang/lib/Evaluate/fold-implementation.h

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ static constexpr bool useKahanSummation{false};
5454
// Utilities
5555
template <typename T> class Folder {
5656
public:
57-
explicit Folder(FoldingContext &c) : context_{c} {}
57+
explicit Folder(FoldingContext &c, bool forOptionalArgument = false)
58+
: context_{c}, forOptionalArgument_{forOptionalArgument} {}
5859
std::optional<Constant<T>> GetNamedConstant(const Symbol &);
5960
std::optional<Constant<T>> ApplySubscripts(const Constant<T> &array,
6061
const std::vector<Constant<SubscriptInteger>> &subscripts);
@@ -81,6 +82,7 @@ template <typename T> class Folder {
8182

8283
private:
8384
FoldingContext &context_;
85+
bool forOptionalArgument_{false};
8486
};
8587

8688
std::optional<Constant<SubscriptInteger>> GetConstantSubscript(
@@ -407,7 +409,14 @@ Constant<T> *Folder<T>::Folding(std::optional<ActualArgument> &arg) {
407409
if (auto *expr{UnwrapExpr<Expr<SomeType>>(arg)}) {
408410
if constexpr (T::category != TypeCategory::Derived) {
409411
if (!UnwrapExpr<Expr<T>>(*expr)) {
410-
if (auto converted{ConvertToType(T::GetType(), std::move(*expr))}) {
412+
if (const Symbol *
413+
var{forOptionalArgument_
414+
? UnwrapWholeSymbolOrComponentDataRef(*expr)
415+
: nullptr};
416+
var && (IsOptional(*var) || IsAllocatableOrObjectPointer(var))) {
417+
// can't safely convert item that may not be present
418+
} else if (auto converted{
419+
ConvertToType(T::GetType(), std::move(*expr))}) {
411420
*expr = Fold(context_, std::move(*converted));
412421
}
413422
}
@@ -420,10 +429,10 @@ Constant<T> *Folder<T>::Folding(std::optional<ActualArgument> &arg) {
420429
template <typename... A, std::size_t... I>
421430
std::optional<std::tuple<const Constant<A> *...>> GetConstantArgumentsHelper(
422431
FoldingContext &context, ActualArguments &arguments,
423-
std::index_sequence<I...>) {
432+
bool hasOptionalArgument, std::index_sequence<I...>) {
424433
static_assert(sizeof...(A) > 0);
425434
std::tuple<const Constant<A> *...> args{
426-
Folder<A>{context}.Folding(arguments.at(I))...};
435+
Folder<A>{context, hasOptionalArgument}.Folding(arguments.at(I))...};
427436
if ((... && (std::get<I>(args)))) {
428437
return args;
429438
} else {
@@ -433,15 +442,17 @@ std::optional<std::tuple<const Constant<A> *...>> GetConstantArgumentsHelper(
433442

434443
template <typename... A>
435444
std::optional<std::tuple<const Constant<A> *...>> GetConstantArguments(
436-
FoldingContext &context, ActualArguments &args) {
445+
FoldingContext &context, ActualArguments &args, bool hasOptionalArgument) {
437446
return GetConstantArgumentsHelper<A...>(
438-
context, args, std::index_sequence_for<A...>{});
447+
context, args, hasOptionalArgument, std::index_sequence_for<A...>{});
439448
}
440449

441450
template <typename... A, std::size_t... I>
442451
std::optional<std::tuple<Scalar<A>...>> GetScalarConstantArgumentsHelper(
443-
FoldingContext &context, ActualArguments &args, std::index_sequence<I...>) {
444-
if (auto constArgs{GetConstantArguments<A...>(context, args)}) {
452+
FoldingContext &context, ActualArguments &args, bool hasOptionalArgument,
453+
std::index_sequence<I...>) {
454+
if (auto constArgs{
455+
GetConstantArguments<A...>(context, args, hasOptionalArgument)}) {
445456
return std::tuple<Scalar<A>...>{
446457
std::get<I>(*constArgs)->GetScalarValue().value()...};
447458
} else {
@@ -451,9 +462,9 @@ std::optional<std::tuple<Scalar<A>...>> GetScalarConstantArgumentsHelper(
451462

452463
template <typename... A>
453464
std::optional<std::tuple<Scalar<A>...>> GetScalarConstantArguments(
454-
FoldingContext &context, ActualArguments &args) {
465+
FoldingContext &context, ActualArguments &args, bool hasOptionalArgument) {
455466
return GetScalarConstantArgumentsHelper<A...>(
456-
context, args, std::index_sequence_for<A...>{});
467+
context, args, hasOptionalArgument, std::index_sequence_for<A...>{});
457468
}
458469

459470
// helpers to fold intrinsic function references
@@ -470,9 +481,10 @@ template <template <typename, typename...> typename WrapperType, typename TR,
470481
typename... TA, std::size_t... I>
471482
Expr<TR> FoldElementalIntrinsicHelper(FoldingContext &context,
472483
FunctionRef<TR> &&funcRef, WrapperType<TR, TA...> func,
473-
std::index_sequence<I...>) {
484+
bool hasOptionalArgument, std::index_sequence<I...>) {
474485
if (std::optional<std::tuple<const Constant<TA> *...>> args{
475-
GetConstantArguments<TA...>(context, funcRef.arguments())}) {
486+
GetConstantArguments<TA...>(
487+
context, funcRef.arguments(), hasOptionalArgument)}) {
476488
// Compute the shape of the result based on shapes of arguments
477489
ConstantSubscripts shape;
478490
int rank{0};
@@ -542,15 +554,19 @@ Expr<TR> FoldElementalIntrinsicHelper(FoldingContext &context,
542554

543555
template <typename TR, typename... TA>
544556
Expr<TR> FoldElementalIntrinsic(FoldingContext &context,
545-
FunctionRef<TR> &&funcRef, ScalarFunc<TR, TA...> func) {
546-
return FoldElementalIntrinsicHelper<ScalarFunc, TR, TA...>(
547-
context, std::move(funcRef), func, std::index_sequence_for<TA...>{});
557+
FunctionRef<TR> &&funcRef, ScalarFunc<TR, TA...> func,
558+
bool hasOptionalArgument = false) {
559+
return FoldElementalIntrinsicHelper<ScalarFunc, TR, TA...>(context,
560+
std::move(funcRef), func, hasOptionalArgument,
561+
std::index_sequence_for<TA...>{});
548562
}
549563
template <typename TR, typename... TA>
550564
Expr<TR> FoldElementalIntrinsic(FoldingContext &context,
551-
FunctionRef<TR> &&funcRef, ScalarFuncWithContext<TR, TA...> func) {
552-
return FoldElementalIntrinsicHelper<ScalarFuncWithContext, TR, TA...>(
553-
context, std::move(funcRef), func, std::index_sequence_for<TA...>{});
565+
FunctionRef<TR> &&funcRef, ScalarFuncWithContext<TR, TA...> func,
566+
bool hasOptionalArgument = false) {
567+
return FoldElementalIntrinsicHelper<ScalarFuncWithContext, TR, TA...>(context,
568+
std::move(funcRef), func, hasOptionalArgument,
569+
std::index_sequence_for<TA...>{});
554570
}
555571

556572
std::optional<std::int64_t> GetInt64ArgOr(

flang/lib/Evaluate/fold-integer.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,8 @@ template <WhichLocation WHICH> class LocationHelper {
347347
bool back{false};
348348
if (arg_[backArg]) {
349349
const auto *backConst{
350-
Folder<LogicalResult>{context_}.Folding(arg_[backArg])};
350+
Folder<LogicalResult>{context_, /*forOptionalArgument=*/true}.Folding(
351+
arg_[backArg])};
351352
if (backConst) {
352353
back = backConst->GetScalarValue().value().IsTrue();
353354
} else {
@@ -910,8 +911,10 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
910911
const auto *argCon{Folder<T>(context).Folding(args[0])};
911912
const auto *shiftCon{Folder<Int4>(context).Folding(args[1])};
912913
const auto *shiftVals{shiftCon ? &shiftCon->values() : nullptr};
913-
const auto *sizeCon{
914-
args.size() == 3 ? Folder<Int4>(context).Folding(args[2]) : nullptr};
914+
const auto *sizeCon{args.size() == 3
915+
? Folder<Int4>{context, /*forOptionalArgument=*/true}.Folding(
916+
args[2])
917+
: nullptr};
915918
const auto *sizeVals{sizeCon ? &sizeCon->values() : nullptr};
916919
if ((argCon && argCon->empty()) || !shiftVals || shiftVals->empty() ||
917920
(sizeVals && sizeVals->empty())) {
@@ -985,7 +988,8 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
985988
auto shiftVal{static_cast<int>(shift.ToInt64())};
986989
auto sizeVal{static_cast<int>(size.ToInt64())};
987990
return i.ISHFTC(shiftVal, sizeVal);
988-
}));
991+
}),
992+
/*hasOptionalArgument=*/true);
989993
}
990994
} else if (name == "izext" || name == "jzext") {
991995
if (args.size() == 1) {

flang/lib/Evaluate/fold-real.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ static Expr<T> FoldTransformationalBessel(
2020
/// arguments to Int4, any overflow error will be reported during the
2121
/// conversion folding.
2222
using Int4 = Type<TypeCategory::Integer, 4>;
23-
if (auto args{
24-
GetConstantArguments<Int4, Int4, T>(context, funcRef.arguments())}) {
23+
if (auto args{GetConstantArguments<Int4, Int4, T>(
24+
context, funcRef.arguments(), /*hasOptionalArgument=*/false)}) {
2525
const std::string &name{std::get<SpecificIntrinsic>(funcRef.proc().u).name};
2626
if (auto elementalBessel{GetHostRuntimeWrapper<T, Int4, T>(name)}) {
2727
std::vector<Scalar<T>> results;

flang/test/Evaluate/rewrite08.f90

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
2+
subroutine s(oi,ol)
3+
integer(1), optional, intent(in) :: oi
4+
logical(1), optional, intent(in) :: ol
5+
integer(1), allocatable :: ai
6+
logical(1), allocatable :: al
7+
integer(1), pointer :: pi
8+
logical(1), pointer :: pl
9+
!CHECK: PRINT *, ishftc(-1_4,1_4,oi)
10+
!CHECK: PRINT *, ishftc(-1_4,1_4,ai)
11+
!CHECK: PRINT *, ishftc(-1_4,1_4,pi)
12+
!CHECK: PRINT *, findloc([INTEGER(4)::1_4,2_4,1_4],1_4,back=ol)
13+
!CHECK: PRINT *, findloc([INTEGER(4)::1_4,2_4,1_4],1_4,back=al)
14+
!CHECK: PRINT *, findloc([INTEGER(4)::1_4,2_4,1_4],1_4,back=pl)
15+
print *, ishftc(-1,1,oi)
16+
print *, ishftc(-1,1,ai)
17+
print *, ishftc(-1,1,pi)
18+
print *, findloc([1,2,1],1,back=ol)
19+
print *, findloc([1,2,1],1,back=al)
20+
print *, findloc([1,2,1],1,back=pl)
21+
end

0 commit comments

Comments
 (0)