diff --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h --- a/flang/include/flang/Lower/CallInterface.h +++ b/flang/include/flang/Lower/CallInterface.h @@ -167,6 +167,11 @@ 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 --- a/flang/include/flang/Optimizer/Builder/Runtime/Assign.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Assign.h @@ -48,5 +48,26 @@ 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> and \p sourceBox a fir.box. +/// \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 --- a/flang/include/flang/Optimizer/Builder/Runtime/Derived.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Derived.h @@ -31,6 +31,12 @@ 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 --- a/flang/include/flang/Runtime/assign.h +++ b/flang/include/flang/Runtime/assign.h @@ -36,6 +36,8 @@ // 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 --- a/flang/include/flang/Runtime/derived-api.h +++ b/flang/include/flang/Runtime/derived-api.h @@ -37,6 +37,11 @@ // 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 --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -1229,6 +1229,57 @@ Fortran::evaluate::characteristics::DummyDataObject::Attr::Value); } +template +bool Fortran::lower::CallInterface::PassedEntity::hasAllocatableAttribute() + const { + if (!characteristics) + return false; + const auto *dummy = + std::get_if( + &characteristics->u); + using Attrs = Fortran::evaluate::characteristics::DummyDataObject::Attr; + return dummy && dummy->attrs.test(Attrs::Allocatable); +} + +template +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( + &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 void Fortran::lower::CallInterface::determineInterface( bool isImplicit, diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -925,6 +925,13 @@ // Copy-in non contiguous variables. assert(entity.getType().isa() && "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( 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 --- a/flang/lib/Lower/ConvertExpr.cpp +++ b/flang/lib/Lower/ConvertExpr.cpp @@ -2153,7 +2153,27 @@ 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()) { + mlir::Value tempBox = fir::getBase(builder.createBox(loc, temp)); + fir::runtime::genDerivedTypeInitialize(builder, loc, tempBox); + } return temp; } if (!isActualArgBox || inlineCopyInOutForBoxes) { @@ -2161,12 +2181,16 @@ 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(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 @@ 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(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()) { + // 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(loc, fir::getBase(copyOutPair.temp)); return; } @@ -2294,6 +2334,17 @@ builder.genIfThen(loc, *copyOutPair.restrictCopyAndFreeAtRuntime) .genThen([&]() { doCopyOut(); + if (fir::getElementTypeOf(copyOutPair.temp).isa()) { + // 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(loc, fir::getBase(copyOutPair.temp)); }) .end(); diff --git a/flang/lib/Optimizer/Builder/Runtime/Assign.cpp b/flang/lib/Optimizer/Builder/Runtime/Assign.cpp --- a/flang/lib/Optimizer/Builder/Runtime/Assign.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/Assign.cpp @@ -54,3 +54,34 @@ sourceBox, sourceFile, sourceLine); builder.create(loc, func, args); } + +void fir::runtime::genAssignTemporary(fir::FirOpBuilder &builder, + mlir::Location loc, mlir::Value destBox, + mlir::Value sourceBox) { + auto func = + fir::runtime::getRuntimeFunc(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(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(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(loc, func, args); +} diff --git a/flang/lib/Optimizer/Builder/Runtime/Derived.cpp b/flang/lib/Optimizer/Builder/Runtime/Derived.cpp --- a/flang/lib/Optimizer/Builder/Runtime/Derived.cpp +++ b/flang/lib/Optimizer/Builder/Runtime/Derived.cpp @@ -37,6 +37,15 @@ builder.create(loc, func, args); } +void fir::runtime::genDerivedTypeDestroyWithoutFinalization( + fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value box) { + auto func = fir::runtime::getRuntimeFunc( + loc, builder); + auto fTy = func.getFunctionType(); + auto args = fir::runtime::createArguments(builder, loc, fTy, box); + builder.create(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 --- 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 @@ 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(loc, fromMutableBox); return copy; } @@ -248,20 +249,32 @@ .genThen([&]() { mlir::Value temp = copyOutOp.getTemp(); if (mlir::Value var = copyOutOp.getVar()) { - auto mutableBox = builder.createTemporary(loc, var.getType()); - builder.create(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(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(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(loc, tempAddr); }) .end(); diff --git a/flang/runtime/assign.cpp b/flang/runtime/assign.cpp --- a/flang/runtime/assign.cpp +++ b/flang/runtime/assign.cpp @@ -561,9 +561,32 @@ } } } + 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 --- a/flang/runtime/derived-api.cpp +++ b/flang/runtime/derived-api.cpp @@ -156,5 +156,15 @@ 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 --- a/flang/test/HLFIR/copy-in-out-codegen.fir +++ b/flang/test/HLFIR/copy-in-out-codegen.fir @@ -21,7 +21,7 @@ // CHECK: fir.store %[[VAL_8]] to %[[VAL_1]] : !fir.ref>>> // CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>>>) -> !fir.ref> // CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box -// 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>>> // CHECK: %[[VAL_17:.*]] = fir.rebox %[[VAL_16]] : (!fir.box>>) -> !fir.box> // CHECK: fir.result %[[VAL_17]] : !fir.box> @@ -52,7 +52,7 @@ // CHECK: fir.store %[[VAL_10]] to %[[VAL_2]] : !fir.ref>>> // CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> // CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box -// 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>>> // CHECK: %[[VAL_19:.*]] = fir.rebox %[[VAL_18]] : (!fir.box>>) -> !fir.box> // CHECK: fir.result %[[VAL_19]] : !fir.box> @@ -73,8 +73,10 @@ // CHECK-SAME: %[[VAL_0:.*]]: !fir.box>, // CHECK-SAME: %[[VAL_1:.*]]: i1) { // CHECK-NEXT: fir.if %[[VAL_1]] { -// CHECK-NEXT: %[[VAL_2:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.heap> -// CHECK-NEXT: fir.freemem %[[VAL_2]] : !fir.heap> +// CHECK-NEXT: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.box>) -> !fir.box +// CHECK-NEXT: %[[VAL_3:.*]] = fir.call @_FortranADestroyWithoutFinalization(%[[VAL_2]]) : (!fir.box) -> none +// CHECK-NEXT: %[[VAL_4:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>) -> !fir.heap> +// CHECK-NEXT: fir.freemem %[[VAL_4]] : !fir.heap> // CHECK-NEXT: } func.func @test_copy_out_copy_back(%box: !fir.box>, %temp: !fir.box>, %was_copied: i1) { @@ -88,11 +90,14 @@ // CHECK: %[[VAL_3:.*]] = fir.alloca !fir.box> // CHECK: fir.if %[[VAL_2]] { // CHECK: fir.store %[[VAL_0]] to %[[VAL_3]] : !fir.ref>> -// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_3]] : (!fir.ref>>) -> !fir.ref> -// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.box>) -> !fir.box -// CHECK: %[[VAL_10:.*]] = fir.call @_FortranAAssign(%[[VAL_7]], %[[VAL_8]], -// CHECK: %[[VAL_11:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>) -> !fir.heap> -// CHECK: fir.freemem %[[VAL_11]] : !fir.heap> +// CHECK: %[[VAL_7:.*]] = arith.constant true +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_3]] : (!fir.ref>>) -> !fir.ref> +// CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_1]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_11:.*]] = fir.call @_FortranACopyOutAssign(%[[VAL_8]], %[[VAL_9]], %[[VAL_7]], +// CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_13:.*]] = fir.call @_FortranADestroyWithoutFinalization(%[[VAL_12]]) : (!fir.box) -> none +// CHECK: %[[VAL_14:.*]] = fir.box_addr %[[VAL_1]] : (!fir.box>) -> !fir.heap> +// CHECK: fir.freemem %[[VAL_14]] : !fir.heap> // CHECK: } func.func @test_copy_in_poly(%poly : !fir.class>>) { @@ -118,7 +123,7 @@ // CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>>>>) -> !fir.ref> // CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_0]] : (!fir.class>>) -> !fir.box // CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_9]] : (!fir.ref>) -> !fir.ref -// CHECK: %[[VAL_15:.*]] = fir.call @_FortranAAssign(%[[VAL_12]], %[[VAL_13]], %[[VAL_14]], %[[VAL_11]]) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +// CHECK: %[[VAL_15:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_12]], %[[VAL_13]], %[[VAL_14]], %[[VAL_11]]) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none // CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_1]] : !fir.ref>>>> // CHECK: %[[VAL_17:.*]] = fir.rebox %[[VAL_16]] : (!fir.box>>>) -> !fir.class>> // CHECK: fir.result %[[VAL_17]] : !fir.class>> diff --git a/flang/test/Lower/call-by-value-attr.f90 b/flang/test/Lower/call-by-value-attr.f90 --- a/flang/test/Lower/call-by-value-attr.f90 +++ b/flang/test/Lower/call-by-value-attr.f90 @@ -78,7 +78,7 @@ !CHECK: fir.store %[[TEMP_BOX]] to %[[TEMP_BOX_LOC:.*]] : !fir.ref>> !CHECK: %[[TEMP_BOX_ADDR:.*]] = fir.convert %[[TEMP_BOX_LOC]] : (!fir.ref>>) -> !fir.ref> !CHECK: %[[BOX_ADDR:.*]] = fir.convert %[[BOX]] : (!fir.box>) -> !fir.box - !CHECK: fir.call @_FortranAAssign(%[[TEMP_BOX_ADDR]], %[[BOX_ADDR]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref>, !fir.box, !fir.ref, i32) -> none + !CHECK: fir.call @_FortranAAssignTemporary(%[[TEMP_BOX_ADDR]], %[[BOX_ADDR]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref>, !fir.box, !fir.ref, i32) -> none !CHECK: fir.result %[[ARRAY_COPY_2]] : !fir.heap> !CHECK: %[[CONVERT_B:.*]] = fir.convert %[[ADDR]] : (!fir.heap>) -> !fir.ref> !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 --- a/flang/test/Lower/call-copy-in-out.f90 +++ b/flang/test/Lower/call-copy-in-out.f90 @@ -23,7 +23,7 @@ ! CHECK-DAG: fir.store %[[temp_box]] to %[[temp_box_loc:.*]] : !fir.ref>> ! CHECK-DAG: %[[temp_box_addr:.*]] = fir.convert %[[temp_box_loc]] : (!fir.ref>>) -> !fir.ref> ! CHECK-DAG: %[[arg_box:.*]] = fir.convert %[[x]] : (!fir.box>) -> !fir.box -! CHECK-DAG: fir.call @_FortranAAssign(%[[temp_box_addr]], %[[arg_box]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref>, !fir.box, !fir.ref, i32) -> none +! CHECK-DAG: fir.call @_FortranAAssignTemporary(%[[temp_box_addr]], %[[arg_box]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref>, !fir.box, !fir.ref, i32) -> none ! CHECK: fir.result %[[temp]] : !fir.heap> ! CHECK: %[[dim:.*]]:3 = fir.box_dims %[[x]], %c0{{.*}} : (!fir.box>, index) -> (index, index, index) @@ -34,9 +34,10 @@ ! CHECK-DAG: %[[shape:.*]] = fir.shape %[[dim]]#1 : (index) -> !fir.shape<1> ! CHECK-DAG: %[[temp_box:.*]] = fir.embox %[[addr]](%[[shape]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box> ! CHECK-DAG: fir.store %[[x]] to %[[arg_box_loc:.*]] : !fir.ref>> +! CHECK-DAG: %[[skipToInit:.*]] = arith.constant true ! CHECK-DAG: %[[arg_box_addr:.*]] = fir.convert %[[arg_box_loc]] : (!fir.ref>>) -> !fir.ref> ! CHECK-DAG: %[[temp_box_cast:.*]] = fir.convert %[[temp_box]] : (!fir.box>) -> !fir.box -! CHECK-DAG: fir.call @_FortranAAssign(%[[arg_box_addr]], %[[temp_box_cast]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref>, !fir.box, !fir.ref, i32) -> none +! CHECK-DAG: fir.call @_FortranACopyOutAssign(%[[arg_box_addr]], %[[temp_box_cast]], %[[skipToInit]], %{{.*}}, %{{.*}}){{.*}}: (!fir.ref>, !fir.box, i1, !fir.ref, i32) -> none ! CHECK: fir.freemem %[[addr]] : !fir.heap> call bar(x) @@ -57,7 +58,7 @@ ! CHECK: %[[temp:.*]] = fir.allocmem !fir.array ! 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.ref> @@ -65,7 +66,7 @@ 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> @@ -77,10 +78,10 @@ subroutine test_contiguous(x) real, contiguous :: x(:) ! CHECK: %[[addr:.*]] = fir.box_addr %[[x]] : (!fir.box>) -> !fir.ref> -! CHECK-NOT: fir.call @_FortranAAssign +! CHECK-NOT: fir.call @_FortranAAssignTemporary ! CHECK: fir.call @_QPbar(%[[addr]]) {{.*}}: (!fir.ref>) -> () call bar(x) -! CHECK-NOT: fir.call @_FortranAAssign +! CHECK-NOT: fir.call @_FortranACopyOutAssign ! CHECK: return end subroutine @@ -95,7 +96,7 @@ ! CHECK: %[[cast:.*]] = fir.convert %[[temp]] : (!fir.heap>) -> !fir.ref> ! CHECK: fir.call @_QPbar(%[[cast]]) {{.*}}: (!fir.ref>) -> () call bar((x)) -! CHECK-NOT: fir.call @_FortranAAssign +! CHECK-NOT: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[temp]] : !fir.heap> ! CHECK: return end subroutine @@ -116,14 +117,14 @@ ! CHECK: } else { ! CHECK: %[[dim:.*]]:3 = fir.box_dims %[[x]], %c0{{.*}} : (!fir.box>, index) -> (index, index, index) ! CHECK: %[[temp:.*]] = fir.allocmem !fir.array, %[[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.ref> ! CHECK: fir.call @_QPbar_intent_out(%[[cast]]) {{.*}}: (!fir.ref>) -> () call bar_intent_out(x) ! CHECK: fir.if %[[not_contiguous]] -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[addr]] : !fir.heap> ! CHECK: return end subroutine @@ -148,13 +149,13 @@ ! CHECK: %[[temp_box:.*]] = fir.embox %[[temp]](%[[temp_shape]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box> ! CHECK: fir.store %[[temp_box]] to %[[temp_box_loc:.*]] : !fir.ref>> ! CHECK: %[[temp_box_addr:.*]] = fir.convert %[[temp_box_loc]] : (!fir.ref>>) -> !fir.ref> -! 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.ref> ! CHECK: fir.call @_QPbar_intent_in(%[[cast]]) {{.*}}: (!fir.ref>) -> () 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> ! CHECK: return end subroutine @@ -181,7 +182,7 @@ ! CHECK: fir.call @_QPbar_intent_inout(%[[cast]]) {{.*}}: (!fir.ref>) -> () call bar_intent_inout(x) ! CHECK: fir.if %[[not_contiguous]] -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[addr]] : !fir.heap> ! CHECK: return end subroutine @@ -190,48 +191,43 @@ ! CHECK-LABEL: func @_QPtest_char( ! CHECK-SAME: %[[VAL_0:.*]]: !fir.box>>{{.*}}) { subroutine test_char(x) - ! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box>> - ! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box>> - ! CHECK: %[[VAL_3:.*]] = arith.constant 10 : index - ! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box - ! CHECK: %[[VAL_5:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_4]]) fastmath : (!fir.box) -> i1 - ! CHECK: %[[VAL_6:.*]] = fir.if %[[VAL_5]] -> (!fir.heap>>) { - ! CHECK: %[[VAL_7:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> - ! CHECK: fir.result %[[VAL_7]] : !fir.heap>> - ! CHECK: } else { - ! CHECK: %[[VAL_8:.*]] = arith.constant 0 : index - ! CHECK: %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_8]] : (!fir.box>>, index) -> (index, index, index) - ! CHECK: %[[VAL_10:.*]] = fir.allocmem !fir.array>, %[[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.shape<1>) -> !fir.box>> - ! CHECK: fir.store %[[VAL_12]] to %[[VAL_2]] : !fir.ref>>> - ! CHECK: %[[VAL_13:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref> - ! CHECK: %[[VAL_14:.*]] = arith.constant {{.*}} : i32 - ! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> - ! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box - ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_13]] : (!fir.ref>) -> !fir.ref - ! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAAssign(%[[VAL_15]], %[[VAL_16]], %[[VAL_17]], %[[VAL_14]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> none - ! CHECK: fir.result %[[VAL_10]] : !fir.heap>> - ! CHECK: } - ! CHECK: %[[VAL_19:.*]] = arith.constant 0 : index - ! CHECK: %[[VAL_20:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_19]] : (!fir.box>>, 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.ref> - ! CHECK: %[[VAL_25:.*]] = fir.emboxchar %[[VAL_23]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<1> - ! CHECK: fir.call @_QPbar_char(%[[VAL_25]]) fastmath : (!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.shape<1>) -> !fir.box>> - ! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref>>> - ! CHECK: %[[VAL_28:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref> - ! CHECK: %[[VAL_29:.*]] = arith.constant {{.*}} : i32 - ! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>>>) -> !fir.ref> - ! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_27]] : (!fir.box>>) -> !fir.box - ! CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_28]] : (!fir.ref>) -> !fir.ref - ! CHECK: %[[VAL_33:.*]] = fir.call @_FortranAAssign(%[[VAL_30]], %[[VAL_31]], %[[VAL_32]], %[[VAL_29]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> none - ! CHECK: fir.freemem %[[VAL_24]] : !fir.heap>> - ! CHECK: } +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.box>> +! CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box>> +! CHECK: %[[VAL_3:.*]] = arith.constant 10 : index +! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +! CHECK: %[[VAL_5:.*]] = fir.call @_FortranAIsContiguous(%[[VAL_4]]) fastmath : (!fir.box) -> i1 +! CHECK: %[[VAL_6:.*]] = fir.if %[[VAL_5]] -> (!fir.heap>>) { +! CHECK: %[[VAL_7:.*]] = fir.box_addr %[[VAL_0]] : (!fir.box>>) -> !fir.heap>> +! CHECK: fir.result %[[VAL_7]] : !fir.heap>> +! CHECK: } else { +! CHECK: %[[VAL_8:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_8]] : (!fir.box>>, index) -> (index, index, index) +! CHECK: %[[VAL_10:.*]] = fir.allocmem !fir.array>, %[[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.shape<1>) -> !fir.box>> +! CHECK: fir.store %[[VAL_12]] to %[[VAL_2]] : !fir.ref>>> +! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_0]] : (!fir.box>>) -> !fir.box +! CHECK: %[[VAL_18:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_15]], %[[VAL_16]], %{{.*}}, %{{.*}}) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +! CHECK: fir.result %[[VAL_10]] : !fir.heap>> +! CHECK: } +! CHECK: %[[VAL_19:.*]] = arith.constant 0 : index +! CHECK: %[[VAL_20:.*]]:3 = fir.box_dims %[[VAL_0]], %[[VAL_19]] : (!fir.box>>, 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.ref> +! CHECK: %[[VAL_25:.*]] = fir.emboxchar %[[VAL_23]], %[[VAL_3]] : (!fir.ref>, index) -> !fir.boxchar<1> +! CHECK: fir.call @_QPbar_char(%[[VAL_25]]) fastmath : (!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.shape<1>) -> !fir.box>> +! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref>>> +! CHECK: %[[VAL_30:.*]] = arith.constant true +! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>>>) -> !fir.ref> +! CHECK: %[[VAL_32:.*]] = fir.convert %[[VAL_27]] : (!fir.box>>) -> !fir.box +! CHECK: %[[VAL_34:.*]] = fir.call @_FortranACopyOutAssign(%[[VAL_31]], %[[VAL_32]], %[[VAL_30]], %{{.*}}, %{{.*}}) fastmath : (!fir.ref>, !fir.box, i1, !fir.ref, i32) -> none +! CHECK: fir.freemem %[[VAL_24]] : !fir.heap>> +! 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 --- a/flang/test/Lower/dummy-argument-assumed-shape-optional.f90 +++ b/flang/test/Lower/dummy-argument-assumed-shape-optional.f90 @@ -40,7 +40,7 @@ ! CHECK: %[[VAL_25:.*]] = fir.embox %[[VAL_3]](%[[VAL_24]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box> ! CHECK: fir.call @_QPtakes_contiguous(%[[VAL_25]]) {{.*}}: (!fir.box>) -> () ! CHECK: fir.if %[[VAL_23]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_3]] : !fir.heap> ! CHECK: } ! CHECK: return @@ -85,7 +85,7 @@ ! CHECK: %[[VAL_25:.*]] = fir.embox %[[VAL_3]](%[[VAL_24]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box> ! CHECK: fir.call @_QPtakes_contiguous(%[[VAL_25]]) {{.*}}: (!fir.box>) -> () ! CHECK: fir.if %[[VAL_23]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_3]] : !fir.heap> ! CHECK: } ! CHECK: return @@ -131,7 +131,7 @@ ! CHECK: %[[VAL_25:.*]] = fir.embox %[[VAL_3]](%[[VAL_24]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box> ! CHECK: fir.call @_QPtakes_contiguous_optional(%[[VAL_25]]) {{.*}}: (!fir.box>) -> () ! CHECK: fir.if %[[VAL_23]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_3]] : !fir.heap> ! CHECK: } ! CHECK: return @@ -191,7 +191,7 @@ ! CHECK: %[[VAL_38:.*]] = arith.select %[[VAL_1]], %[[VAL_35]], %[[VAL_37]] : !fir.box> ! CHECK: fir.call @_QPtakes_contiguous_optional(%[[VAL_38]]) {{.*}}: (!fir.box>) -> () ! CHECK: fir.if %[[VAL_33]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_9]] : !fir.heap> ! CHECK: } ! CHECK: return @@ -254,7 +254,7 @@ ! CHECK: %[[VAL_41:.*]] = arith.select %[[VAL_5]], %[[VAL_38]], %[[VAL_40]] : !fir.box> ! CHECK: fir.call @_QPtakes_contiguous_optional(%[[VAL_41]]) {{.*}}: (!fir.box>) -> () ! CHECK: fir.if %[[VAL_36]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_11]] : !fir.heap> ! CHECK: } ! CHECK: return @@ -323,7 +323,7 @@ ! CHECK: %[[VAL_41:.*]] = arith.select %[[VAL_5]], %[[VAL_38]], %[[VAL_40]] : !fir.box> ! CHECK: fir.call @_QPtakes_contiguous_optional(%[[VAL_41]]) {{.*}}: (!fir.box>) -> () ! CHECK: fir.if %[[VAL_36]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_11]] : !fir.heap> ! CHECK: } ! CHECK: return diff --git a/flang/test/Lower/dummy-argument-optional-2.f90 b/flang/test/Lower/dummy-argument-optional-2.f90 --- a/flang/test/Lower/dummy-argument-optional-2.f90 +++ b/flang/test/Lower/dummy-argument-optional-2.f90 @@ -111,7 +111,7 @@ ! CHECK: %[[VAL_10:.*]] = arith.constant 0 : index ! CHECK: %[[VAL_11:.*]]:3 = fir.box_dims %[[box]], %[[VAL_10]] : (!fir.box>>, index) -> (index, index, index) ! CHECK: %[[VAL_12:.*]] = fir.allocmem !fir.array, %[[VAL_11]]#1 {uniq_name = ".copyinout"} -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranAAssignTemporary ! CHECK: fir.result %[[VAL_12]] : !fir.heap> ! CHECK: } else { ! CHECK: %[[VAL_26:.*]] = fir.zero_bits !fir.heap> @@ -122,7 +122,7 @@ ! CHECK: %[[VAL_29:.*]] = fir.convert %[[VAL_9]] : (!fir.heap>) -> !fir.ref> ! CHECK: fir.call @_QPtakes_opt_explicit_shape(%[[VAL_29]]) {{.*}}: (!fir.ref>) -> () ! CHECK: fir.if %[[and]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_9]] : !fir.heap> ! CHECK: } end subroutine @@ -145,7 +145,7 @@ ! CHECK: %[[VAL_11:.*]]:3 = fir.box_dims %[[VAL_6]], %[[VAL_10]] : (!fir.box>>>, index) -> (index, index, index) ! CHECK: %[[VAL_12:.*]] = fir.box_elesize %[[VAL_6]] : (!fir.box>>>) -> index ! CHECK: %[[VAL_13:.*]] = fir.allocmem !fir.array>(%[[VAL_12]] : index), %[[VAL_11]]#1 {uniq_name = ".copyinout"} -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranAAssignTemporary ! CHECK: fir.result %[[VAL_13]] : !fir.heap>> ! CHECK: } else { ! CHECK: %[[VAL_46:.*]] = fir.zero_bits !fir.heap>> @@ -158,7 +158,7 @@ ! CHECK: %[[VAL_52:.*]] = fir.emboxchar %[[VAL_50]], %[[VAL_47]] : (!fir.ref>, 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>> ! CHECK: } ! CHECK: return @@ -182,7 +182,7 @@ ! CHECK: %[[is_contiguous:.*]] = fir.call @_FortranAIsContiguous(%{{.*}}) {{.*}}: (!fir.box) -> i1 ! CHECK: %[[VAL_7:.*]] = fir.if %[[VAL_6]] -> (!fir.heap>) { ! CHECK: %[[VAL_10:.*]] = fir.allocmem !fir.array -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranAAssignTemporary ! CHECK: fir.result %[[VAL_10]] : !fir.heap> ! CHECK: } else { ! CHECK: %[[VAL_11:.*]] = fir.zero_bits !fir.heap> @@ -193,7 +193,7 @@ ! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_7]] : (!fir.heap>) -> !fir.ref> ! CHECK: fir.call @_QPtakes_opt_explicit_shape(%[[VAL_14]]) {{.*}}: (!fir.ref>) -> () ! CHECK: fir.if %[[and]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_7]] : !fir.heap> ! CHECK: } end subroutine @@ -221,7 +221,7 @@ ! CHECK: %[[VAL_8:.*]] = arith.constant 0 : index ! CHECK: %[[VAL_9:.*]]:3 = fir.box_dims %[[VAL_6]], %[[VAL_8]] : (!fir.box>, index) -> (index, index, index) ! CHECK: %[[VAL_10:.*]] = fir.allocmem !fir.array, %[[VAL_9]]#1 {uniq_name = ".copyinout"} -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranAAssignTemporary ! CHECK: fir.result %[[VAL_10]] : !fir.heap> ! CHECK: } else { ! CHECK: %[[VAL_23:.*]] = fir.zero_bits !fir.heap> @@ -232,7 +232,7 @@ ! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_27:.*]] : (!fir.heap>) -> !fir.ref> ! CHECK: fir.call @_QPtakes_opt_explicit_shape(%[[VAL_26]]) {{.*}}: (!fir.ref>) -> () ! CHECK: fir.if %[[and]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_27]] : !fir.heap> ! CHECK: } end subroutine @@ -258,7 +258,7 @@ ! CHECK: } else { ! CHECK: %[[box_elesize:.*]] = fir.box_elesize %[[VAL_7]] : (!fir.box>>) -> index ! CHECK: %[[temp:.*]] = fir.allocmem !fir.array>(%[[box_elesize]] : index), %{{.*}}#1 {uniq_name = ".copyinout"} -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranAAssignTemporary ! CHECK: fir.result %[[VAL_12]] : !fir.heap>> ! CHECK: } else { ! CHECK: %[[VAL_44:.*]] = fir.zero_bits !fir.heap>> @@ -271,7 +271,7 @@ ! CHECK: %[[VAL_50:.*]] = fir.emboxchar %[[VAL_48]], %[[VAL_45]] : (!fir.ref>, 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>> ! CHECK: } end subroutine @@ -394,7 +394,7 @@ ! CHECK: %[[is_contiguous:.*]] = fir.call @_FortranAIsContiguous(%[[box_none]]) {{.*}}: (!fir.box) -> i1 ! CHECK: %[[VAL_7:.*]] = fir.if %[[VAL_1]] -> (!fir.heap>) { ! CHECK: %[[VAL_10:.*]] = fir.allocmem !fir.array -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranAAssignTemporary ! CHECK: fir.result %[[VAL_10]] : !fir.heap> ! CHECK: } else { ! CHECK: %[[VAL_23:.*]] = fir.zero_bits !fir.heap> @@ -405,7 +405,7 @@ ! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_7]] : (!fir.heap>) -> !fir.ref> ! CHECK: fir.call @_QPtakes_opt_explicit_shape_intentin(%[[VAL_24]]) {{.*}}: (!fir.ref>) -> () ! CHECK: fir.if %[[and]] { -! CHECK-NOT: fir.call @_FortranAAssign +! CHECK-NOT: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_7]] : !fir.heap> ! CHECK: } end subroutine @@ -425,7 +425,7 @@ ! CHECK: %[[is_contiguous:.*]] = fir.call @_FortranAIsContiguous(%[[box_none]]) {{.*}}: (!fir.box) -> i1 ! CHECK: %[[VAL_7:.*]] = fir.if %[[VAL_1]] -> (!fir.heap>) { ! CHECK: %[[VAL_10:.*]] = fir.allocmem !fir.array -! CHECK-NOT: fir.call @_FortranAAssign +! CHECK-NOT: fir.call @_FortranAAssignTemporary ! CHECK: fir.result %[[VAL_10]] : !fir.heap> ! CHECK: } else { ! CHECK: %[[VAL_11:.*]] = fir.zero_bits !fir.heap> @@ -436,7 +436,7 @@ ! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_7]] : (!fir.heap>) -> !fir.ref> ! CHECK: fir.call @_QPtakes_opt_explicit_shape_intentout(%[[VAL_14]]) {{.*}}: (!fir.ref>) -> () ! CHECK: fir.if %[[and]] { -! CHECK: fir.call @_FortranAAssign +! CHECK: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_7]] : !fir.heap> ! CHECK: } end subroutine diff --git a/flang/test/Lower/optional-value-caller.f90 b/flang/test/Lower/optional-value-caller.f90 --- a/flang/test/Lower/optional-value-caller.f90 +++ b/flang/test/Lower/optional-value-caller.f90 @@ -298,7 +298,7 @@ ! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_8]] : (!fir.heap>) -> !fir.ref> ! CHECK: fir.call @_QPdyn_array(%[[VAL_25]], %[[VAL_1]]) {{.*}}: (!fir.ref>, !fir.ref) -> () ! CHECK: fir.if %[[and]] { -! CHECK-NOT: fir.call @_FortranAAssign +! CHECK-NOT: fir.call @_FortranACopyOutAssign ! CHECK: fir.freemem %[[VAL_8]] : !fir.heap> ! CHECK: } end subroutine @@ -333,7 +333,7 @@ ! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>>) -> !fir.ref> ! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_7]] : (!fir.box>>) -> !fir.box ! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_18]] : (!fir.ref>) -> !fir.ref -! CHECK: %[[VAL_23:.*]] = fir.call @_FortranAAssign(%[[VAL_20]], %[[VAL_21]], %[[VAL_22]], %[[VAL_19]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +! CHECK: %[[VAL_23:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_20]], %[[VAL_21]], %[[VAL_22]], %[[VAL_19]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> none ! CHECK: fir.result %[[VAL_15]] : !fir.heap> ! CHECK: } ! CHECK: fir.result %[[VAL_24:.*]] : !fir.heap> @@ -439,7 +439,7 @@ ! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_1]] : (!fir.ref>>>) -> !fir.ref> ! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_9]] : (!fir.box>>) -> !fir.box ! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_21]] : (!fir.ref>) -> !fir.ref -! CHECK: %[[VAL_26:.*]] = fir.call @_FortranAAssign(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_22]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +! CHECK: %[[VAL_26:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_23]], %[[VAL_24]], %[[VAL_25]], %[[VAL_22]]) fastmath : (!fir.ref>, !fir.box, !fir.ref, i32) -> none ! CHECK: fir.result %[[VAL_18]] : !fir.heap>> ! CHECK: } ! CHECK: fir.result %[[VAL_27:.*]] : !fir.heap>>