[flang-commits] [flang] ebd0b8a - [flang][hlfir] Special handling for temporary LHS in AssignOp.
Slava Zakharin via flang-commits
flang-commits at lists.llvm.org
Mon Jun 26 18:28:16 PDT 2023
Author: Slava Zakharin
Date: 2023-06-26T18:28:10-07:00
New Revision: ebd0b8a0472b865b7eb6e1a32af97ae31d829033
URL: https://github.com/llvm/llvm-project/commit/ebd0b8a0472b865b7eb6e1a32af97ae31d829033
DIFF: https://github.com/llvm/llvm-project/commit/ebd0b8a0472b865b7eb6e1a32af97ae31d829033.diff
LOG: [flang][hlfir] Special handling for temporary LHS in AssignOp.
When `AssignOp` is used with LHS that is a compiler generated temporary
special care must be taken to initialize the temporary and avoid
finalizations of its components. This change-set adds optional
`temporary_lhs` attribute for `AssignOp` to convey this information
to HLFIR-to-FIR conversion pass. Currently, this results in
calling `AssignTemporary` runtime for doing the assignment.
Reviewed By: jeanPerier, tblah
Differential Revision: https://reviews.llvm.org/D152482
Added:
Modified:
flang/docs/HighLevelFIR.md
flang/include/flang/Optimizer/Builder/FIRBuilder.h
flang/include/flang/Optimizer/HLFIR/HLFIROps.td
flang/lib/Lower/ConvertExprToHLFIR.cpp
flang/lib/Optimizer/Builder/FIRBuilder.cpp
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
flang/test/HLFIR/as_expr-codegen.fir
flang/test/HLFIR/assign-codegen.fir
flang/test/HLFIR/bufferize01.fir
flang/test/HLFIR/elemental-codegen-nested.fir
flang/test/HLFIR/elemental-codegen.fir
flang/test/HLFIR/invalid.fir
flang/test/HLFIR/set_length-codegen.fir
flang/test/Lower/HLFIR/structure-constructor.f90
Removed:
################################################################################
diff --git a/flang/docs/HighLevelFIR.md b/flang/docs/HighLevelFIR.md
index 8c671ae216678..9b3f75671dfea 100644
--- a/flang/docs/HighLevelFIR.md
+++ b/flang/docs/HighLevelFIR.md
@@ -496,6 +496,8 @@ The attributes can be:
analysis pass).
- unordered : mark that an assignment can happen in any element order (not
true if there is an impure elemental function being called).
+- temporary_lhs: mark that the left hand side of the assignment is
+ a compiler generated temporary.
This will replace the current array_load/array_access/array_merge semantics.
Instead, a more generic alias analysis will be performed on the LHS and RHS to
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index fe34177ead13b..92e9d49045628 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -588,14 +588,16 @@ fir::ExtendedValue arraySectionElementToExtendedValue(
/// assignment follows Fortran intrinsic assignment semantic (10.2.1.3).
void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &lhs,
- const fir::ExtendedValue &rhs);
+ const fir::ExtendedValue &rhs,
+ bool isTemporaryLHS = false);
/// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived
/// types. The assignment follows Fortran intrinsic assignment semantic for
/// derived types (10.2.1.3 point 13).
void genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &lhs,
const fir::ExtendedValue &rhs,
- bool needFinalization = false);
+ bool needFinalization = false,
+ bool isTemporaryLHS = false);
/// Builds and returns the type of a ragged array header used to cache mask
/// evaluations. RaggedArrayHeader is defined in
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index cfc020e6b0d29..ee99cc77ef518 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -140,16 +140,25 @@ def fir_AssignOp : hlfir_Op<"assign", [MemoryEffects<[MemWrite]>]> {
Otherwise, the left hand side will be allocated or reallocated to match the
right hand side length if they
diff er. This covers the case of deferred
length character allocatables.
+ The optional "temporary_lhs" flag indicates that the LHS is a compiler
+ generated temporary. In this case the temporary is initialized if needed
+ (e.g. the LHS is of derived type with allocatable/pointer components),
+ and the assignment is done without LHS (or its subobjects) finalization
+ and with automatic allocation. Since LHS is uninitialized in this case,
+ "keep_lhs_length_if_realloc" attribute does not make sense. "realloc"
+ attribute is allowed with "temporary_lhs", though, it is implied.
}];
let arguments = (ins AnyFortranEntity:$rhs,
Arg<AnyFortranVariable, "", [MemWrite]>:$lhs,
UnitAttr:$realloc,
- UnitAttr:$keep_lhs_length_if_realloc);
+ UnitAttr:$keep_lhs_length_if_realloc,
+ UnitAttr:$temporary_lhs);
let assemblyFormat = [{
$rhs `to` $lhs (`realloc` $realloc^)?
(`keep_lhs_len` $keep_lhs_length_if_realloc^)?
+ (`temporary_lhs` $temporary_lhs^)?
attr-dict `:` type(operands)
}];
@@ -164,6 +173,10 @@ def fir_AssignOp : hlfir_Op<"assign", [MemoryEffects<[MemWrite]>]> {
bool mustKeepLhsLengthInAllocatableAssignment() {
return getKeepLhsLengthIfRealloc();
}
+ /// Is the assignment's left hand side a compiler generated temporary?
+ bool isTemporaryLHS() {
+ return getTemporaryLhs();
+ }
}];
let hasVerifier = 1;
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 33cc5b4a30e5c..a2774de95f870 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1686,7 +1686,9 @@ class HlfirBuilder {
loc, resultType, varOp, /*shape=*/nullptr,
/*typeparams=*/mlir::ValueRange{});
auto rhs = gen(expr);
- builder.create<hlfir::AssignOp>(loc, rhs, lhs);
+ builder.create<hlfir::AssignOp>(loc, rhs, lhs, /*realloc=*/false,
+ /*keep_lhs_length_if_realloc=*/false,
+ /*temporary_lhs=*/true);
continue;
}
@@ -1742,7 +1744,9 @@ class HlfirBuilder {
bitEnumContainsAny(attrs.getFlags(),
fir::FortranVariableFlagsEnum::allocatable);
auto rhs = gen(expr);
- builder.create<hlfir::AssignOp>(loc, rhs, lhs, allowRealloc);
+ builder.create<hlfir::AssignOp>(loc, rhs, lhs, allowRealloc,
+ /*keep_lhs_length_if_realloc=*/false,
+ /*temporary_lhs=*/true);
}
return varOp;
diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
index ae46287ea3c2c..5f98b105eb1f9 100644
--- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp
+++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
@@ -1138,7 +1138,8 @@ fir::ExtendedValue fir::factory::arraySectionElementToExtendedValue(
void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::ExtendedValue &lhs,
- const fir::ExtendedValue &rhs) {
+ const fir::ExtendedValue &rhs,
+ bool isTemporaryLHS) {
assert(lhs.rank() == 0 && rhs.rank() == 0 && "must be scalars");
auto type = fir::unwrapSequenceType(
fir::unwrapPassByRefType(fir::getBase(lhs).getType()));
@@ -1150,7 +1151,8 @@ void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder,
helper.createAssign(fir::ExtendedValue{*toChar},
fir::ExtendedValue{*fromChar});
} else if (type.isa<fir::RecordType>()) {
- fir::factory::genRecordAssignment(builder, loc, lhs, rhs);
+ fir::factory::genRecordAssignment(
+ builder, loc, lhs, rhs, /*needFinalization=*/false, isTemporaryLHS);
} else {
assert(!fir::hasDynamicSize(type));
auto rhsVal = fir::getBase(rhs);
@@ -1166,7 +1168,8 @@ void fir::factory::genScalarAssignment(fir::FirOpBuilder &builder,
static void genComponentByComponentAssignment(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::ExtendedValue &lhs,
- const fir::ExtendedValue &rhs) {
+ const fir::ExtendedValue &rhs,
+ bool isTemporaryLHS) {
auto lbaseType = fir::unwrapPassByRefType(fir::getBase(lhs).getType());
auto lhsType = lbaseType.dyn_cast<fir::RecordType>();
assert(lhsType && "lhs must be a scalar record type");
@@ -1229,7 +1232,7 @@ static void genComponentByComponentAssignment(fir::FirOpBuilder &builder,
auto from =
fir::factory::componentToExtendedValue(builder, loc, fromCoor);
auto to = fir::factory::componentToExtendedValue(builder, loc, toCoor);
- fir::factory::genScalarAssignment(builder, loc, to, from);
+ fir::factory::genScalarAssignment(builder, loc, to, from, isTemporaryLHS);
}
if (outerLoop)
builder.setInsertionPointAfter(*outerLoop);
@@ -1260,7 +1263,8 @@ void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::ExtendedValue &lhs,
const fir::ExtendedValue &rhs,
- bool needFinalization) {
+ bool needFinalization,
+ bool isTemporaryLHS) {
assert(lhs.rank() == 0 && rhs.rank() == 0 && "assume scalar assignment");
auto baseTy = fir::dyn_cast_ptrOrBoxEleTy(fir::getBase(lhs).getType());
assert(baseTy && "must be a memory type");
@@ -1281,7 +1285,10 @@ void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder,
// TODO: does this holds true with polymorphic entities ?
auto toMutableBox = builder.createTemporary(loc, to.getType());
builder.create<fir::StoreOp>(loc, to, toMutableBox);
- fir::runtime::genAssign(builder, loc, toMutableBox, from);
+ if (isTemporaryLHS)
+ fir::runtime::genAssignTemporary(builder, loc, toMutableBox, from);
+ else
+ fir::runtime::genAssign(builder, loc, toMutableBox, from);
return;
}
@@ -1299,7 +1306,7 @@ void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder,
// leads to issues in LLVM (long compile times, long IR files, and even
// asserts at some point). Since there is no good size boundary, just always
// use component by component assignment here.
- genComponentByComponentAssignment(builder, loc, lhs, rhs);
+ genComponentByComponentAssignment(builder, loc, lhs, rhs, isTemporaryLHS);
}
mlir::TupleType
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index a310b50c1c997..a0e06351ab81a 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -47,6 +47,9 @@ mlir::LogicalResult hlfir::AssignOp::verify() {
hlfir::getFortranElementType(lhsType).isa<fir::CharacterType>()))
return emitOpError("`realloc` must be set and lhs must be a character "
"allocatable when `keep_lhs_length_if_realloc` is set");
+ if (mustKeepLhsLengthInAllocatableAssignment() && isTemporaryLHS())
+ return emitOpError("`keep_lhs_length_if_realloc` does not make sense "
+ "for `temporary_lhs` assignments");
return mlir::success();
}
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
index db816d1a56904..4b16b224f6121 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
@@ -119,7 +119,7 @@ createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
isHeapAlloc = builder.createBool(loc, true);
} else {
alloc = builder.createTemporary(loc, mold.getFortranElementType(), tmpName,
- /*shape*/ std::nullopt, lenParams);
+ /*shape=*/std::nullopt, lenParams);
isHeapAlloc = builder.createBool(loc, false);
}
auto declareOp = builder.create<hlfir::DeclareOp>(
@@ -162,7 +162,9 @@ struct AsExprOpConversion : public mlir::OpConversionPattern<hlfir::AsExprOp> {
// Otherwise, create a copy in a new buffer.
hlfir::Entity source = hlfir::Entity{adaptor.getVar()};
auto [temp, cleanup] = createTempFromMold(loc, builder, source);
- builder.create<hlfir::AssignOp>(loc, source, temp);
+ builder.create<hlfir::AssignOp>(loc, source, temp, /*realloc=*/false,
+ /*keep_lhs_length_if_realloc=*/false,
+ /*temporary_lhs=*/true);
mlir::Value bufferizedExpr =
packageBufferizedExpr(loc, builder, temp, cleanup);
rewriter.replaceOp(asExpr, bufferizedExpr);
@@ -307,7 +309,10 @@ struct SetLengthOpConversion
fir::FortranVariableFlagsAttr{});
hlfir::Entity temp{declareOp.getBase()};
// Assign string value to the created temp.
- builder.create<hlfir::AssignOp>(loc, string, temp);
+ builder.create<hlfir::AssignOp>(loc, string, temp,
+ /*realloc=*/false,
+ /*keep_lhs_length_if_realloc=*/false,
+ /*temporary_lhs=*/true);
mlir::Value bufferizedExpr =
packageBufferizedExpr(loc, builder, temp, false);
rewriter.replaceOp(setLength, bufferizedExpr);
@@ -572,7 +577,10 @@ struct ElementalOpConversion
// Assign the element value to the temp element for this iteration.
auto tempElement =
hlfir::getElementAt(loc, builder, temp, loopNest.oneBasedIndices);
- builder.create<hlfir::AssignOp>(loc, elementValue, tempElement);
+ builder.create<hlfir::AssignOp>(loc, elementValue, tempElement,
+ /*realloc=*/false,
+ /*keep_lhs_length_if_realloc=*/false,
+ /*temporary_lhs=*/true);
// hlfir.yield_element implicitly marks the end-of-life its operand if
// it is an expression created in the hlfir.elemental (since it is its
// last use and an hlfir.destroy could not be created afterwards)
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
index 4cb5cd6fdbf4c..15e75c3857aa3 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp
@@ -121,6 +121,11 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
// mismatch, and that it should use the LHS explicit/assumed length if
// allocating/reallocation the LHS.
fir::runtime::genAssignExplicitLengthCharacter(builder, loc, to, from);
+ } else if (assignOp.isTemporaryLHS()) {
+ // Use AssignTemporary, when the LHS is a compiler generated temporary.
+ // Note that it also works properly for polymorphic LHS (i.e. the LHS
+ // will have the RHS dynamic type after the assignment).
+ fir::runtime::genAssignTemporary(builder, loc, to, from);
} else if (lhs.isPolymorphic()) {
// Indicate the runtime that the LHS must have the RHS dynamic type
// after the assignment.
@@ -138,13 +143,17 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> {
// reference.
auto toMutableBox = builder.createTemporary(loc, to.getType());
builder.create<fir::StoreOp>(loc, to, toMutableBox);
- fir::runtime::genAssign(builder, loc, toMutableBox, from);
+ if (assignOp.isTemporaryLHS())
+ fir::runtime::genAssignTemporary(builder, loc, toMutableBox, from);
+ else
+ fir::runtime::genAssign(builder, loc, toMutableBox, from);
} else {
// genScalarAssignment() must take care of potential overlap
// between LHS and RHS. Note that the overlap is possible
// also for components of LHS/RHS, and the Assign() runtime
// must take care of it.
- fir::factory::genScalarAssignment(builder, loc, lhsExv, rhsExv);
+ fir::factory::genScalarAssignment(builder, loc, lhsExv, rhsExv,
+ assignOp.isTemporaryLHS());
}
rewriter.eraseOp(assignOp);
return mlir::success();
diff --git a/flang/test/HLFIR/as_expr-codegen.fir b/flang/test/HLFIR/as_expr-codegen.fir
index 8c8d83b69426a..7123e499e9f73 100644
--- a/flang/test/HLFIR/as_expr-codegen.fir
+++ b/flang/test/HLFIR/as_expr-codegen.fir
@@ -14,7 +14,7 @@ func.func @char_expr(%addr: !fir.ref<!fir.char<1,?>>, %len: index) {
// CHECK: %[[VAL_3:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_1]] : index) {bindc_name = ".tmp"}
// CHECK: %[[VAL_5:.*]] = arith.constant false
// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
-// CHECK: hlfir.assign %[[VAL_2]]#0 to %[[VAL_4]]#0 : !fir.boxchar<1>, !fir.boxchar<1>
+// CHECK: hlfir.assign %[[VAL_2]]#0 to %[[VAL_4]]#0 temporary_lhs : !fir.boxchar<1>, !fir.boxchar<1>
// CHECK: %[[VAL_6:.*]] = fir.undefined tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_5]], [1 : index] : (tuple<!fir.boxchar<1>, i1>, i1) -> tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_4]]#0, [0 : index] : (tuple<!fir.boxchar<1>, i1>, !fir.boxchar<1>) -> tuple<!fir.boxchar<1>, i1>
@@ -31,7 +31,7 @@ func.func @char_expr_2(%addr: !fir.ref<!fir.char<1,10>>, %len: index) {
// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[VAL_1]] {uniq_name = "c"} : (!fir.ref<!fir.char<1,10>>, index) -> (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,10>>)
// CHECK: %[[VAL_5:.*]] = arith.constant false
// CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref<!fir.char<1,10>>, index) -> (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,10>>)
-// CHECK: hlfir.assign %[[VAL_3]]#0 to %[[VAL_4]]#0 : !fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,10>>
+// CHECK: hlfir.assign %[[VAL_3]]#0 to %[[VAL_4]]#0 temporary_lhs : !fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,10>>
// CHECK: %[[VAL_6:.*]] = fir.undefined tuple<!fir.ref<!fir.char<1,10>>, i1>
// CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_5]], [1 : index] : (tuple<!fir.ref<!fir.char<1,10>>, i1>, i1) -> tuple<!fir.ref<!fir.char<1,10>>, i1>
// CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_4]]#0, [0 : index] : (tuple<!fir.ref<!fir.char<1,10>>, i1>, !fir.ref<!fir.char<1,10>>) -> tuple<!fir.ref<!fir.char<1,10>>, i1>
@@ -48,7 +48,7 @@ func.func @shape_from_type(%arg0 : !fir.ref<!fir.array<10x20xi32>>) {
// CHECK: %[[VAL_4:.*]] = fir.allocmem !fir.array<10x20xi32> {bindc_name = ".tmp", uniq_name = ""}
// CHECK: %[[VAL_5:.*]] = arith.constant true
// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_3]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<10x20xi32>>, !fir.shape<2>) -> (!fir.heap<!fir.array<10x20xi32>>, !fir.heap<!fir.array<10x20xi32>>)
-// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 : !fir.ref<!fir.array<10x20xi32>>, !fir.heap<!fir.array<10x20xi32>>
+// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 temporary_lhs : !fir.ref<!fir.array<10x20xi32>>, !fir.heap<!fir.array<10x20xi32>>
// CHECK: %[[VAL_7:.*]] = fir.undefined tuple<!fir.heap<!fir.array<10x20xi32>>, i1>
// CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_5]], [1 : index] : (tuple<!fir.heap<!fir.array<10x20xi32>>, i1>, i1) -> tuple<!fir.heap<!fir.array<10x20xi32>>, i1>
// CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_8]], %[[VAL_6]]#0, [0 : index] : (tuple<!fir.heap<!fir.array<10x20xi32>>, i1>, !fir.heap<!fir.array<10x20xi32>>) -> tuple<!fir.heap<!fir.array<10x20xi32>>, i1>
@@ -67,7 +67,7 @@ func.func @shape_from_box(%arg0 : !fir.box<!fir.array<10x?xi32>>) {
// CHECK: %[[VAL_5:.*]] = fir.allocmem !fir.array<10x?xi32>, %[[VAL_3]]#1 {bindc_name = ".tmp", uniq_name = ""}
// CHECK: %[[VAL_6:.*]] = arith.constant true
// CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_5]](%[[VAL_4]]) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<10x?xi32>>, !fir.shape<2>) -> (!fir.box<!fir.array<10x?xi32>>, !fir.heap<!fir.array<10x?xi32>>)
-// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_7]]#0 : !fir.box<!fir.array<10x?xi32>>, !fir.box<!fir.array<10x?xi32>>
+// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_7]]#0 temporary_lhs : !fir.box<!fir.array<10x?xi32>>, !fir.box<!fir.array<10x?xi32>>
// CHECK: %[[VAL_8:.*]] = fir.undefined tuple<!fir.box<!fir.array<10x?xi32>>, i1>
// CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_8]], %[[VAL_6]], [1 : index] : (tuple<!fir.box<!fir.array<10x?xi32>>, i1>, i1) -> tuple<!fir.box<!fir.array<10x?xi32>>, i1>
// CHECK: %[[VAL_10:.*]] = fir.insert_value %[[VAL_9]], %[[VAL_7]]#0, [0 : index] : (tuple<!fir.box<!fir.array<10x?xi32>>, i1>, !fir.box<!fir.array<10x?xi32>>) -> tuple<!fir.box<!fir.array<10x?xi32>>, i1>
diff --git a/flang/test/HLFIR/assign-codegen.fir b/flang/test/HLFIR/assign-codegen.fir
index 7d3b4d54b04cf..c5473b0085217 100644
--- a/flang/test/HLFIR/assign-codegen.fir
+++ b/flang/test/HLFIR/assign-codegen.fir
@@ -145,6 +145,31 @@ func.func @array(%arg0: !fir.box<!fir.array<?xi32>>, %arg1: !fir.ref<!fir.array<
// CHECK: %[[VAL_29:.*]] = fir.call @_FortranAAssign(%[[VAL_26]], %[[VAL_27]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+func.func @array_temp(%arg0: !fir.box<!fir.array<?xi32>>, %arg1: !fir.ref<!fir.array<100xi32>>) {
+ %c100 = arith.constant 100 : index
+ %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+ %1 = fir.shape %c100 : (index) -> !fir.shape<1>
+ %2:2 = hlfir.declare %arg1(%1) {uniq_name = "y"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<100xi32>>, !fir.ref<!fir.array<100xi32>>)
+ hlfir.assign %2#0 to %0#0 temporary_lhs : !fir.ref<!fir.array<100xi32>>, !fir.box<!fir.array<?xi32>>
+ return
+}
+// CHECK-LABEL: func.func @array_temp(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>>,
+// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.array<100xi32>>) {
+// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.array<?xi32>>
+// CHECK: %[[VAL_4:.*]] = arith.constant 100 : index
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[VAL_6:.*]] = fir.rebox %[[VAL_5]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_1]](%[[VAL_7]]) {uniq_name = "y"} : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<100xi32>>
+// CHECK: %[[VAL_9:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
+// CHECK: %[[VAL_10:.*]] = fir.embox %[[VAL_8]](%[[VAL_9]]) : (!fir.ref<!fir.array<100xi32>>, !fir.shape<1>) -> !fir.box<!fir.array<100xi32>>
+// CHECK: fir.store %[[VAL_5]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
+// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_10]] : (!fir.box<!fir.array<100xi32>>) -> !fir.box<none>
+// CHECK: %[[VAL_29:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_26]], %[[VAL_27]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+
+
func.func @test_scalar_to_array(%lhs: !fir.box<!fir.array<?xi32>>, %rhs: i32) {
hlfir.assign %rhs to %lhs : i32, !fir.box<!fir.array<?xi32>>
return
@@ -184,6 +209,16 @@ func.func @alloc_assign(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
// CHECK: fir.call @_FortranAAssign(%[[VAL_2]], %[[VAL_3]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+func.func @alloc_assign_temp(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %arg1: !fir.box<!fir.array<?xi32>>) {
+ hlfir.assign %arg1 to %arg0 realloc temporary_lhs : !fir.box<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ return
+}
+// CHECK-LABEL: func.func @alloc_assign_temp(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
+// CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>>) {
+// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_1]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
+// CHECK: fir.call @_FortranAAssignTemporary(%[[VAL_2]], %[[VAL_3]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
func.func @test_alloc_assign_explicit_length_character(%lhs: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,10>>>>>, %rhs: !fir.box<!fir.array<?x!fir.char<1,?>>>) {
hlfir.assign %rhs to %lhs realloc keep_lhs_len : !fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,10>>>>>
@@ -246,6 +281,17 @@ func.func @assign_i1_to_polymorphic(%arg0: !fir.ref<!fir.class<!fir.heap<none>>>
// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_6]] : (!fir.box<!fir.logical<4>>) -> !fir.box<none>
// CHECK: %[[VAL_13:.*]] = fir.call @_FortranAAssignPolymorphic(%[[VAL_10]], %[[VAL_11]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+func.func @test_alloc_assign_polymorphic_temp(%lhs: !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t>>>>>, %rhs: !fir.class<!fir.array<?x!fir.type<t>>>) {
+ hlfir.assign %rhs to %lhs realloc temporary_lhs : !fir.class<!fir.array<?x!fir.type<t>>>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t>>>>>
+ return
+}
+// CHECK-LABEL: func.func @test_alloc_assign_polymorphic_temp(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t>>>>>,
+// CHECK-SAME: %[[VAL_1:.*]]: !fir.class<!fir.array<?x!fir.type<t>>>) {
+// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t>>>>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.class<!fir.array<?x!fir.type<t>>>) -> !fir.box<none>
+// CHECK: %[[VAL_10:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_7]], %[[VAL_8]], %{{.*}}, %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+
func.func @test_allocatable_component(%arg0: !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>> {fir.bindc_name = "x", fir.target}, %arg1: !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>> {fir.bindc_name = "y", fir.target}) {
%4:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEx"} : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
%5:2 = hlfir.declare %arg1 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEy"} : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
@@ -267,3 +313,25 @@ func.func @test_allocatable_component(%arg0: !fir.ref<!fir.type<_QFtestTt1{a:!fi
// CHECK: %[[VAL_13:.*]] = fir.call @_FortranAAssign(%[[VAL_10]], %[[VAL_11]], %[[VAL_12]], %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
// CHECK: return
// CHECK: }
+
+func.func @test_allocatable_component_temp(%arg0: !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>> {fir.bindc_name = "x", fir.target}, %arg1: !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>> {fir.bindc_name = "y", fir.target}) {
+ %4:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEx"} : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
+ %5:2 = hlfir.declare %arg1 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEy"} : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
+ hlfir.assign %5#0 to %4#0 temporary_lhs : !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+ return
+}
+// CHECK-LABEL: func.func @test_allocatable_component_temp(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>> {fir.bindc_name = "x", fir.target},
+// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>> {fir.bindc_name = "y", fir.target}) {
+// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEx"} : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEy"} : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+// CHECK: %[[VAL_5:.*]] = fir.embox %[[VAL_3]] : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.box<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+// CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_4]] : (!fir.ref<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.box<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+// CHECK: fir.store %[[VAL_5]] to %[[VAL_2]] : !fir.ref<!fir.box<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>
+// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.box<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>) -> !fir.ref<!fir.box<none>>
+// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_6]] : (!fir.box<!fir.type<_QFtestTt1{a:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> !fir.box<none>
+// CHECK: %[[VAL_12:.*]] = fir.convert %{{.*}} : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8>
+// CHECK: %[[VAL_13:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_10]], %[[VAL_11]], %[[VAL_12]], %{{.*}}) : (!fir.ref<!fir.box<none>>, !fir.box<none>, !fir.ref<i8>, i32) -> none
+// CHECK: return
+// CHECK: }
diff --git a/flang/test/HLFIR/bufferize01.fir b/flang/test/HLFIR/bufferize01.fir
index 81f8f2cd6a7e1..139eb900d0951 100644
--- a/flang/test/HLFIR/bufferize01.fir
+++ b/flang/test/HLFIR/bufferize01.fir
@@ -66,7 +66,7 @@
// CHECK: %[[VAL_54:.*]] = fir.insert_value %[[VAL_53]], %[[VAL_48]], [1 : index] : (tuple<!fir.boxchar<1>, i1>, i1) -> tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_55:.*]] = fir.insert_value %[[VAL_54]], %[[VAL_52]], [0 : index] : (tuple<!fir.boxchar<1>, i1>, !fir.boxchar<1>) -> tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_56:.*]] = hlfir.designate %[[VAL_42]]#0 (%[[VAL_45]]) typeparams %[[VAL_39]] : (!fir.box<!fir.array<1x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
-// CHECK: hlfir.assign %[[VAL_52]] to %[[VAL_56]] : !fir.boxchar<1>, !fir.boxchar<1>
+// CHECK: hlfir.assign %[[VAL_52]] to %[[VAL_56]] temporary_lhs : !fir.boxchar<1>, !fir.boxchar<1>
// CHECK: }
// CHECK: %[[VAL_57:.*]] = fir.undefined tuple<!fir.box<!fir.array<1x!fir.char<1,?>>>, i1>
// CHECK: %[[VAL_58:.*]] = fir.insert_value %[[VAL_57]], %[[VAL_43]], [1 : index] : (tuple<!fir.box<!fir.array<1x!fir.char<1,?>>>, i1>, i1) -> tuple<!fir.box<!fir.array<1x!fir.char<1,?>>>, i1>
diff --git a/flang/test/HLFIR/elemental-codegen-nested.fir b/flang/test/HLFIR/elemental-codegen-nested.fir
index b43286f51141c..1d9586204b6a2 100644
--- a/flang/test/HLFIR/elemental-codegen-nested.fir
+++ b/flang/test/HLFIR/elemental-codegen-nested.fir
@@ -28,7 +28,7 @@
// CHECK: fir.do_loop %[[VAL_23:.*]] = %[[VAL_22]] to %[[VAL_2]] step %[[VAL_22]] {
// CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref<f32>
// CHECK: %[[VAL_25:.*]] = hlfir.designate %[[VAL_20]]#0 (%[[VAL_23]]) : (!fir.heap<!fir.array<2xf32>>, index) -> !fir.ref<f32>
-// CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_25]] : f32, !fir.ref<f32>
+// CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_25]] temporary_lhs : f32, !fir.ref<f32>
// CHECK: }
// CHECK: %[[VAL_26:.*]] = fir.undefined tuple<!fir.heap<!fir.array<2xf32>>, i1>
// CHECK: %[[VAL_27:.*]] = fir.insert_value %[[VAL_26]], %[[VAL_21]], [1 : index] : (tuple<!fir.heap<!fir.array<2xf32>>, i1>, i1) -> tuple<!fir.heap<!fir.array<2xf32>>, i1>
@@ -41,7 +41,7 @@
// CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_30]] : (!fir.ref<!fir.array<2xf32>>) -> !fir.heap<!fir.array<2xf32>>
// CHECK: fir.freemem %[[VAL_34]] : !fir.heap<!fir.array<2xf32>>
// CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_14]]#0 (%[[VAL_17]]) : (!fir.heap<!fir.array<2xf32>>, index) -> !fir.ref<f32>
-// CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_35]] : f32, !fir.ref<f32>
+// CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_35]] temporary_lhs : f32, !fir.ref<f32>
// CHECK: }
// CHECK: %[[VAL_36:.*]] = fir.undefined tuple<!fir.heap<!fir.array<2xf32>>, i1>
// CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_36]], %[[VAL_15]], [1 : index] : (tuple<!fir.heap<!fir.array<2xf32>>, i1>, i1) -> tuple<!fir.heap<!fir.array<2xf32>>, i1>
diff --git a/flang/test/HLFIR/elemental-codegen.fir b/flang/test/HLFIR/elemental-codegen.fir
index ecdb3776f930d..aa10412b588bc 100644
--- a/flang/test/HLFIR/elemental-codegen.fir
+++ b/flang/test/HLFIR/elemental-codegen.fir
@@ -34,7 +34,7 @@ func.func @numeric_type(%arg0: !fir.ref<!fir.array<10x20xi32>>, %arg1: !fir.ref<
// CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_12]] : !fir.ref<i32>
// CHECK: %[[VAL_15:.*]] = arith.addi %[[VAL_13]], %[[VAL_14]] : i32
// CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_10]], %[[VAL_9]]) : (!fir.heap<!fir.array<10x20xi32>>, index, index) -> !fir.ref<i32>
-// CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_16]] : i32, !fir.ref<i32>
+// CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_16]] temporary_lhs : i32, !fir.ref<i32>
// CHECK: }
// CHECK: }
// CHECK: %[[VAL_17:.*]] = fir.undefined tuple<!fir.heap<!fir.array<10x20xi32>>, i1>
@@ -71,7 +71,7 @@ func.func @char_type(%arg0: !fir.box<!fir.array<?x!fir.char<1,?>>>, %arg1: index
// CHECK: %[[VAL_33:.*]] = fir.insert_value %[[VAL_32]], %[[VAL_31]], [1 : index] : (tuple<!fir.boxchar<1>, i1>, i1) -> tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_34:.*]] = fir.insert_value %[[VAL_33]], %[[VAL_30]]#0, [0 : index] : (tuple<!fir.boxchar<1>, i1>, !fir.boxchar<1>) -> tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_9]]) typeparams %[[VAL_2]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
-// CHECK: hlfir.assign %[[VAL_30]]#0 to %[[VAL_35]] : !fir.boxchar<1>, !fir.boxchar<1>
+// CHECK: hlfir.assign %[[VAL_30]]#0 to %[[VAL_35]] temporary_lhs : !fir.boxchar<1>, !fir.boxchar<1>
// CHECK: }
// CHECK: %[[VAL_36:.*]] = fir.undefined tuple<!fir.box<!fir.array<?x!fir.char<1,?>>>, i1>
// CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_36]], %[[VAL_7]], [1 : index] : (tuple<!fir.box<!fir.array<?x!fir.char<1,?>>>, i1>, i1) -> tuple<!fir.box<!fir.array<?x!fir.char<1,?>>>, i1>
@@ -101,7 +101,7 @@ func.func @derived_transpose(%arg0: !fir.box<!fir.array<?x?x!fir.type<t{field:f3
// CHECK: fir.do_loop %[[VAL_9:.*]] = %[[VAL_7]] to %[[VAL_2]] step %[[VAL_7]] {
// CHECK: %[[VAL_10:.*]] = hlfir.designate %[[VAL_0]] (%[[VAL_9]], %[[VAL_8]]) : (!fir.box<!fir.array<?x?x!fir.type<t{field:f32}>>>, index, index) -> !fir.box<!fir.type<t{field:f32}>>
// CHECK: %[[VAL_11:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_9]], %[[VAL_8]]) : (!fir.box<!fir.array<?x?x!fir.type<t{field:f32}>>>, index, index) -> !fir.ref<!fir.type<t{field:f32}>>
-// CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_11]] : !fir.box<!fir.type<t{field:f32}>>, !fir.ref<!fir.type<t{field:f32}>>
+// CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_11]] temporary_lhs : !fir.box<!fir.type<t{field:f32}>>, !fir.ref<!fir.type<t{field:f32}>>
// CHECK: }
// CHECK: }
// CHECK: %[[VAL_12:.*]] = fir.undefined tuple<!fir.box<!fir.array<?x?x!fir.type<t{field:f32}>>>, i1>
diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir
index 6db1b79e0818f..231dd013bbc4d 100644
--- a/flang/test/HLFIR/invalid.fir
+++ b/flang/test/HLFIR/invalid.fir
@@ -644,6 +644,13 @@ func.func @bad_assign_2(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>,
return
}
+// -----
+func.func @bad_assign_3(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>>, %arg1: !fir.box<!fir.array<?x!fir.char<1,?>>>) {
+ // expected-error at +1 {{'hlfir.assign' op `keep_lhs_length_if_realloc` does not make sense for `temporary_lhs` assignments}}
+ hlfir.assign %arg1 to %arg0 realloc keep_lhs_len temporary_lhs : !fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>>
+ return
+}
+
// -----
func.func @bad_parent_comp1(%arg0: !fir.box<!fir.array<10x!fir.type<t2{i:i32,j:i32}>>>) {
// expected-error at +1 {{'hlfir.parent_comp' op must be provided a shape if and only if the base is an array}}
diff --git a/flang/test/HLFIR/set_length-codegen.fir b/flang/test/HLFIR/set_length-codegen.fir
index 4e3c7f6136b48..571eb01a825ed 100644
--- a/flang/test/HLFIR/set_length-codegen.fir
+++ b/flang/test/HLFIR/set_length-codegen.fir
@@ -11,7 +11,7 @@ func.func @test_cst_len(%str : !fir.boxchar<1>) {
// CHECK: %[[VAL_1:.*]] = fir.alloca !fir.char<1,10> {bindc_name = ".tmp"}
// CHECK: %[[VAL_2:.*]] = arith.constant 10 : index
// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_1]] typeparams %[[VAL_2]] {uniq_name = ".tmp"} : (!fir.ref<!fir.char<1,10>>, index) -> (!fir.ref<!fir.char<1,10>>, !fir.ref<!fir.char<1,10>>)
-// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : !fir.boxchar<1>, !fir.ref<!fir.char<1,10>>
+// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 temporary_lhs : !fir.boxchar<1>, !fir.ref<!fir.char<1,10>>
// CHECK: %[[VAL_4:.*]] = arith.constant false
// CHECK: %[[VAL_5:.*]] = fir.undefined tuple<!fir.ref<!fir.char<1,10>>, i1>
// CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_4]], [1 : index] : (tuple<!fir.ref<!fir.char<1,10>>, i1>, i1) -> tuple<!fir.ref<!fir.char<1,10>>, i1>
@@ -26,7 +26,7 @@ func.func @test_dyn_len(%str : !fir.ref<!fir.char<1,10>>, %len : index) {
// CHECK-SAME: %[[VAL_1:.*]]: index) {
// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_1]] : index) {bindc_name = ".tmp"}
// CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
-// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : !fir.ref<!fir.char<1,10>>, !fir.boxchar<1>
+// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 temporary_lhs : !fir.ref<!fir.char<1,10>>, !fir.boxchar<1>
// CHECK: %[[VAL_4:.*]] = arith.constant false
// CHECK: %[[VAL_5:.*]] = fir.undefined tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_4]], [1 : index] : (tuple<!fir.boxchar<1>, i1>, i1) -> tuple<!fir.boxchar<1>, i1>
diff --git a/flang/test/Lower/HLFIR/structure-constructor.f90 b/flang/test/Lower/HLFIR/structure-constructor.f90
index 8cf10483ea82a..5eff0fcb400b2 100644
--- a/flang/test/Lower/HLFIR/structure-constructor.f90
+++ b/flang/test/Lower/HLFIR/structure-constructor.f90
@@ -48,7 +48,7 @@ end subroutine test1
! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_8]]#0{"c"} typeparams %[[VAL_15]] : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, index) -> !fir.ref<!fir.char<1,4>>
! CHECK: %[[VAL_17:.*]] = arith.constant 4 : i64
! CHECK: %[[VAL_18:.*]] = hlfir.set_length %[[VAL_7]]#0 len %[[VAL_17]] : (!fir.ref<!fir.char<1,4>>, i64) -> !hlfir.expr<!fir.char<1,4>>
-! CHECK: hlfir.assign %[[VAL_18]] to %[[VAL_16]] : !hlfir.expr<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>
+! CHECK: hlfir.assign %[[VAL_18]] to %[[VAL_16]] temporary_lhs : !hlfir.expr<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>
! CHECK: hlfir.assign %[[VAL_8]]#0 to %[[VAL_3]]#0 : !fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>
! CHECK: return
! CHECK: }
@@ -77,7 +77,7 @@ end subroutine test2
! CHECK: %[[VAL_14:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_15:.*]] = fir.shape %[[VAL_14]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_7]]#0{"i"} <%[[VAL_15]]> shape %[[VAL_15]] : (!fir.ref<!fir.type<_QMtypesTt2{i:!fir.array<10xi32>}>>, !fir.shape<1>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>>
-! CHECK: hlfir.assign %[[VAL_6]]#0 to %[[VAL_16]] : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
+! CHECK: hlfir.assign %[[VAL_6]]#0 to %[[VAL_16]] temporary_lhs : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! CHECK: hlfir.assign %[[VAL_7]]#0 to %[[VAL_3]]#0 : !fir.ref<!fir.type<_QMtypesTt2{i:!fir.array<10xi32>}>>, !fir.ref<!fir.type<_QMtypesTt2{i:!fir.array<10xi32>}>>
! CHECK: return
! CHECK: }
@@ -162,7 +162,7 @@ end subroutine test4
! CHECK: %[[VAL_34:.*]] = hlfir.set_length %[[VAL_33]] len %[[VAL_22]] : (!fir.ref<!fir.char<1,2>>, i64) -> !hlfir.expr<!fir.char<1,2>>
! CHECK: hlfir.yield_element %[[VAL_34]] : !hlfir.expr<!fir.char<1,2>>
! CHECK: }
-! CHECK: hlfir.assign %[[VAL_35:.*]] to %[[VAL_20]] realloc : !hlfir.expr<?x!fir.char<1,?>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>>
+! CHECK: hlfir.assign %[[VAL_35:.*]] to %[[VAL_20]] realloc temporary_lhs : !hlfir.expr<?x!fir.char<1,?>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>>
! CHECK: hlfir.assign %[[VAL_12]]#0 to %[[VAL_3]]#0 : !fir.ref<!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>, !fir.ref<!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>
! CHECK: hlfir.destroy %[[VAL_35]] : !hlfir.expr<?x!fir.char<1,?>>
! CHECK: return
@@ -194,7 +194,7 @@ end subroutine test5
! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<!fir.char<1,{{[0-9]*}}>>) -> !fir.ref<i8>
! CHECK: %[[VAL_17:.*]] = fir.call @_FortranAInitialize(%[[VAL_15]], %[[VAL_16]], %[[VAL_14]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_11]]#0{"t5m"} {fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>
-! CHECK: hlfir.assign %[[VAL_10]]#0 to %[[VAL_18]] realloc : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>
+! CHECK: hlfir.assign %[[VAL_10]]#0 to %[[VAL_18]] realloc temporary_lhs : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>
! CHECK: hlfir.assign %[[VAL_11]]#0 to %[[VAL_3]]#0 : !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>, !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>
! CHECK: return
! CHECK: }
@@ -243,8 +243,8 @@ end subroutine test6
! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_30]] : (!fir.ref<!fir.char<1,{{[0-9]*}}>>) -> !fir.ref<i8>
! CHECK: %[[VAL_34:.*]] = fir.call @_FortranAInitialize(%[[VAL_32]], %[[VAL_33]], %[[VAL_31]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32) -> none
! CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_28]]#0{"t5m"} {fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>
-! CHECK: hlfir.assign %[[VAL_19]]#0 to %[[VAL_35]] realloc : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>
-! CHECK: hlfir.assign %[[VAL_28]]#0 to %[[VAL_27]] : !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>, !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>
+! CHECK: hlfir.assign %[[VAL_19]]#0 to %[[VAL_35]] realloc temporary_lhs : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>>
+! CHECK: hlfir.assign %[[VAL_28]]#0 to %[[VAL_27]] temporary_lhs : !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>, !fir.ref<!fir.type<_QMtypesTt5{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>}>>
! CHECK: %[[VAL_36:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_37:.*]] = fir.shape %[[VAL_36]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_38:.*]] = hlfir.designate %[[VAL_20]]#0{"t6m"} <%[[VAL_37]]> shape %[[VAL_37]] : (!fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.shape<1>, !fir.shape<1>) -> !fir.ref<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>
@@ -273,12 +273,12 @@ end subroutine test6
! CHECK: %[[VAL_60:.*]] = hlfir.designate %[[VAL_52]]#0{"c"} typeparams %[[VAL_59]] : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, index) -> !fir.ref<!fir.char<1,4>>
! CHECK: %[[VAL_61:.*]] = arith.constant 4 : i64
! CHECK: %[[VAL_62:.*]] = hlfir.set_length %[[VAL_10]]#0 len %[[VAL_61]] : (!fir.ref<!fir.char<1,4>>, i64) -> !hlfir.expr<!fir.char<1,4>>
-! CHECK: hlfir.assign %[[VAL_62]] to %[[VAL_60]] : !hlfir.expr<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>
+! CHECK: hlfir.assign %[[VAL_62]] to %[[VAL_60]] temporary_lhs : !hlfir.expr<!fir.char<1,4>>, !fir.ref<!fir.char<1,4>>
! CHECK: %[[VAL_63:.*]] = fir.convert %[[VAL_52]]#1 : (!fir.ref<!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>) -> !fir.llvm_ptr<i8>
! CHECK: %[[VAL_64:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_45]], %[[VAL_63]]) fastmath<contract> : (!fir.llvm_ptr<i8>, !fir.llvm_ptr<i8>) -> none
! CHECK: %[[VAL_65:.*]] = arith.constant true
! CHECK: %[[VAL_66:.*]] = hlfir.as_expr %[[VAL_42]]#0 move %[[VAL_65]] : (!fir.heap<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>, i1) -> !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>
-! CHECK: hlfir.assign %[[VAL_66]] to %[[VAL_38]] : !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>
+! CHECK: hlfir.assign %[[VAL_66]] to %[[VAL_38]] temporary_lhs : !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref<!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>>
! CHECK: hlfir.assign %[[VAL_20]]#0 to %[[VAL_12]]#0 : !fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref<!fir.type<_QMtypesTt6{t5m:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMtypesTt4{c:!fir.box<!fir.heap<!fir.array<?x!fir.char<1,2>>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>
! CHECK: hlfir.destroy %[[VAL_66]] : !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>
! CHECK: return
More information about the flang-commits
mailing list