[flang-commits] [flang] bc699ed - [flang] prevent rewrite of CMPLX with dynamically optional Y argument

Jean Perier via flang-commits flang-commits at lists.llvm.org
Wed Feb 2 10:53:47 PST 2022


Author: Jean Perier
Date: 2022-02-02T19:52:52+01:00
New Revision: bc699ed0bfaf82700f02fab6a27bdcaad2396f00

URL: https://github.com/llvm/llvm-project/commit/bc699ed0bfaf82700f02fab6a27bdcaad2396f00
DIFF: https://github.com/llvm/llvm-project/commit/bc699ed0bfaf82700f02fab6a27bdcaad2396f00.diff

LOG: [flang] prevent rewrite of CMPLX with dynamically optional Y argument

CMPLX was always rewritten as a complex constructor, but the second operand
of a complex constructor cannot be dynamically absent (i.e., a
disassociated pointer, an unallocated allocatable or an absent OPTIONAL
dummy argument), while the second argument of CMPLX can be dynamically
absent.

To avoid having to generate branches in complex constructor lowering
when Y is a pointer, keep the distinction between CMPLX and a complex
constructor when Y is a pointer, an allocatable, or an OPTIONAL entity.

Differential Revision: https://reviews.llvm.org/D118784

Added: 
    

Modified: 
    flang/include/flang/Evaluate/tools.h
    flang/lib/Evaluate/fold-complex.cpp
    flang/lib/Evaluate/tools.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 0e2cdcde274c7..703cc335275eb 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -889,6 +889,10 @@ template <typename A> bool IsAllocatableOrPointer(const A &x) {
       semantics::Attrs{semantics::Attr::POINTER, semantics::Attr::ALLOCATABLE});
 }
 
+// Like IsAllocatableOrPointer, but accepts pointer function results as being
+// pointers.
+bool IsAllocatableOrPointerObject(const Expr<SomeType> &, FoldingContext &);
+
 // Procedure and pointer detection predicates
 bool IsProcedure(const Expr<SomeType> &);
 bool IsFunction(const Expr<SomeType> &);
@@ -897,6 +901,10 @@ bool IsBareNullPointer(const Expr<SomeType> *); // NULL() w/o MOLD=
 bool IsNullPointer(const Expr<SomeType> &);
 bool IsObjectPointer(const Expr<SomeType> &, FoldingContext &);
 
+// Can Expr be passed as absent to an optional dummy argument.
+// See 15.5.2.12 point 1 for more details.
+bool MayBePassedAsAbsentOptional(const Expr<SomeType> &, FoldingContext &);
+
 // Extracts the chain of symbols from a designator, which has perhaps been
 // wrapped in an Expr<>, removing all of the (co)subscripts.  The
 // base object will be the first symbol in the result vector.

diff  --git a/flang/lib/Evaluate/fold-complex.cpp b/flang/lib/Evaluate/fold-complex.cpp
index 7458aa9ca9596..e7981a189ce27 100644
--- a/flang/lib/Evaluate/fold-complex.cpp
+++ b/flang/lib/Evaluate/fold-complex.cpp
@@ -41,6 +41,15 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldIntrinsicFunction(
         // CMPLX(X [, KIND]) with complex X
         return Fold(context, ConvertToType<T>(std::move(*x)));
       } else {
+        if (args.size() >= 2 && args[1].has_value()) {
+          // Do not fold CMPLX with an Y argument that may be absent at runtime
+          // into a complex constructor so that lowering can deal with the
+          // optional aspect (there is no optional aspect with the complex
+          // constructor).
+          if (MayBePassedAsAbsentOptional(*args[1]->UnwrapExpr(), context)) {
+            return Expr<T>{std::move(funcRef)};
+          }
+        }
         // CMPLX(X [, Y [, KIND]]) with non-complex X
         Expr<SomeType> re{std::move(*args[0].value().UnwrapExpr())};
         Expr<SomeType> im{args.size() >= 2 && args[1].has_value()

diff  --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 707da891fd5a3..25ea7992b057a 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1078,6 +1078,24 @@ std::optional<Expr<SomeType>> DataConstantConversionExtension(
   return std::nullopt;
 }
 
+bool IsAllocatableOrPointerObject(
+    const Expr<SomeType> &expr, FoldingContext &context) {
+  const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
+  return (sym && semantics::IsAllocatableOrPointer(*sym)) ||
+      evaluate::IsObjectPointer(expr, context);
+}
+
+bool MayBePassedAsAbsentOptional(
+    const Expr<SomeType> &expr, FoldingContext &context) {
+  const semantics::Symbol *sym{UnwrapWholeSymbolOrComponentDataRef(expr)};
+  // 15.5.2.12 1. is pretty clear that an unallocated allocatable/pointer actual
+  // may be passed to a non-allocatable/non-pointer optional dummy. Note that
+  // other compilers (like nag, nvfortran, ifort, gfortran and xlf) seems to
+  // ignore this point in intrinsic contexts (e.g CMPLX argument).
+  return (sym && semantics::IsOptional(*sym)) ||
+      IsAllocatableOrPointerObject(expr, context);
+}
+
 } // namespace Fortran::evaluate
 
 namespace Fortran::semantics {


        


More information about the flang-commits mailing list