[flang] Legacy extension intrinsic functions IMAG, IZEXT, JZEXT

Support these legacy extension intrinsic functions with unambiguous
semantics in those existing compilers that support them by means
of recognizing them as aliases for standard intrinsics (IMAG) or
with simple rewrites (IZEXT, JZEXT).  Note that ZEXT has different
semantics in different existing compilers, so we will not support it
due to lack of a broad unambiguous precedent.

Differential Revision: https://reviews.llvm.org/D132154
This commit is contained in:
Peter Klausler 2022-08-12 12:28:44 -07:00
parent b066195b3f
commit 6d279f4051
4 changed files with 30 additions and 1 deletions

View File

@ -235,6 +235,11 @@ end
respectively.
* A digit count of d=0 is accepted in Ew.0, Dw.0, and Gw.0 output
editing if no nonzero scale factor (kP) is in effect.
* The name `IMAG` is accepted as an alias for the generic intrinsic
function `AIMAG`.
* The legacy extension intrinsic functions `IZEXT` and `JZEXT`
are supported; `ZEXT` has different behavior with various older
compilers, so it is not supported.
### Extensions supported when enabled by options

View File

@ -762,6 +762,17 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
return i.ISHFTC(countVal);
}));
}
} else if (name == "izext" || name == "jzext") {
if (args.size() == 1) {
if (auto *expr{UnwrapExpr<Expr<SomeInteger>>(args[0])}) {
// Rewrite to IAND(INT(n,k),255_k) for k=KIND(T)
intrinsic->name = "iand";
auto converted{ConvertToType<T>(std::move(*expr))};
*expr = Fold(context, Expr<SomeInteger>{std::move(converted)});
args.emplace_back(AsGenericExpr(Expr<T>{Scalar<T>{255}}));
return FoldIntrinsicFunction(context, std::move(funcRef));
}
}
} else if (name == "lbound") {
return LBOUND(context, std::move(funcRef));
} else if (name == "leadz" || name == "trailz" || name == "poppar" ||

View File

@ -507,6 +507,8 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
DefaultLogical, Rank::elemental, IntrinsicClass::inquiryFunction},
{"is_iostat_end", {{"i", AnyInt}}, DefaultLogical},
{"is_iostat_eor", {{"i", AnyInt}}, DefaultLogical},
{"izext", {{"i", AnyInt}}, TypePattern{IntType, KindCode::exactKind, 2}},
{"jzext", {{"i", AnyInt}}, DefaultInt},
{"kind", {{"x", AnyIntrinsic}}, DefaultInt, Rank::elemental,
IntrinsicClass::inquiryFunction},
{"lbound",
@ -844,7 +846,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
// TODO: Coarray intrinsic functions
// LCOBOUND, UCOBOUND, IMAGE_INDEX, COSHAPE
// TODO: Non-standard intrinsic functions
// LSHIFT, RSHIFT, SHIFT, ZEXT, IZEXT,
// LSHIFT, RSHIFT, SHIFT,
// COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT,
// QCMPLX, QEXT, QFLOAT, QREAL, DNUM,
// INUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN,
@ -860,6 +862,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
// compatibility and builtins.
static const std::pair<const char *, const char *> genericAlias[]{
{"and", "iand"},
{"imag", "aimag"},
{"or", "ior"},
{"xor", "ieor"},
{"__builtin_ieee_selected_real_kind", "selected_real_kind"},

View File

@ -0,0 +1,10 @@
! RUN: %python %S/test_folding.py %s %flang_fc1
! Tests folding of IZEXT() & JZEXT()
module m
logical, parameter :: test_1 = kind(izext(-1_1)) == 2
logical, parameter :: test_2 = izext(-1_1) == 255_2
logical, parameter :: test_3 = kind(jzext(-1_1)) == 4
logical, parameter :: test_4 = jzext(-1_1) == 255_4
logical, parameter :: test_5 = kind(jzext(-1_2)) == 4
logical, parameter :: test_6 = jzext(-1_2) == 255_4
end module