[flang-commits] [flang] da60b9e - [flang] Fixed managing copy-in/copy-out temps.

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Tue May 23 09:37:35 PDT 2023


Author: Slava Zakharin
Date: 2023-05-23T09:35:17-07:00
New Revision: da60b9e7dc6b217ecd8f422a71ee3aa4a4022015

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

LOG: [flang] Fixed managing copy-in/copy-out temps.

There are several observations regarding the copy-in/copy-out:
  * Actual argument associated with INTENT(OUT) dummy argument that
    requires finalization (7.5.6.3 p. 7) may be read by the finalization
    function, so a copy-in is required.
  * A temporary created for the copy-in/copy-out must be destroyed
    without finalization after the call (or after the corresponding copy-out),
    otherwise, memory leaks may occur.
  * The copy-out assignment must not perform finalization for the LHS.
  * The copy-out assignment from the temporary to the actual argument
    may or may not need to initialize the LHS.

This change-set introduces new runtime methods: CopyOutAssign and
DestroyWithoutFinalization. They are called by the compiler generated
code to match the behavior described above.

Reviewed By: jeanPerier

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

Added: 
    

Modified: 
    flang/include/flang/Lower/CallInterface.h
    flang/include/flang/Optimizer/Builder/Runtime/Assign.h
    flang/include/flang/Optimizer/Builder/Runtime/Derived.h
    flang/include/flang/Runtime/assign.h
    flang/include/flang/Runtime/derived-api.h
    flang/lib/Lower/CallInterface.cpp
    flang/lib/Lower/ConvertCall.cpp
    flang/lib/Lower/ConvertExpr.cpp
    flang/lib/Optimizer/Builder/Runtime/Assign.cpp
    flang/lib/Optimizer/Builder/Runtime/Derived.cpp
    flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
    flang/runtime/assign.cpp
    flang/runtime/derived-api.cpp
    flang/test/HLFIR/copy-in-out-codegen.fir
    flang/test/Lower/call-by-value-attr.f90
    flang/test/Lower/call-copy-in-out.f90
    flang/test/Lower/dummy-argument-assumed-shape-optional.f90
    flang/test/Lower/dummy-argument-optional-2.f90
    flang/test/Lower/optional-value-caller.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h
index fc338dbe1e8a9..8586a056f180e 100644
--- a/flang/include/flang/Lower/CallInterface.h
+++ b/flang/include/flang/Lower/CallInterface.h
@@ -167,6 +167,11 @@ class CallInterface {
     bool mustBeMadeContiguous() const;
     /// Does the dummy argument have the VALUE attribute?
     bool hasValueAttribute() const;
+    /// Does the dummy argument have the ALLOCATABLE attribute?
+    bool hasAllocatableAttribute() const;
+    /// May the dummy argument require INTENT(OUT) finalization
+    /// on entry to the invoked procedure? Provides conservative answer.
+    bool mayRequireIntentoutFinalization() const;
     /// How entity is passed by.
     PassEntityBy passBy;
     /// What is the entity (SymbolRef for callee/ActualArgument* for caller)

diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/Assign.h b/flang/include/flang/Optimizer/Builder/Runtime/Assign.h
index f33a76a6e8299..14d338b7093e8 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Assign.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Assign.h
@@ -48,5 +48,26 @@ void genAssignExplicitLengthCharacter(fir::FirOpBuilder &builder,
                                       mlir::Location loc, mlir::Value destBox,
                                       mlir::Value sourceBox);
 
+/// Generate runtime call to assign \p sourceBox to \p destBox.
+/// \p destBox must be a fir.ref<fir.box<T>> and \p sourceBox a fir.box<T>.
+/// \p destBox Fortran descriptor may be modified if destBox is an allocatable
+/// according to Fortran allocatable assignment rules, otherwise it is not
+/// modified.
+void genAssignTemporary(fir::FirOpBuilder &builder, mlir::Location loc,
+                        mlir::Value destBox, mlir::Value sourceBox);
+
+/// Generate runtime call to CopyOutAssign to assign \p sourceBox to
+/// \p destBox. This call implements the copy-out of a temporary
+/// (\p sourceBox) to the actual argument (\p destBox) passed to a procedure,
+/// after the procedure returns to the caller.
+/// If \p skipToInit is false, then \p destBox will be initialized before
+/// the assignment, otherwise, it is assumed to be already initialized.
+/// The runtime makes sure that there is no reallocation of the top-level
+/// entity represented by \p destBox. If reallocation is required
+/// for the components of \p destBox, then it is done without finalization.
+void genCopyOutAssign(fir::FirOpBuilder &builder, mlir::Location loc,
+                      mlir::Value destBox, mlir::Value sourceBox,
+                      bool skipToInit);
+
 } // namespace fir::runtime
 #endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_ASSIGN_H

