Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions flang/docs/Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ end
* Specific intrinsics AMAX0, AMAX1, AMIN0, AMIN1, DMAX1, DMIN1, MAX0, MAX1,
MIN0, and MIN1 accept more argument types than specified. They are replaced by
the related generics followed by conversions to the specified result types.
For MAX0 and MIN0, the result type matches the argument types rather than
being converted to default INTEGER, preserving the kind of the arguments.
For example, `MAX0(1_8, 2_8)` returns `INTEGER(8)`, not `INTEGER(4)`.
* When a scalar CHARACTER actual argument of the same kind is known to
have a length shorter than the associated dummy argument, it is extended
on the right with blanks, similar to assignment.
Expand Down
6 changes: 6 additions & 0 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3654,6 +3654,12 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::Probe(
.GetTypeAndShape())
.type()};
DynamicType newType{GetReturnType(*specIter->second, defaults_)};
// For MAX0/MIN0, preserve the generic type rather than forcing
// to default integer. This allows, for example, MAX0(1_8,2_8) to
// return INTEGER(8) instead of INTEGER(4).
if (genericType.category() == newType.category()) {
newType = genericType;
}
if (genericType.category() == newType.category() ||
((genericType.category() == TypeCategory::Integer ||
genericType.category() == TypeCategory::Real) &&
Expand Down
13 changes: 7 additions & 6 deletions flang/test/Evaluate/folding04.f90
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,16 @@ module parentheses
module specific_extremums
! f18 accepts all type kinds for the arguments of specific extremum intrinsics
! instead of of only default kind (or double precision for DMAX1 and DMIN1).
! This extensions is implemented by using the related generic intrinsic and
! converting the result.
! This extension is implemented by using the related generic intrinsic.
! For MAX0/MIN0, the result type matches the argument types (preserving kind).
! For AMAX0/AMIN0/MAX1/MIN1, the result is converted to the specified type.
! The tests below are cases where an implementation that converts the arguments to the
! standard required types instead would give different results than the implementation
! specified for f18 (converting the result).
! specified for f18.
integer(8), parameter :: max_i32_8 = 2_8**31-1
integer, parameter :: expected_min0 = int(min(max_i32_8, 2_8*max_i32_8), 4)
!WARN: portability: Argument types do not match specific intrinsic 'min0' requirements; using 'min' generic instead and converting the result to INTEGER(4) if needed [-Wuse-generic-intrinsic-when-specific-doesnt-match]
integer, parameter :: result_min0 = min0(max_i32_8, 2_8*max_i32_8)
integer(8), parameter :: expected_min0 = min(max_i32_8, 2_8*max_i32_8)
!WARN: portability: Argument types do not match specific intrinsic 'min0' requirements; using 'min' generic instead and converting the result to INTEGER(8) if needed [-Wuse-generic-intrinsic-when-specific-doesnt-match]
integer(8), parameter :: result_min0 = min0(max_i32_8, 2_8*max_i32_8)
! result_min0 would be -2 if arguments were converted to default integer.
logical, parameter :: test_min0 = expected_min0 .EQ. result_min0

Expand Down