diff  --git a/flang/include/flang/Optimizer/Builder/Runtime/Derived.h b/flang/include/flang/Optimizer/Builder/Runtime/Derived.h
index 8539d2781c33b..30998f8b0ea65 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Derived.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Derived.h
@@ -31,6 +31,12 @@ void genDerivedTypeInitialize(fir::FirOpBuilder &builder, mlir::Location loc,
 void genDerivedTypeDestroy(fir::FirOpBuilder &builder, mlir::Location loc,
                            mlir::Value box);
 
+/// Generate call to derived type destruction runtime routine to
+/// destroy \p box without finalization
+void genDerivedTypeDestroyWithoutFinalization(fir::FirOpBuilder &builder,
+                                              mlir::Location loc,
+                                              mlir::Value box);
+
 /// Generate call to `PointerNullifyDerived` runtime function to nullify
 /// and set the correct dynamic type to a boxed derived type.
 void genNullifyDerivedType(fir::FirOpBuilder &builder, mlir::Location loc,

diff  --git a/flang/include/flang/Runtime/assign.h b/flang/include/flang/Runtime/assign.h
index 0b049b9d4b75d..779997dab6186 100644
--- a/flang/include/flang/Runtime/assign.h
+++ b/flang/include/flang/Runtime/assign.h
@@ -36,6 +36,8 @@ void RTNAME(Assign)(Descriptor &to, const Descriptor &from,
 // reallocation.
 void RTNAME(AssignTemporary)(Descriptor &to, const Descriptor &from,
     const char *sourceFile = nullptr, int sourceLine = 0);
+void RTNAME(CopyOutAssign)(Descriptor &to, const Descriptor &from,
+    bool skipToInit, const char *sourceFile = nullptr, int sourceLine = 0);
 // This variant is for assignments to explicit-length CHARACTER left-hand
 // sides that might need to handle truncation or blank-fill, and
 // must maintain the character length even if an allocatable array

diff  --git a/flang/include/flang/Runtime/derived-api.h b/flang/include/flang/Runtime/derived-api.h
index 651ab406939e6..3bf631bc4d0c7 100644
--- a/flang/include/flang/Runtime/derived-api.h
+++ b/flang/include/flang/Runtime/derived-api.h
@@ -37,6 +37,11 @@ void RTNAME(Initialize)(
 // storage.
 void RTNAME(Destroy)(const Descriptor &);
 
+/// Deallocates any allocatable/automatic components.
+/// Does not deallocate the descriptor's storage.
+/// Does not perform any finalization.
+void RTNAME(DestroyWithoutFinalization)(const Descriptor &);
+
 // Intrinsic or defined assignment, with scalar expansion but not type
 // conversion.
 void RTNAME(Assign)(const Descriptor &, const Descriptor &,

diff  --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp
index b7c4d920b37c5..833ad73d164a4 100644
--- a/flang/lib/Lower/CallInterface.cpp
+++ b/flang/lib/Lower/CallInterface.cpp
@@ -1229,6 +1229,57 @@ bool Fortran::lower::CallInterface<T>::PassedEntity::hasValueAttribute() const {
              Fortran::evaluate::characteristics::DummyDataObject::Attr::Value);
 }
 
+template <typename T>
+bool Fortran::lower::CallInterface<T>::PassedEntity::hasAllocatableAttribute()
+    const {
+  if (!characteristics)
+    return false;
+  const auto *dummy =
+      std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
+          &characteristics->u);
+  using Attrs = Fortran::evaluate::characteristics::DummyDataObject::Attr;
+  return dummy && dummy->attrs.test(Attrs::Allocatable);
+}
+
+template <typename T>
+bool Fortran::lower::CallInterface<
+    T>::PassedEntity::mayRequireIntentoutFinalization() const {
+  // Conservatively assume that the finalization is needed.
+  if (!characteristics)
+    return true;
+
+  // No INTENT(OUT) dummy arguments do not require finalization on entry.
+  if (!isIntentOut())
+    return false;
+
+  const auto *dummy =
+      std::get_if<Fortran::evaluate::characteristics::DummyDataObject>(
+          &characteristics->u);
+  if (!dummy)
+    return true;
+
+  // POINTER/ALLOCATABLE dummy arguments do not require finalization.
+  using Attrs = Fortran::evaluate::characteristics::DummyDataObject::Attr;
+  if (dummy->attrs.test(Attrs::Allocatable) ||
+      dummy->attrs.test(Attrs::Pointer))
+    return false;
+
+  // Polymorphic and unlimited polymorphic INTENT(OUT) dummy arguments
+  // may need finalization.
+  const Fortran::evaluate::DynamicType &type = dummy->type.type();
+  if (type.IsPolymorphic() || type.IsUnlimitedPolymorphic())
+    return true;
+
+  // INTENT(OUT) dummy arguments of derived types require finalization,
+  // if their type has finalization.
+  const Fortran::semantics::DerivedTypeSpec *derived =
+      Fortran::evaluate::GetDerivedTypeSpec(type);
+  if (!derived)
+    return false;
+
+  return Fortran::semantics::IsFinalizable(*derived);
+}
+
 template <typename T>
 void Fortran::lower::CallInterface<T>::determineInterface(
     bool isImplicit,

diff  --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 0c9d7af9678ec..d8160c6b7b198 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -925,6 +925,13 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
       // Copy-in non contiguous variables.
       assert(entity.getType().isa<fir::BaseBoxType>() &&
              "expect non simply contiguous variables to be boxes");
+      // TODO: for non-finalizable monomorphic derived type actual
+      // arguments associated with INTENT(OUT) dummy arguments
+      // we may avoid doing the copy and only allocate the temporary.
+      // The codegen would do a "mold" allocation instead of "sourced"
+      // allocation for the temp in this case. We can communicate
+      // this to the codegen via some CopyInOp flag.
+      // This is a performance concern.
       auto copyIn = builder.create<hlfir::CopyInOp>(
           loc, entity, /*var_is_present=*/mlir::Value{});
       entity = hlfir::Entity{copyIn.getCopiedIn()};

diff  --git a/flang/lib/Lower/ConvertExpr.cpp b/flang/lib/Lower/ConvertExpr.cpp
index 47d5ed4c02e54..b5423205ed065 100644
--- a/flang/lib/Lower/ConvertExpr.cpp
+++ b/flang/lib/Lower/ConvertExpr.cpp
@@ -2153,7 +2153,27 @@ class ScalarExprLowering {
 
     auto doCopyIn = [&]() -> ExtValue {
       ExtValue temp = genArrayTempFromMold(actualArg, tempName);
-      if (!arg.mayBeReadByCall()) {
+      if (!arg.mayBeReadByCall() &&
+          // INTENT(OUT) dummy argument finalization, automatically
+          // done when the procedure is invoked, may imply reading
+          // the argument value in the finalization routine.
+          // So we need to make a copy, if finalization may occur.
+          // TODO: do we have to avoid the copying for an actual
+          // argument of type that does not require finalization?
+          !arg.mayRequireIntentoutFinalization() &&
+          // ALLOCATABLE dummy argument may require finalization.
+          // If it has to be automatically deallocated at the end
+          // of the procedure invocation (9.7.3.2 p. 2),
+          // then the finalization may happen if the actual argument
+          // is allocated (7.5.6.3 p. 2).
+          !arg.hasAllocatableAttribute()) {
+        // We have to initialize the temp if it may have components
+        // that need initialization. If there are no components
+        // requiring initialization, then the call is a no-op.
+        if (getElementTypeOf(temp).isa<fir::RecordType>()) {
+          mlir::Value tempBox = fir::getBase(builder.createBox(loc, temp));
+          fir::runtime::genDerivedTypeInitialize(builder, loc, tempBox);
+        }
         return temp;
       }
       if (!isActualArgBox || inlineCopyInOutForBoxes) {
@@ -2161,12 +2181,16 @@ class ScalarExprLowering {
         return temp;
       }
 
-      // Generate Assign() call to copy data from the actualArg
-      // to a temporary.
+      // Generate AssignTemporary() call to copy data from the actualArg
+      // to a temporary. AssignTemporary() will initialize the temporary,
+      // if needed, before doing the assignment, which is required
+      // since the temporary's components (if any) are uninitialized
+      // at this point.
       mlir::Value destBox = fir::getBase(builder.createBox(loc, temp));
       mlir::Value boxRef = builder.createTemporary(loc, destBox.getType());
       builder.create<fir::StoreOp>(loc, destBox, boxRef);
-      fir::runtime::genAssign(builder, loc, boxRef, fir::getBase(actualArg));
+      fir::runtime::genAssignTemporary(builder, loc, boxRef,
+                                       fir::getBase(actualArg));
       return temp;
     };
 
@@ -2272,21 +2296,37 @@ class ScalarExprLowering {
         genArrayCopy(copyOutPair.var, copyOutPair.temp);
         return;
       }
-      // Generate Assign() call to copy data from the temporary
+      // Generate CopyOutAssign() call to copy data from the temporary
       // to the actualArg. Note that in case the actual argument
-      // is ALLOCATABLE/POINTER the Assign() implementation
+      // is ALLOCATABLE/POINTER the CopyOutAssign() implementation
       // should not engage its reallocation, because the temporary
       // is rank, shape and type compatible with it.
+      // Moreover, CopyOutAssign() guarantees that there will be no
+      // finalization for the LHS even if it is of a derived type
+      // with finalization.
       mlir::Value srcBox =
           fir::getBase(builder.createBox(loc, copyOutPair.temp));
       mlir::Value destBox =
           fir::getBase(builder.createBox(loc, copyOutPair.var));
       mlir::Value destBoxRef = builder.createTemporary(loc, destBox.getType());
       builder.create<fir::StoreOp>(loc, destBox, destBoxRef);
-      fir::runtime::genAssign(builder, loc, destBoxRef, srcBox);
+      fir::runtime::genCopyOutAssign(builder, loc, destBoxRef, srcBox,
+                                     /*skipToInit=*/true);
     };
     if (!copyOutPair.restrictCopyAndFreeAtRuntime) {
       doCopyOut();
+
+      if (fir::getElementTypeOf(copyOutPair.temp).isa<fir::RecordType>()) {
+        // Destroy components of the temporary (if any).
+        // If there are no components requiring destruction, then the call
+        // is a no-op.
+        mlir::Value tempBox =
+            fir::getBase(builder.createBox(loc, copyOutPair.temp));
+        fir::runtime::genDerivedTypeDestroyWithoutFinalization(builder, loc,
+                                                               tempBox);
+      }
+
+      // Deallocate the top-level entity of the temporary.
       builder.create<fir::FreeMemOp>(loc, fir::getBase(copyOutPair.temp));
       return;
     }
@@ -2294,6 +2334,17 @@ class ScalarExprLowering {
     builder.genIfThen(loc, *copyOutPair.restrictCopyAndFreeAtRuntime)
         .genThen([&]() {
           doCopyOut();
+          if (fir::getElementTypeOf(copyOutPair.temp).isa<fir::RecordType>()) {
+            // Destroy components of the temporary (if any).
+            // If there are no components requiring destruction, then the call
+            // is a no-op.
+            mlir::Value tempBox =
+                fir::getBase(builder.createBox(loc, copyOutPair.temp));
+            fir::runtime::genDerivedTypeDestroyWithoutFinalization(builder, loc,
+                                                                   tempBox);
+          }
+
+          // Deallocate the top-level entity of the temporary.
           builder.create<fir::FreeMemOp>(loc, fir::getBase(copyOutPair.temp));
         })
         .end();

diff  --git a/flang/lib/Optimizer/Builder/Runtime/Assign.cpp b/flang/lib/Optimizer/Builder/Runtime/Assign.cpp
index db4de8ac9f377..ad0c2af85cdf3 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Assign.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Assign.cpp
@@ -54,3 +54,34 @@ void fir::runtime::genAssignExplicitLengthCharacter(fir::FirOpBuilder &builder,
                                             sourceBox, sourceFile, sourceLine);
   builder.create<fir::CallOp>(loc, func, args);
 }
+
+void fir::runtime::genAssignTemporary(fir::FirOpBuilder &builder,
+                                      mlir::Location loc, mlir::Value destBox,
+                                      mlir::Value sourceBox) {
+  auto func =
+      fir::runtime::getRuntimeFunc<mkRTKey(AssignTemporary)>(loc, builder);
+  auto fTy = func.getFunctionType();
+  auto sourceFile = fir::factory::locationToFilename(builder, loc);
+  auto sourceLine =
+      fir::factory::locationToLineNo(builder, loc, fTy.getInput(3));
+  auto args = fir::runtime::createArguments(builder, loc, fTy, destBox,
+                                            sourceBox, sourceFile, sourceLine);
+  builder.create<fir::CallOp>(loc, func, args);
+}
+
+void fir::runtime::genCopyOutAssign(fir::FirOpBuilder &builder,
+                                    mlir::Location loc, mlir::Value destBox,
+                                    mlir::Value sourceBox, bool skipToInit) {
+  auto func =
+      fir::runtime::getRuntimeFunc<mkRTKey(CopyOutAssign)>(loc, builder);
+  auto fTy = func.getFunctionType();
+  auto sourceFile = fir::factory::locationToFilename(builder, loc);
+  auto sourceLine =
+      fir::factory::locationToLineNo(builder, loc, fTy.getInput(4));
+  auto i1Ty = builder.getIntegerType(1);
+  auto skipToInitVal = builder.createIntegerConstant(loc, i1Ty, skipToInit);
+  auto args =
+      fir::runtime::createArguments(builder, loc, fTy, destBox, sourceBox,
+                                    skipToInitVal, sourceFile, sourceLine);
+  builder.create<fir::CallOp>(loc, func, args);
+}

diff  --git a/flang/lib/Optimizer/Builder/Runtime/Derived.cpp b/flang/lib/Optimizer/Builder/Runtime/Derived.cpp
index 796f35631bbee..e6cd9ff5a797d 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Derived.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Derived.cpp
@@ -37,6 +37,15 @@ void fir::runtime::genDerivedTypeDestroy(fir::FirOpBuilder &builder,
   builder.create<fir::CallOp>(loc, func, args);
 }
 
+void fir::runtime::genDerivedTypeDestroyWithoutFinalization(
+    fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value box) {
+  auto func = fir::runtime::getRuntimeFunc<mkRTKey(DestroyWithoutFinalization)>(
+      loc, builder);
+  auto fTy = func.getFunctionType();
+  auto args = fir::runtime::createArguments(builder, loc, fTy, box);
+  builder.create<fir::CallOp>(loc, func, args);
+}
+
 void fir::runtime::genNullifyDerivedType(fir::FirOpBuilder &builder,
                                          mlir::Location loc, mlir::Value box,
                                          fir::RecordType derivedType,

diff  --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index ab1f7417531bd..20718aaa42da1 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -13,6 +13,7 @@
 #include "flang/Optimizer/Builder/HLFIRTools.h"
 #include "flang/Optimizer/Builder/MutableBox.h"
 #include "flang/Optimizer/Builder/Runtime/Assign.h"
+#include "flang/Optimizer/Builder/Runtime/Derived.h"
 #include "flang/Optimizer/Builder/Runtime/Inquiry.h"
 #include "flang/Optimizer/Builder/Todo.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
@@ -47,7 +48,7 @@ static mlir::Value genAllocatableTempFromSourceBox(mlir::Location loc,
   mlir::Type fromBoxHeapType = fir::BoxType::get(fromHeapType);
   mlir::Value fromMutableBox =
       fir::factory::genNullBoxStorage(builder, loc, fromBoxHeapType);
-  fir::runtime::genAssign(builder, loc, fromMutableBox, sourceBox);
+  fir::runtime::genAssignTemporary(builder, loc, fromMutableBox, sourceBox);
   mlir::Value copy = builder.create<fir::LoadOp>(loc, fromMutableBox);
   return copy;
 }
@@ -248,20 +249,32 @@ class CopyOutOpConversion : public mlir::OpRewritePattern<hlfir::CopyOutOp> {
         .genThen([&]() {
           mlir::Value temp = copyOutOp.getTemp();
           if (mlir::Value var = copyOutOp.getVar()) {
-            auto mutableBox = builder.createTemporary(loc, var.getType());
-            builder.create<fir::StoreOp>(loc, var, mutableBox);
-            // Generate Assign() call to copy data from the temporary
-            // to the variable. Note that in case the actual argument
-            // is ALLOCATABLE/POINTER the Assign() implementation
+            auto mutableBoxTo = builder.createTemporary(loc, var.getType());
+            builder.create<fir::StoreOp>(loc, var, mutableBoxTo);
+            // Generate CopyOutAssign() call to copy data from the temporary
+            // to the actualArg. Note that in case the actual argument
+            // is ALLOCATABLE/POINTER the CopyOutAssign() implementation
             // should not engage its reallocation, because the temporary
-            // is rank, shape and type compatible with it (it was created
-            // from the variable).
-            fir::runtime::genAssign(builder, loc, mutableBox, temp);
+            // is rank, shape and type compatible with it.
+            // Moreover, CopyOutAssign() guarantees that there will be no
+            // finalization for the LHS even if it is of a derived type
+            // with finalization.
+            fir::runtime::genCopyOutAssign(builder, loc, mutableBoxTo, temp,
+                                           /*skipToInit=*/true);
           }
+          // Destroy components of the temporary (if any).
+          fir::runtime::genDerivedTypeDestroyWithoutFinalization(builder, loc,
+                                                                 temp);
           mlir::Type heapType =
               fir::HeapType::get(fir::dyn_cast_ptrOrBoxEleTy(temp.getType()));
           mlir::Value tempAddr =
               builder.create<fir::BoxAddrOp>(loc, heapType, temp);
+
+          // Deallocate the top-level entity of the temporary.
+          //
+          // Note that this FreeMemOp is coupled with the runtime
+          // allocation engaged by the code generated by
+          // genAllocatableTempFromSourceBox().
           builder.create<fir::FreeMemOp>(loc, tempAddr);
         })
         .end();

diff  --git a/flang/runtime/assign.cpp b/flang/runtime/assign.cpp
index f75fe94bf3009..49e86c20b17cc 100644
--- a/flang/runtime/assign.cpp
+++ b/flang/runtime/assign.cpp
@@ -561,9 +561,32 @@ void RTNAME(AssignTemporary)(Descriptor &to, const Descriptor &from,
       }
     }
   }
+
   Assign(to, from, terminator, PolymorphicLHS);
 }
 
+void RTNAME(CopyOutAssign)(Descriptor &to, const Descriptor &from,
+    bool skipToInit, const char *sourceFile, int sourceLine) {
+  Terminator terminator{sourceFile, sourceLine};
+  // Initialize the "to" if it is of derived type that needs initialization.
+  if (!skipToInit) {
+    if (const DescriptorAddendum * addendum{to.Addendum()}) {
+      if (const auto *derived{addendum->derivedType()}) {
+        if (!derived->noInitializationNeeded()) {
+          if (ReturnError(terminator, Initialize(to, *derived, terminator)) !=
+              StatOk) {
+            return;
+          }
+        }
+      }
+    }
+  }
+
+  // Copyout from the temporary must not cause any finalizations
+  // for LHS.
+  Assign(to, from, terminator, NoAssignFlags);
+}
+
 void RTNAME(AssignExplicitLengthCharacter)(Descriptor &to,
     const Descriptor &from, const char *sourceFile, int sourceLine) {
   Terminator terminator{sourceFile, sourceLine};

diff  --git a/flang/runtime/derived-api.cpp b/flang/runtime/derived-api.cpp
index 9b3455d9f0293..8df49c5841a1c 100644
--- a/flang/runtime/derived-api.cpp
+++ b/flang/runtime/derived-api.cpp
@@ -156,5 +156,15 @@ bool RTNAME(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
   return false;
 }
 
+void RTNAME(DestroyWithoutFinalization)(const Descriptor &descriptor) {
+  if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
+    if (const auto *derived{addendum->derivedType()}) {
+      if (!derived->noDestructionNeeded()) {
+        Destroy(descriptor, /*finalize=*/false, *derived);
+      }
+    }
+  }
+}
+
 } // extern "C"
 } // namespace Fortran::runtime

diff  --git a/flang/test/HLFIR/copy-in-out-codegen.fir b/flang/test/HLFIR/copy-in-out-codegen.fir
index 71962d90f013a..462dc483a21f6 100644
--- a/flang/test/HLFIR/copy-in-out-codegen.fir
+++ b/flang/test/HLFIR/copy-in-out-codegen.fir
@@ -21,7 +21,7 @@ func.func @test_copy_in(%box: !fir.box<!fir.array<?xf64>>) {
 // CHECK:      fir.store %[[VAL_8]] to %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>
 // CHECK:      %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>) -> !fir.ref<!fir.box<none>>
 // CHECK:      %[[VAL_13:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?xf64>>) -> !fir.box<none>
-// CHECK:      %[[VAL_15:.*]] = fir.call @_FortranAAssign(%[[VAL_12]], %[[VAL_13]],
+// CHECK:      %[[VAL_15:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_12]], %[[VAL_13]],
 // CHECK:      %[[VAL_16:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>
 // CHECK:      %[[VAL_17:.*]] = fir.rebox %[[VAL_16]] : (!fir.box<!fir.heap<!fir.array<?xf64>>>) -> !fir.box<!fir.array<?xf64>>
 // CHECK:      fir.result %[[VAL_17]] : !fir.box<!fir.array<?xf64>>
@@ -52,7 +52,7 @@ func.func @test_copy_in_optional(%box: !fir.box<!fir.array<?xf64>>, %is_present:
 // CHECK:        fir.store %[[VAL_10]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>
 // CHECK:        %[[VAL_14:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>) -> !fir.ref<!fir.box<none>>
 // CHECK:        %[[VAL_15:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?xf64>>) -> !fir.box<none>
-// CHECK:        %[[VAL_17:.*]] = fir.call @_FortranAAssign(%[[VAL_14]], %[[VAL_15]],
+// CHECK:        %[[VAL_17:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_14]], %[[VAL_15]],
 // CHECK:        %[[VAL_18:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>
 // CHECK:        %[[VAL_19:.*]] = fir.rebox %[[VAL_18]] : (!fir.box<!fir.heap<!fir.array<?xf64>>>) -> !fir.box<!fir.array<?xf64>>
 // CHECK:        fir.result %[[VAL_19]] : !fir.box<!fir.array<?xf64>>
@@ -73,8 +73,10 @@ func.func @test_copy_out_no_copy_back(%temp: !fir.box<!fir.array<?xf64>>, %was_c
 // CHECK-SAME:    %[[VAL_0:.*]]: !fir.box<!fir.array<?xf64>>,
 // CHECK-SAME:    %[[VAL_1:.*]]: i1) {
 // CHECK-NEXT:    fir.if %[[VAL_1]] {
-// CHECK-NEXT:      %[[VAL_2:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box<!fir.array<?xf64>>) -> !fir.heap<!fir.array<?xf64>>
-// CHECK-NEXT:      fir.freemem %[[VAL_2]] : !fir.heap<!fir.array<?xf64>>
+// CHECK-NEXT:      %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?xf64>>) -> !fir.box<none>
+// CHECK-NEXT:      %[[VAL_3:.*]] = fir.call @_FortranADestroyWithoutFinalization(%[[VAL_2]]) : (!fir.box<none>) -> none
+// CHECK-NEXT:      %[[VAL_4:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box<!fir.array<?xf64>>) -> !fir.heap<!fir.array<?xf64>>
+// CHECK-NEXT:      fir.freemem %[[VAL_4]] : !fir.heap<!fir.array<?xf64>>
 // CHECK-NEXT:    }
 
 func.func @test_copy_out_copy_back(%box: !fir.box<!fir.array<?xf64>>, %temp: !fir.box<!fir.array<?xf64>>, %was_copied: i1) {
@@ -88,11 +90,14 @@ func.func @test_copy_out_copy_back(%box: !fir.box<!fir.array<?xf64>>, %temp: !fi
 // CHECK:    %[[VAL_3:.*]] = fir.alloca !fir.box<!fir.array<?xf64>>
 // CHECK:    fir.if %[[VAL_2]] {
 // CHECK:      fir.store %[[VAL_0]] to %[[VAL_3]] : !fir.ref<!fir.box<!fir.array<?xf64>>>
-// CHECK:      %[[VAL_7:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.box<!fir.array<?xf64>>>) -> !fir.ref<!fir.box<none>>
-// CHECK:      %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.box<!fir.array<?xf64>>) -> !fir.box<none>
-// CHECK:      %[[VAL_10:.*]] = fir.call @_FortranAAssign(%[[VAL_7]], %[[VAL_8]],
-// CHECK:      %[[VAL_11:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?xf64>>) -> !fir.heap<!fir.array<?xf64>>
-// CHECK:      fir.freemem %[[VAL_11]] : !fir.heap<!fir.array<?xf64>>
+// CHECK:      %[[VAL_7:.*]] = arith.constant true
+// CHECK:      %[[VAL_8:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<!fir.box<!fir.array<?xf64>>>) -> !fir.ref<!fir.box<none>>
+// CHECK:      %[[VAL_9:.*]] = fir.convert %[[VAL_1]] : (!fir.box<!fir.array<?xf64>>) -> !fir.box<none>
+// CHECK:      %[[VAL_11:.*]] = fir.call @_FortranACopyOutAssign(%[[VAL_8]], %[[VAL_9]], %[[VAL_7]],
+// CHECK:      %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.box<!fir.array<?xf64>>) -> !fir.box<none>
+// CHECK:      %[[VAL_13:.*]] = fir.call @_FortranADestroyWithoutFinalization(%[[VAL_12]]) : (!fir.box<none>) -> none
+// CHECK:      %[[VAL_14:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box<!fir.array<?xf64>>) -> !fir.heap<!fir.array<?xf64>>
+// CHECK:      fir.freemem %[[VAL_14]] : !fir.heap<!fir.array<?xf64>>
 // CHECK:    }
 
 func.func @test_copy_in_poly(%poly : !fir.class<!fir.array<?x!fir.type<test_copy_in_polyTt1{i:i32}>>>) {
@@ -118,7 +123,7 @@ func.func @test_copy_in_poly(%poly : !fir.class<!fir.array<?x!fir.type<test_copy
 // CHECK:             %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<test_copy_in_polyTt1{i:i32}>>>>>) -> !fir.ref<!fir.box<none>>
 // CHECK:             %[[VAL_13:.*]] = fir.convert %[[VAL_0]] : (!fir.class<!fir.array<?x!fir.type<test_copy_in_polyTt1{i:i32}>>>) -> !fir.box<none>
 // CHECK:             %[[VAL_14:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
-// CHECK:             %[[VAL_15:.*]] = fir.call @_FortranAAssign(%[[VAL_12]], %[[VAL_13]], %[[VAL_14]], %[[VAL_11]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+// CHECK:             %[[VAL_15:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_12]], %[[VAL_13]], %[[VAL_14]], %[[VAL_11]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
 // CHECK:             %[[VAL_16:.*]] = fir.load %[[VAL_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<test_copy_in_polyTt1{i:i32}>>>>>
 // CHECK:             %[[VAL_17:.*]] = fir.rebox %[[VAL_16]] : (!fir.box<!fir.heap<!fir.array<?x!fir.type<test_copy_in_polyTt1{i:i32}>>>>) -> !fir.class<!fir.array<?x!fir.type<test_copy_in_polyTt1{i:i32}>>>
 // CHECK:             fir.result %[[VAL_17]] : !fir.class<!fir.array<?x!fir.type<test_copy_in_polyTt1{i:i32}>>>

diff  --git a/flang/test/Lower/call-by-value-attr.f90 b/flang/test/Lower/call-by-value-attr.f90
index 1e4ca4cd03c39..33060e0e9401f 100644
--- a/flang/test/Lower/call-by-value-attr.f90
+++ b/flang/test/Lower/call-by-value-attr.f90
@@ -78,7 +78,7 @@ end subroutine subra
   !CHECK: fir.store %[[TEMP_BOX]] to %[[TEMP_BOX_LOC:.*]] : !fir.ref<!fir.box<!fir.array<11xi32>>>
   !CHECK: %[[TEMP_BOX_ADDR:.*]] = fir.convert %[[TEMP_BOX_LOC]] : (!fir.ref<!fir.box<!fir.array<11xi32>>>) -> !fir.ref<!fir.box<none>>
   !CHECK: %[[BOX_ADDR:.*]] = fir.convert %[[BOX]] : (!fir.box<!fir.array<11xi32>>) -> !fir.box<none>
-  !CHECK: fir.call @_FortranAAssign(%[[TEMP_BOX_ADDR]], %[[BOX_ADDR]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+  !CHECK: fir.call @_FortranAAssignTemporary(%[[TEMP_BOX_ADDR]], %[[BOX_ADDR]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
   !CHECK: fir.result %[[ARRAY_COPY_2]] : !fir.heap<!fir.array<11xi32>>
   !CHECK: %[[CONVERT_B:.*]] = fir.convert %[[ADDR]] : (!fir.heap<!fir.array<11xi32>>) -> !fir.ref<!fir.array<10xi32>>
   !CHECK: fir.call @_QPsubra(%[[CONVERT_B]])

diff  --git a/flang/test/Lower/call-copy-in-out.f90 b/flang/test/Lower/call-copy-in-out.f90
index d6e21c73e3b7c..bcc2f81cf6bee 100644
--- a/flang/test/Lower/call-copy-in-out.f90
+++ b/flang/test/Lower/call-copy-in-out.f90
@@ -23,7 +23,7 @@ subroutine test_assumed_shape_to_array(x)
 ! CHECK-DAG:  fir.store %[[temp_box]] to %[[temp_box_loc:.*]] : !fir.ref<!fir.box<!fir.array<?xf32>>>
 ! CHECK-DAG: %[[temp_box_addr:.*]] = fir.convert %[[temp_box_loc]] : (!fir.ref<!fir.box<!fir.array<?xf32>>>) -> !fir.ref<!fir.box<none>>
 ! CHECK-DAG: %[[arg_box:.*]] = fir.convert %[[x]] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<none>
-! CHECK-DAG: fir.call @_FortranAAssign(%[[temp_box_addr]], %[[arg_box]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+! CHECK-DAG: fir.call @_FortranAAssignTemporary(%[[temp_box_addr]], %[[arg_box]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
 ! CHECK:  fir.result %[[temp]] : !fir.heap<!fir.array<?xf32>>
 
 ! CHECK:  %[[dim:.*]]:3 = fir.box_dims %[[x]], %c0{{.*}} : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
@@ -34,9 +34,10 @@ subroutine test_assumed_shape_to_array(x)
 ! CHECK-DAG:  %[[shape:.*]] = fir.shape %[[dim]]#1 : (index) -> !fir.shape<1>
 ! CHECK-DAG:  %[[temp_box:.*]] = fir.embox %[[addr]](%[[shape]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
 ! CHECK-DAG:  fir.store %[[x]] to %[[arg_box_loc:.*]] : !fir.ref<!fir.box<!fir.array<?xf32>>>
+! CHECK-DAG:  %[[skipToInit:.*]] = arith.constant true
 ! CHECK-DAG: %[[arg_box_addr:.*]] = fir.convert %[[arg_box_loc]] : (!fir.ref<!fir.box<!fir.array<?xf32>>>) -> !fir.ref<!fir.box<none>>
 ! CHECK-DAG: %[[temp_box_cast:.*]] = fir.convert %[[temp_box]] : (!fir.box<!fir.array<?xf32>>) -> !fir.box<none>
-! CHECK-DAG: fir.call @_FortranAAssign(%[[arg_box_addr]], %[[temp_box_cast]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+! CHECK-DAG: fir.call @_FortranACopyOutAssign(%[[arg_box_addr]], %[[temp_box_cast]], %[[skipToInit]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref<!fir.box<none>>, !fir.box<none>, i1, !fir.ref<i8>, i32) -> none
 ! CHECK: fir.freemem %[[addr]] : !fir.heap<!fir.array<?xf32>>
 
   call bar(x)
@@ -57,7 +58,7 @@ subroutine eval_expr_only_once(x)
 
 ! CHECK: %[[temp:.*]] = fir.allocmem !fir.array<?xf32>
 ! CHECK-NOT: fir.call @_QPonly_once()
-! CHECK:  fir.call @_FortranAAssign
+! CHECK:  fir.call @_FortranAAssignTemporary
 ! CHECK-NOT: fir.call @_QPonly_once()
 
 ! CHECK:  %[[cast:.*]] = fir.convert %[[addr]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
@@ -65,7 +66,7 @@ subroutine eval_expr_only_once(x)
   call bar(x(1:200:only_once()))
 
 ! CHECK-NOT: fir.call @_QPonly_once()
-! CHECK:  fir.call @_FortranAAssign
+! CHECK:  fir.call @_FortranACopyOutAssign
 ! CHECK-NOT: fir.call @_QPonly_once()
 
 ! CHECK: fir.freemem %[[addr]] : !fir.heap<!fir.array<?xf32>>
@@ -77,10 +78,10 @@ subroutine eval_expr_only_once(x)
 subroutine test_contiguous(x)
   real, contiguous :: x(:)
 ! CHECK: %[[addr:.*]] = fir.box_addr %[[x]] : (!fir.box<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
-! CHECK-NOT:  fir.call @_FortranAAssign
+! CHECK-NOT:  fir.call @_FortranAAssignTemporary
 ! CHECK: fir.call @_QPbar(%[[addr]]) {{.*}}: (!fir.ref<!fir.array<?xf32>>) -> ()
   call bar(x)
-! CHECK-NOT:  fir.call @_FortranAAssign
+! CHECK-NOT:  fir.call @_FortranACopyOutAssign
 ! CHECK: return
 end subroutine
 
@@ -95,7 +96,7 @@ subroutine test_parenthesis(x)
 ! CHECK:  %[[cast:.*]] = fir.convert %[[temp]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
 ! CHECK:  fir.call @_QPbar(%[[cast]]) {{.*}}: (!fir.ref<!fir.array<?xf32>>) -> ()
   call bar((x))
-! CHECK-NOT:  fir.call @_FortranAAssign
+! CHECK-NOT:  fir.call @_FortranACopyOutAssign
 ! CHECK: fir.freemem %[[temp]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK: return
 end subroutine
@@ -116,14 +117,14 @@ subroutine bar_intent_out(x)
 ! CHECK: } else {
 ! CHECK: %[[dim:.*]]:3 = fir.box_dims %[[x]], %c0{{.*}} : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
 ! CHECK: %[[temp:.*]] = fir.allocmem !fir.array<?xf32>, %[[dim]]#1
-! CHECK-NOT:  fir.call @_FortranAAssign
+! CHECK-NOT:  fir.call @_FortranAAssignTemporary
 ! CHECK: %[[not_contiguous:.*]] = arith.cmpi eq, %[[is_contiguous]], %false{{.*}} : i1
 ! CHECK:  %[[cast:.*]] = fir.convert %[[addr]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<100xf32>>
 ! CHECK:  fir.call @_QPbar_intent_out(%[[cast]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
   call bar_intent_out(x)
   
 ! CHECK: fir.if %[[not_contiguous]]
-! CHECK: fir.call @_FortranAAssign
+! CHECK: fir.call @_FortranACopyOutAssign
 ! CHECK: fir.freemem %[[addr]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK: return
 end subroutine
@@ -148,13 +149,13 @@ subroutine bar_intent_in(x)
 ! CHECK: %[[temp_box:.*]] = fir.embox %[[temp]](%[[temp_shape]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
 ! CHECK: fir.store %[[temp_box]] to %[[temp_box_loc:.*]] : !fir.ref<!fir.box<!fir.array<?xf32>>>
 ! CHECK: %[[temp_box_addr:.*]] = fir.convert %[[temp_box_loc]] : (!fir.ref<!fir.box<!fir.array<?xf32>>>) -> !fir.ref<!fir.box<none>>
-! CHECK: fir.call @_FortranAAssign(%[[temp_box_addr]],
+! CHECK: fir.call @_FortranAAssignTemporary(%[[temp_box_addr]],
 ! CHECK: %[[not_contiguous:.*]] = arith.cmpi eq, %[[is_contiguous]], %false{{.*}} : i1
 ! CHECK:  %[[cast:.*]] = fir.convert %[[addr]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<100xf32>>
 ! CHECK:  fir.call @_QPbar_intent_in(%[[cast]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
   call bar_intent_in(x)
 ! CHECK: fir.if %[[not_contiguous]]
-! CHECK-NOT:  fir.call @_FortranAAssign
+! CHECK-NOT:  fir.call @_FortranACopyOutAssign
 ! CHECK: fir.freemem %[[addr]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK: return
 end subroutine
@@ -181,7 +182,7 @@ subroutine bar_intent_inout(x)
 ! CHECK:  fir.call @_QPbar_intent_inout(%[[cast]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
   call bar_intent_inout(x)
 ! CHECK: fir.if %[[not_contiguous]]
-! CHECK:  fir.call @_FortranAAssign
+! CHECK:  fir.call @_FortranACopyOutAssign
 ! CHECK: fir.freemem %[[addr]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK: return
 end subroutine
@@ -190,48 +191,43 @@ subroutine bar_intent_inout(x)
 ! CHECK-LABEL: func @_QPtest_char(
 ! CHECK-SAME:    %[[VAL_0:.*]]: !fir.box<!fir.array<?x!fir.char<1,10>>>{{.*}}) {
 subroutine test_char(x)
-  ! CHECK:         %[[VAL_1:.*]] = fir.alloca !fir.box<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:         %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:         %[[VAL_3:.*]] = arith.constant 10 : index
-  ! CHECK:         %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.box<none>
-  ! CHECK:         %[[VAL_5:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_4]]) fastmath<contract> : (!fir.box<none>) -> i1
-  ! CHECK:         %[[VAL_6:.*]] = fir.if %[[VAL_5]] -> (!fir.heap<!fir.array<?x!fir.char<1,10>>>) {
-  ! CHECK:           %[[VAL_7:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.heap<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:           fir.result %[[VAL_7]] : !fir.heap<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:         } else {
-  ! CHECK:           %[[VAL_8:.*]] = arith.constant 0 : index
-  ! CHECK:           %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_8]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>, index) -> (index, index, index)
-  ! CHECK:           %[[VAL_10:.*]] = fir.allocmem !fir.array<?x!fir.char<1,10>>, %[[VAL_9]]#1 {uniq_name = ".copyinout"}
-  ! CHECK:           %[[VAL_11:.*]] = fir.shape %[[VAL_9]]#1 : (index) -> !fir.shape<1>
-  ! CHECK:           %[[VAL_12:.*]] = fir.embox %[[VAL_10]](%[[VAL_11]]) : (!fir.heap<!fir.array<?x!fir.char<1,10>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:           fir.store %[[VAL_12]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>
-  ! CHECK:           %[[VAL_13:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
-  ! CHECK:           %[[VAL_14:.*]] = arith.constant {{.*}} : i32
-  ! CHECK:           %[[VAL_15:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>) -> !fir.ref<!fir.box<none>>
-  ! CHECK:           %[[VAL_16:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.box<none>
-  ! CHECK:           %[[VAL_17:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
-  ! CHECK:           %[[VAL_18:.*]] = fir.call @_FortranAAssign(%[[VAL_15]], %[[VAL_16]], %[[VAL_17]], %[[VAL_14]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
-  ! CHECK:           fir.result %[[VAL_10]] : !fir.heap<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:         }
-  ! CHECK:         %[[VAL_19:.*]] = arith.constant 0 : index
-  ! CHECK:         %[[VAL_20:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_19]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>, index) -> (index, index, index)
-  ! CHECK:         %[[VAL_21:.*]] = arith.constant false
-  ! CHECK:         %[[VAL_22:.*]] = arith.cmpi eq, %[[VAL_5]], %[[VAL_21]] : i1
-  ! CHECK:         %[[VAL_23:.*]] = fir.convert %[[VAL_24:.*]] : (!fir.heap<!fir.array<?x!fir.char<1,10>>>) -> !fir.ref<!fir.char<1,?>>
-  ! CHECK:         %[[VAL_25:.*]] = fir.emboxchar %[[VAL_23]], %[[VAL_3]] : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
-  ! CHECK:         fir.call @_QPbar_char(%[[VAL_25]]) fastmath<contract> : (!fir.boxchar<1>) -> ()
-  ! CHECK:         fir.if %[[VAL_22]] {
-  ! CHECK:           %[[VAL_26:.*]] = fir.shape %[[VAL_20]]#1 : (index) -> !fir.shape<1>
-  ! CHECK:           %[[VAL_27:.*]] = fir.embox %[[VAL_24]](%[[VAL_26]]) : (!fir.heap<!fir.array<?x!fir.char<1,10>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:           fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>
-  ! CHECK:           %[[VAL_28:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1,{{.*}}>>
-  ! CHECK:           %[[VAL_29:.*]] = arith.constant {{.*}} : i32
-  ! CHECK:           %[[VAL_30:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>) -> !fir.ref<!fir.box<none>>
-  ! CHECK:           %[[VAL_31:.*]] = fir.convert %[[VAL_27]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.box<none>
-  ! CHECK:           %[[VAL_32:.*]] = fir.convert %[[VAL_28]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
-  ! CHECK:           %[[VAL_33:.*]] = fir.call @_FortranAAssign(%[[VAL_30]], %[[VAL_31]], %[[VAL_32]], %[[VAL_29]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
-  ! CHECK:           fir.freemem %[[VAL_24]] : !fir.heap<!fir.array<?x!fir.char<1,10>>>
-  ! CHECK:         }
+! CHECK:           %[[VAL_1:.*]] = fir.alloca !fir.box<!fir.array<?x!fir.char<1,10>>>
+! CHECK:           %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.array<?x!fir.char<1,10>>>
+! CHECK:           %[[VAL_3:.*]] = arith.constant 10 : index
+! CHECK:           %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.box<none>
+! CHECK:           %[[VAL_5:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_4]]) fastmath<contract> : (!fir.box<none>) -> i1
+! CHECK:           %[[VAL_6:.*]] = fir.if %[[VAL_5]] -> (!fir.heap<!fir.array<?x!fir.char<1,10>>>) {
+! CHECK:             %[[VAL_7:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.heap<!fir.array<?x!fir.char<1,10>>>
+! CHECK:             fir.result %[[VAL_7]] : !fir.heap<!fir.array<?x!fir.char<1,10>>>
+! CHECK:           } else {
+! CHECK:             %[[VAL_8:.*]] = arith.constant 0 : index
+! CHECK:             %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_8]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>, index) -> (index, index, index)
+! CHECK:             %[[VAL_10:.*]] = fir.allocmem !fir.array<?x!fir.char<1,10>>, %[[VAL_9]]#1 {uniq_name = ".copyinout"}
+! CHECK:             %[[VAL_11:.*]] = fir.shape %[[VAL_9]]#1 : (index) -> !fir.shape<1>
+! CHECK:             %[[VAL_12:.*]] = fir.embox %[[VAL_10]](%[[VAL_11]]) : (!fir.heap<!fir.array<?x!fir.char<1,10>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.char<1,10>>>
+! CHECK:             fir.store %[[VAL_12]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>
+! CHECK:             %[[VAL_15:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK:             %[[VAL_16:.*]] = fir.convert %[[VAL_0]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.box<none>
+! CHECK:             %[[VAL_18:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_15]], %[[VAL_16]], %{{.*}}, %{{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+! CHECK:             fir.result %[[VAL_10]] : !fir.heap<!fir.array<?x!fir.char<1,10>>>
+! CHECK:           }
+! CHECK:           %[[VAL_19:.*]] = arith.constant 0 : index
+! CHECK:           %[[VAL_20:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_19]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>, index) -> (index, index, index)
+! CHECK:           %[[VAL_21:.*]] = arith.constant false
+! CHECK:           %[[VAL_22:.*]] = arith.cmpi eq, %[[VAL_5]], %[[VAL_21]] : i1
+! CHECK:           %[[VAL_23:.*]] = fir.convert %[[VAL_24:.*]] : (!fir.heap<!fir.array<?x!fir.char<1,10>>>) -> !fir.ref<!fir.char<1,?>>
+! CHECK:           %[[VAL_25:.*]] = fir.emboxchar %[[VAL_23]], %[[VAL_3]] : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
+! CHECK:           fir.call @_QPbar_char(%[[VAL_25]]) fastmath<contract> : (!fir.boxchar<1>) -> ()
+! CHECK:           fir.if %[[VAL_22]] {
+! CHECK:             %[[VAL_26:.*]] = fir.shape %[[VAL_20]]#1 : (index) -> !fir.shape<1>
+! CHECK:             %[[VAL_27:.*]] = fir.embox %[[VAL_24]](%[[VAL_26]]) : (!fir.heap<!fir.array<?x!fir.char<1,10>>>, !fir.shape<1>) -> !fir.box<!fir.array<?x!fir.char<1,10>>>
+! CHECK:             fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>
+! CHECK:             %[[VAL_30:.*]] = arith.constant true
+! CHECK:             %[[VAL_31:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.array<?x!fir.char<1,10>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK:             %[[VAL_32:.*]] = fir.convert %[[VAL_27]] : (!fir.box<!fir.array<?x!fir.char<1,10>>>) -> !fir.box<none>
+! CHECK:             %[[VAL_34:.*]] = fir.call @_FortranACopyOutAssign(%[[VAL_31]], %[[VAL_32]], %[[VAL_30]], %{{.*}}, %{{.*}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, i1, !fir.ref<i8>, i32) -> none
+! CHECK:             fir.freemem %[[VAL_24]] : !fir.heap<!fir.array<?x!fir.char<1,10>>>
+! CHECK:           }
   
   character(10) :: x(:)
   call bar_char(x)

diff  --git a/flang/test/Lower/dummy-argument-assumed-shape-optional.f90 b/flang/test/Lower/dummy-argument-assumed-shape-optional.f90
index 01f774f1713f1..6a5a830fb67a5 100644
--- a/flang/test/Lower/dummy-argument-assumed-shape-optional.f90
+++ b/flang/test/Lower/dummy-argument-assumed-shape-optional.f90
@@ -40,7 +40,7 @@ subroutine test_assumed_shape_to_contiguous(x)
 ! CHECK:  %[[VAL_25:.*]] = fir.embox %[[VAL_3]](%[[VAL_24]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
 ! CHECK:  fir.call @_QPtakes_contiguous(%[[VAL_25]]) {{.*}}: (!fir.box<!fir.array<?xf32>>) -> ()
 ! CHECK:  fir.if %[[VAL_23]] {
-! CHECK:    fir.call @_FortranAAssign
+! CHECK:    fir.call @_FortranACopyOutAssign
 ! CHECK:    fir.freemem %[[VAL_3]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:  }
 ! CHECK:  return
@@ -85,7 +85,7 @@ subroutine test_assumed_shape_opt_to_contiguous(x)
 ! CHECK:  %[[VAL_25:.*]] = fir.embox %[[VAL_3]](%[[VAL_24]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
 ! CHECK:  fir.call @_QPtakes_contiguous(%[[VAL_25]]) {{.*}}: (!fir.box<!fir.array<?xf32>>) -> ()
 ! CHECK:  fir.if %[[VAL_23]] {
-! CHECK:    fir.call @_FortranAAssign
+! CHECK:    fir.call @_FortranACopyOutAssign
 ! CHECK:    fir.freemem %[[VAL_3]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:  }
 ! CHECK:  return
@@ -131,7 +131,7 @@ subroutine test_assumed_shape_to_contiguous_opt(x)
 ! CHECK:  %[[VAL_25:.*]] = fir.embox %[[VAL_3]](%[[VAL_24]]) : (!fir.heap<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<?xf32>>
 ! CHECK:  fir.call @_QPtakes_contiguous_optional(%[[VAL_25]]) {{.*}}: (!fir.box<!fir.array<?xf32>>) -> ()
 ! CHECK:  fir.if %[[VAL_23]] {
-! CHECK:    fir.call @_FortranAAssign
+! CHECK:    fir.call @_FortranACopyOutAssign
 ! CHECK:    fir.freemem %[[VAL_3]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:  }
 ! CHECK:  return
@@ -191,7 +191,7 @@ subroutine test_assumed_shape_opt_to_contiguous_opt(x)
 ! CHECK:  %[[VAL_38:.*]] = arith.select %[[VAL_1]], %[[VAL_35]], %[[VAL_37]] : !fir.box<!fir.array<?xf32>>
 ! CHECK:  fir.call @_QPtakes_contiguous_optional(%[[VAL_38]]) {{.*}}: (!fir.box<!fir.array<?xf32>>) -> ()
 ! CHECK:  fir.if %[[VAL_33]] {
-! CHECK:    fir.call @_FortranAAssign
+! CHECK:    fir.call @_FortranACopyOutAssign
 ! CHECK:    fir.freemem %[[VAL_9]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:  }
 ! CHECK:  return
@@ -254,7 +254,7 @@ subroutine test_pointer_to_contiguous_opt(x)
 ! CHECK:  %[[VAL_41:.*]] = arith.select %[[VAL_5]], %[[VAL_38]], %[[VAL_40]] : !fir.box<!fir.array<?xf32>>
 ! CHECK:  fir.call @_QPtakes_contiguous_optional(%[[VAL_41]]) {{.*}}: (!fir.box<!fir.array<?xf32>>) -> ()
 ! CHECK:  fir.if %[[VAL_36]] {
-! CHECK:    fir.call @_FortranAAssign
+! CHECK:    fir.call @_FortranACopyOutAssign
 ! CHECK:    fir.freemem %[[VAL_11]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:  }
 ! CHECK:  return
@@ -323,7 +323,7 @@ subroutine test_pointer_opt_to_contiguous_opt(x)
 ! CHECK:  %[[VAL_41:.*]] = arith.select %[[VAL_5]], %[[VAL_38]], %[[VAL_40]] : !fir.box<!fir.array<?xf32>>
 ! CHECK:  fir.call @_QPtakes_contiguous_optional(%[[VAL_41]]) {{.*}}: (!fir.box<!fir.array<?xf32>>) -> ()
 ! CHECK:  fir.if %[[VAL_36]] {
-! CHECK:    fir.call @_FortranAAssign
+! CHECK:    fir.call @_FortranACopyOutAssign
 ! CHECK:    fir.freemem %[[VAL_11]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:  }
 ! CHECK:  return

diff  --git a/flang/test/Lower/dummy-argument-optional-2.f90 b/flang/test/Lower/dummy-argument-optional-2.f90
index ab43fd9167797..82b7e612c924e 100644
--- a/flang/test/Lower/dummy-argument-optional-2.f90
+++ b/flang/test/Lower/dummy-argument-optional-2.f90
@@ -111,7 +111,7 @@ subroutine pass_pointer_array(i)
 ! CHECK:           %[[VAL_10:.*]] = arith.constant 0 : index
 ! CHECK:           %[[VAL_11:.*]]:3 = fir.box_dims %[[box]], %[[VAL_10]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>, index) -> (index, index, index)
 ! CHECK:           %[[VAL_12:.*]] = fir.allocmem !fir.array<?xf32>, %[[VAL_11]]#1 {uniq_name = ".copyinout"}
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranAAssignTemporary
 ! CHECK:           fir.result %[[VAL_12]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         } else {
 ! CHECK:           %[[VAL_26:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
@@ -122,7 +122,7 @@ subroutine pass_pointer_array(i)
 ! CHECK:         %[[VAL_29:.*]] = fir.convert %[[VAL_9]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<100xf32>>
 ! CHECK:         fir.call @_QPtakes_opt_explicit_shape(%[[VAL_29]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
 ! CHECK:         fir.if %[[and]] {
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranACopyOutAssign
 ! CHECK:           fir.freemem %[[VAL_9]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         }
 end subroutine
@@ -145,7 +145,7 @@ subroutine pass_pointer_array_char(c)
 ! CHECK:           %[[VAL_11:.*]]:3 = fir.box_dims %[[VAL_6]], %[[VAL_10]] : (!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>, index) -> (index, index, index)
 ! CHECK:           %[[VAL_12:.*]] = fir.box_elesize %[[VAL_6]] : (!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,?>>>>) -> index
 ! CHECK:           %[[VAL_13:.*]] = fir.allocmem !fir.array<?x!fir.char<1,?>>(%[[VAL_12]] : index), %[[VAL_11]]#1 {uniq_name = ".copyinout"}
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranAAssignTemporary
 ! CHECK:           fir.result %[[VAL_13]] : !fir.heap<!fir.array<?x!fir.char<1,?>>>
 ! CHECK:         } else {
 ! CHECK:           %[[VAL_46:.*]] = fir.zero_bits !fir.heap<!fir.array<?x!fir.char<1,?>>>
@@ -158,7 +158,7 @@ subroutine pass_pointer_array_char(c)
 ! CHECK:         %[[VAL_52:.*]] = fir.emboxchar %[[VAL_50]], %[[VAL_47]] : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
 ! CHECK:         fir.call @_QPtakes_opt_explicit_shape_char(%[[VAL_52]]) {{.*}}: (!fir.boxchar<1>) -> ()
 ! CHECK:         fir.if %[[and]] {
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranACopyOutAssign
 ! CHECK:           fir.freemem %[[VAL_9]] : !fir.heap<!fir.array<?x!fir.char<1,?>>>
 ! CHECK:         }
 ! CHECK:         return
@@ -182,7 +182,7 @@ subroutine forward_pointer_array()
 ! CHECK:         %[[is_contiguous:.*]] = fir.call @_FortranAIsContiguous(%{{.*}}) {{.*}}: (!fir.box<none>) -> i1
 ! CHECK:         %[[VAL_7:.*]] = fir.if %[[VAL_6]] -> (!fir.heap<!fir.array<?xf32>>) {
 ! CHECK:           %[[VAL_10:.*]] = fir.allocmem !fir.array<?xf32>
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranAAssignTemporary
 ! CHECK:           fir.result %[[VAL_10]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         } else {
 ! CHECK:           %[[VAL_11:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
@@ -193,7 +193,7 @@ subroutine forward_pointer_array()
 ! CHECK:         %[[VAL_14:.*]] = fir.convert %[[VAL_7]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<100xf32>>
 ! CHECK:         fir.call @_QPtakes_opt_explicit_shape(%[[VAL_14]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
 ! CHECK:         fir.if %[[and]] {
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranACopyOutAssign
 ! CHECK:           fir.freemem %[[VAL_7]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         }
 end subroutine
@@ -221,7 +221,7 @@ subroutine pass_opt_assumed_shape(x)
 ! CHECK:           %[[VAL_8:.*]] = arith.constant 0 : index
 ! CHECK:           %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_6]], %[[VAL_8]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
 ! CHECK:           %[[VAL_10:.*]] = fir.allocmem !fir.array<?xf32>, %[[VAL_9]]#1 {uniq_name = ".copyinout"}
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranAAssignTemporary
 ! CHECK:           fir.result %[[VAL_10]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         } else {
 ! CHECK:           %[[VAL_23:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
@@ -232,7 +232,7 @@ subroutine pass_opt_assumed_shape(x)
 ! CHECK:         %[[VAL_26:.*]] = fir.convert %[[VAL_27:.*]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<100xf32>>
 ! CHECK:         fir.call @_QPtakes_opt_explicit_shape(%[[VAL_26]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
 ! CHECK:         fir.if %[[and]] {
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranACopyOutAssign
 ! CHECK:           fir.freemem %[[VAL_27]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         }
 end subroutine
@@ -258,7 +258,7 @@ subroutine pass_opt_assumed_shape_char(c)
 ! CHECK:         } else {
 ! CHECK:           %[[box_elesize:.*]] = fir.box_elesize %[[VAL_7]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
 ! CHECK:           %[[temp:.*]] = fir.allocmem !fir.array<?x!fir.char<1,?>>(%[[box_elesize]] : index), %{{.*}}#1 {uniq_name = ".copyinout"}
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranAAssignTemporary
 ! CHECK:           fir.result %[[VAL_12]] : !fir.heap<!fir.array<?x!fir.char<1,?>>>
 ! CHECK:         } else {
 ! CHECK:           %[[VAL_44:.*]] = fir.zero_bits !fir.heap<!fir.array<?x!fir.char<1,?>>>
@@ -271,7 +271,7 @@ subroutine pass_opt_assumed_shape_char(c)
 ! CHECK:         %[[VAL_50:.*]] = fir.emboxchar %[[VAL_48]], %[[VAL_45]] : (!fir.ref<!fir.char<1,?>>, index) -> !fir.boxchar<1>
 ! CHECK:         fir.call @_QPtakes_opt_explicit_shape_char(%[[VAL_50]]) {{.*}}: (!fir.boxchar<1>) -> ()
 ! CHECK:         fir.if %[[and]] {
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranACopyOutAssign
 ! CHECK:           fir.freemem %[[VAL_49]] : !fir.heap<!fir.array<?x!fir.char<1,?>>>
 ! CHECK:         }
 end subroutine
@@ -394,7 +394,7 @@ subroutine pass_opt_assumed_shape_to_intentin(x)
 ! CHECK:         %[[is_contiguous:.*]] = fir.call @_FortranAIsContiguous(%[[box_none]]) {{.*}}: (!fir.box<none>) -> i1
 ! CHECK:         %[[VAL_7:.*]] = fir.if %[[VAL_1]] -> (!fir.heap<!fir.array<?xf32>>) {
 ! CHECK:           %[[VAL_10:.*]] = fir.allocmem !fir.array<?xf32>
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranAAssignTemporary
 ! CHECK:           fir.result %[[VAL_10]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         } else {
 ! CHECK:           %[[VAL_23:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
@@ -405,7 +405,7 @@ subroutine pass_opt_assumed_shape_to_intentin(x)
 ! CHECK:         %[[VAL_24:.*]] = fir.convert %[[VAL_7]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<100xf32>>
 ! CHECK:         fir.call @_QPtakes_opt_explicit_shape_intentin(%[[VAL_24]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
 ! CHECK:         fir.if %[[and]] {
-! CHECK-NOT:       fir.call @_FortranAAssign
+! CHECK-NOT:       fir.call @_FortranACopyOutAssign
 ! CHECK:           fir.freemem %[[VAL_7]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         }
 end subroutine
@@ -425,7 +425,7 @@ subroutine pass_opt_assumed_shape_to_intentout(x)
 ! CHECK:         %[[is_contiguous:.*]] = fir.call @_FortranAIsContiguous(%[[box_none]]) {{.*}}: (!fir.box<none>) -> i1
 ! CHECK:         %[[VAL_7:.*]] = fir.if %[[VAL_1]] -> (!fir.heap<!fir.array<?xf32>>) {
 ! CHECK:           %[[VAL_10:.*]] = fir.allocmem !fir.array<?xf32>
-! CHECK-NOT:       fir.call @_FortranAAssign
+! CHECK-NOT:       fir.call @_FortranAAssignTemporary
 ! CHECK:           fir.result %[[VAL_10]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         } else {
 ! CHECK:           %[[VAL_11:.*]] = fir.zero_bits !fir.heap<!fir.array<?xf32>>
@@ -436,7 +436,7 @@ subroutine pass_opt_assumed_shape_to_intentout(x)
 ! CHECK:         %[[VAL_14:.*]] = fir.convert %[[VAL_7]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<100xf32>>
 ! CHECK:         fir.call @_QPtakes_opt_explicit_shape_intentout(%[[VAL_14]]) {{.*}}: (!fir.ref<!fir.array<100xf32>>) -> ()
 ! CHECK:         fir.if %[[and]] {
-! CHECK:           fir.call @_FortranAAssign
+! CHECK:           fir.call @_FortranACopyOutAssign
 ! CHECK:           fir.freemem %[[VAL_7]] : !fir.heap<!fir.array<?xf32>>
 ! CHECK:         }
 end subroutine

diff  --git a/flang/test/Lower/optional-value-caller.f90 b/flang/test/Lower/optional-value-caller.f90
index b4df3415b7825..6c68e0dce5ed5 100644
--- a/flang/test/Lower/optional-value-caller.f90
+++ b/flang/test/Lower/optional-value-caller.f90
@@ -298,7 +298,7 @@ subroutine test_dyn_array_from_assumed(i, n)
 ! CHECK:  %[[VAL_25:.*]] = fir.convert %[[VAL_8]] : (!fir.heap<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
 ! CHECK:  fir.call @_QPdyn_array(%[[VAL_25]], %[[VAL_1]]) {{.*}}: (!fir.ref<!fir.array<?xi32>>, !fir.ref<i64>) -> ()
 ! CHECK:  fir.if %[[and]] {
-! CHECK-NOT: fir.call @_FortranAAssign
+! CHECK-NOT: fir.call @_FortranACopyOutAssign
 ! CHECK:    fir.freemem %[[VAL_8]] : !fir.heap<!fir.array<?xi32>>
 ! CHECK:  }
 end subroutine
@@ -333,7 +333,7 @@ subroutine test_array_ptr(i)
 ! CHECK:             %[[VAL_20:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<none>>
 ! CHECK:             %[[VAL_21:.*]] = fir.convert %[[VAL_7]] : (!fir.box<!fir.ptr<!fir.array<?xi32>>>) -> !fir.box<none>
 ! CHECK:             %[[VAL_22:.*]] = fir.convert %[[VAL_18]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
-! CHECK:             %[[VAL_23:.*]] = fir.call @_FortranAAssign(%[[VAL_20]], %[[VAL_21]], %[[VAL_22]], %[[VAL_19]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+! CHECK:             %[[VAL_23:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_20]], %[[VAL_21]], %[[VAL_22]], %[[VAL_19]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
 ! CHECK:             fir.result %[[VAL_15]] : !fir.heap<!fir.array<?xi32>>
 ! CHECK:           }
 ! CHECK:           fir.result %[[VAL_24:.*]] : !fir.heap<!fir.array<?xi32>>
@@ -439,7 +439,7 @@ subroutine test_char_array(c)
 ! CHECK:             %[[VAL_23:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.box<!fir.array<?x!fir.char<1,?>>>>) -> !fir.ref<!fir.box<none>>
 ! CHECK:             %[[VAL_24:.*]] = fir.convert %[[VAL_9]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> !fir.box<none>
 ! CHECK:             %[[VAL_25:.*]] = fir.convert %[[VAL_21]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
-! CHECK:             %[[VAL_26:.*]] = fir.call @_FortranAAssign(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_22]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+! CHECK:             %[[VAL_26:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_22]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
 ! CHECK:             fir.result %[[VAL_18]] : !fir.heap<!fir.array<?x!fir.char<1,?>>>
 ! CHECK:           }
 ! CHECK:           fir.result %[[VAL_27:.*]] : !fir.heap<!fir.array<?x!fir.char<1,?>>>


        


More information about the flang-commits mailing list