diff --git a/flang/docs/HighLevelFIR.md b/flang/docs/HighLevelFIR.md --- a/flang/docs/HighLevelFIR.md +++ b/flang/docs/HighLevelFIR.md @@ -496,6 +496,8 @@ 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 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -588,14 +588,16 @@ /// 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 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -140,16 +140,25 @@ Otherwise, the left hand side will be allocated or reallocated to match the right hand side length if they differ. 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:$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 @@ 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 --- a/flang/lib/Lower/ConvertExprToHLFIR.cpp +++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp @@ -1686,7 +1686,9 @@ loc, resultType, varOp, /*shape=*/nullptr, /*typeparams=*/mlir::ValueRange{}); auto rhs = gen(expr); - builder.create(loc, rhs, lhs); + builder.create(loc, rhs, lhs, /*realloc=*/false, + /*keep_lhs_length_if_realloc=*/false, + /*temporary_lhs=*/true); continue; } @@ -1742,7 +1744,9 @@ bitEnumContainsAny(attrs.getFlags(), fir::FortranVariableFlagsEnum::allocatable); auto rhs = gen(expr); - builder.create(loc, rhs, lhs, allowRealloc); + builder.create(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 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -1138,7 +1138,8 @@ 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 @@ helper.createAssign(fir::ExtendedValue{*toChar}, fir::ExtendedValue{*fromChar}); } else if (type.isa()) { - 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 @@ 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(); assert(lhsType && "lhs must be a scalar record type"); @@ -1229,7 +1232,7 @@ 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 @@ 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 @@ // TODO: does this holds true with polymorphic entities ? auto toMutableBox = builder.createTemporary(loc, to.getType()); builder.create(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 @@ // 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 --- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp @@ -47,6 +47,9 @@ hlfir::getFortranElementType(lhsType).isa())) 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 --- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp @@ -119,7 +119,7 @@ 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( @@ -162,7 +162,9 @@ // Otherwise, create a copy in a new buffer. hlfir::Entity source = hlfir::Entity{adaptor.getVar()}; auto [temp, cleanup] = createTempFromMold(loc, builder, source); - builder.create(loc, source, temp); + builder.create(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 @@ fir::FortranVariableFlagsAttr{}); hlfir::Entity temp{declareOp.getBase()}; // Assign string value to the created temp. - builder.create(loc, string, temp); + builder.create(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 @@ // Assign the element value to the temp element for this iteration. auto tempElement = hlfir::getElementAt(loc, builder, temp, loopNest.oneBasedIndices); - builder.create(loc, elementValue, tempElement); + builder.create(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 --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -121,6 +121,11 @@ // 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 @@ // reference. auto toMutableBox = builder.createTemporary(loc, to.getType()); builder.create(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 --- a/flang/test/HLFIR/as_expr-codegen.fir +++ b/flang/test/HLFIR/as_expr-codegen.fir @@ -14,7 +14,7 @@ // 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>, index) -> (!fir.boxchar<1>, !fir.ref>) -// 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, i1> // CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_5]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> // CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_4]]#0, [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> @@ -31,7 +31,7 @@ // CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] typeparams %[[VAL_1]] {uniq_name = "c"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) // CHECK: %[[VAL_5:.*]] = arith.constant false // CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_1]] {uniq_name = ".tmp"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) -// CHECK: hlfir.assign %[[VAL_3]]#0 to %[[VAL_4]]#0 : !fir.ref>, !fir.ref> +// CHECK: hlfir.assign %[[VAL_3]]#0 to %[[VAL_4]]#0 temporary_lhs : !fir.ref>, !fir.ref> // CHECK: %[[VAL_6:.*]] = fir.undefined tuple>, i1> // CHECK: %[[VAL_7:.*]] = fir.insert_value %[[VAL_6]], %[[VAL_5]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> // CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_4]]#0, [0 : index] : (tuple>, i1>, !fir.ref>) -> tuple>, i1> @@ -48,7 +48,7 @@ // 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.shape<2>) -> (!fir.heap>, !fir.heap>) -// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 : !fir.ref>, !fir.heap> +// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_6]]#0 temporary_lhs : !fir.ref>, !fir.heap> // CHECK: %[[VAL_7:.*]] = fir.undefined tuple>, i1> // CHECK: %[[VAL_8:.*]] = fir.insert_value %[[VAL_7]], %[[VAL_5]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> // CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_8]], %[[VAL_6]]#0, [0 : index] : (tuple>, i1>, !fir.heap>) -> tuple>, i1> @@ -67,7 +67,7 @@ // 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.shape<2>) -> (!fir.box>, !fir.heap>) -// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_7]]#0 : !fir.box>, !fir.box> +// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_7]]#0 temporary_lhs : !fir.box>, !fir.box> // CHECK: %[[VAL_8:.*]] = fir.undefined tuple>, i1> // CHECK: %[[VAL_9:.*]] = fir.insert_value %[[VAL_8]], %[[VAL_6]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> // CHECK: %[[VAL_10:.*]] = fir.insert_value %[[VAL_9]], %[[VAL_7]]#0, [0 : index] : (tuple>, i1>, !fir.box>) -> tuple>, i1> diff --git a/flang/test/HLFIR/assign-codegen.fir b/flang/test/HLFIR/assign-codegen.fir --- a/flang/test/HLFIR/assign-codegen.fir +++ b/flang/test/HLFIR/assign-codegen.fir @@ -145,6 +145,31 @@ // CHECK: %[[VAL_29:.*]] = fir.call @_FortranAAssign(%[[VAL_26]], %[[VAL_27]], %{{.*}}, %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +func.func @array_temp(%arg0: !fir.box>, %arg1: !fir.ref>) { + %c100 = arith.constant 100 : index + %0:2 = hlfir.declare %arg0 {uniq_name = "x"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %1 = fir.shape %c100 : (index) -> !fir.shape<1> + %2:2 = hlfir.declare %arg1(%1) {uniq_name = "y"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + hlfir.assign %2#0 to %0#0 temporary_lhs : !fir.ref>, !fir.box> + return +} +// CHECK-LABEL: func.func @array_temp( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref>) { +// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box> +// CHECK: %[[VAL_4:.*]] = arith.constant 100 : index +// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.box>) -> !fir.box> +// CHECK: %[[VAL_6:.*]] = fir.rebox %[[VAL_5]] : (!fir.box>) -> !fir.box> +// 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.shape<1>) -> !fir.ref> +// CHECK: %[[VAL_9:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1> +// CHECK: %[[VAL_10:.*]] = fir.embox %[[VAL_8]](%[[VAL_9]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> +// CHECK: fir.store %[[VAL_5]] to %[[VAL_2]] : !fir.ref>> +// CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>) -> !fir.ref> +// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_10]] : (!fir.box>) -> !fir.box +// CHECK: %[[VAL_29:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_26]], %[[VAL_27]], %{{.*}}, %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none + + func.func @test_scalar_to_array(%lhs: !fir.box>, %rhs: i32) { hlfir.assign %rhs to %lhs : i32, !fir.box> return @@ -184,6 +209,16 @@ // CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_1]] : (!fir.box>) -> !fir.box // CHECK: fir.call @_FortranAAssign(%[[VAL_2]], %[[VAL_3]], %{{.*}}, %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +func.func @alloc_assign_temp(%arg0: !fir.ref>>>, %arg1: !fir.box>) { + hlfir.assign %arg1 to %arg0 realloc temporary_lhs : !fir.box>, !fir.ref>>> + return +} +// CHECK-LABEL: func.func @alloc_assign_temp( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.box>) { +// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.ref>>>) -> !fir.ref> +// CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_1]] : (!fir.box>) -> !fir.box +// CHECK: fir.call @_FortranAAssignTemporary(%[[VAL_2]], %[[VAL_3]], %{{.*}}, %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none func.func @test_alloc_assign_explicit_length_character(%lhs: !fir.ref>>>>, %rhs: !fir.box>>) { hlfir.assign %rhs to %lhs realloc keep_lhs_len : !fir.box>>, !fir.ref>>>> @@ -246,6 +281,17 @@ // CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_6]] : (!fir.box>) -> !fir.box // CHECK: %[[VAL_13:.*]] = fir.call @_FortranAAssignPolymorphic(%[[VAL_10]], %[[VAL_11]], %{{.*}}, %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +func.func @test_alloc_assign_polymorphic_temp(%lhs: !fir.ref>>>>, %rhs: !fir.class>>) { + hlfir.assign %rhs to %lhs realloc temporary_lhs : !fir.class>>, !fir.ref>>>> + return +} +// CHECK-LABEL: func.func @test_alloc_assign_polymorphic_temp( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>>>, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.class>>) { +// CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_0]] : (!fir.ref>>>>) -> !fir.ref> +// CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_1]] : (!fir.class>>) -> !fir.box +// CHECK: %[[VAL_10:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_7]], %[[VAL_8]], %{{.*}}, %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none + func.func @test_allocatable_component(%arg0: !fir.ref>>}>> {fir.bindc_name = "x", fir.target}, %arg1: !fir.ref>>}>> {fir.bindc_name = "y", fir.target}) { %4:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEx"} : (!fir.ref>>}>>) -> (!fir.ref>>}>>, !fir.ref>>}>>) %5:2 = hlfir.declare %arg1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEy"} : (!fir.ref>>}>>) -> (!fir.ref>>}>>, !fir.ref>>}>>) @@ -267,3 +313,25 @@ // CHECK: %[[VAL_13:.*]] = fir.call @_FortranAAssign(%[[VAL_10]], %[[VAL_11]], %[[VAL_12]], %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none // CHECK: return // CHECK: } + +func.func @test_allocatable_component_temp(%arg0: !fir.ref>>}>> {fir.bindc_name = "x", fir.target}, %arg1: !fir.ref>>}>> {fir.bindc_name = "y", fir.target}) { + %4:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEx"} : (!fir.ref>>}>>) -> (!fir.ref>>}>>, !fir.ref>>}>>) + %5:2 = hlfir.declare %arg1 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEy"} : (!fir.ref>>}>>) -> (!fir.ref>>}>>, !fir.ref>>}>>) + hlfir.assign %5#0 to %4#0 temporary_lhs : !fir.ref>>}>>, !fir.ref>>}>> + return +} +// CHECK-LABEL: func.func @test_allocatable_component_temp( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>}>> {fir.bindc_name = "x", fir.target}, +// CHECK-SAME: %[[VAL_1:.*]]: !fir.ref>>}>> {fir.bindc_name = "y", fir.target}) { +// CHECK: %[[VAL_2:.*]] = fir.alloca !fir.box>>}>> +// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEx"} : (!fir.ref>>}>>) -> !fir.ref>>}>> +// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEy"} : (!fir.ref>>}>>) -> !fir.ref>>}>> +// CHECK: %[[VAL_5:.*]] = fir.embox %[[VAL_3]] : (!fir.ref>>}>>) -> !fir.box>>}>> +// CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_4]] : (!fir.ref>>}>>) -> !fir.box>>}>> +// CHECK: fir.store %[[VAL_5]] to %[[VAL_2]] : !fir.ref>>}>>> +// CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_2]] : (!fir.ref>>}>>>) -> !fir.ref> +// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_6]] : (!fir.box>>}>>) -> !fir.box +// CHECK: %[[VAL_12:.*]] = fir.convert %{{.*}} : (!fir.ref>) -> !fir.ref +// CHECK: %[[VAL_13:.*]] = fir.call @_FortranAAssignTemporary(%[[VAL_10]], %[[VAL_11]], %[[VAL_12]], %{{.*}}) : (!fir.ref>, !fir.box, !fir.ref, i32) -> none +// CHECK: return +// CHECK: } diff --git a/flang/test/HLFIR/bufferize01.fir b/flang/test/HLFIR/bufferize01.fir --- 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, i1>, i1) -> tuple, i1> // CHECK: %[[VAL_55:.*]] = fir.insert_value %[[VAL_54]], %[[VAL_52]], [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> // CHECK: %[[VAL_56:.*]] = hlfir.designate %[[VAL_42]]#0 (%[[VAL_45]]) typeparams %[[VAL_39]] : (!fir.box>>, 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>>, i1> // CHECK: %[[VAL_58:.*]] = fir.insert_value %[[VAL_57]], %[[VAL_43]], [1 : index] : (tuple>>, i1>, i1) -> tuple>>, i1> diff --git a/flang/test/HLFIR/elemental-codegen-nested.fir b/flang/test/HLFIR/elemental-codegen-nested.fir --- 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 // CHECK: %[[VAL_25:.*]] = hlfir.designate %[[VAL_20]]#0 (%[[VAL_23]]) : (!fir.heap>, index) -> !fir.ref -// CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_25]] : f32, !fir.ref +// CHECK: hlfir.assign %[[VAL_24]] to %[[VAL_25]] temporary_lhs : f32, !fir.ref // CHECK: } // CHECK: %[[VAL_26:.*]] = fir.undefined tuple>, i1> // CHECK: %[[VAL_27:.*]] = fir.insert_value %[[VAL_26]], %[[VAL_21]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> @@ -41,7 +41,7 @@ // CHECK: %[[VAL_34:.*]] = fir.convert %[[VAL_30]] : (!fir.ref>) -> !fir.heap> // CHECK: fir.freemem %[[VAL_34]] : !fir.heap> // CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_14]]#0 (%[[VAL_17]]) : (!fir.heap>, index) -> !fir.ref -// CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_35]] : f32, !fir.ref +// CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_35]] temporary_lhs : f32, !fir.ref // CHECK: } // CHECK: %[[VAL_36:.*]] = fir.undefined tuple>, i1> // CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_36]], %[[VAL_15]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> diff --git a/flang/test/HLFIR/elemental-codegen.fir b/flang/test/HLFIR/elemental-codegen.fir --- a/flang/test/HLFIR/elemental-codegen.fir +++ b/flang/test/HLFIR/elemental-codegen.fir @@ -34,7 +34,7 @@ // CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_12]] : !fir.ref // CHECK: %[[VAL_15:.*]] = arith.addi %[[VAL_13]], %[[VAL_14]] : i32 // CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_10]], %[[VAL_9]]) : (!fir.heap>, index, index) -> !fir.ref -// CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_16]] : i32, !fir.ref +// CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_16]] temporary_lhs : i32, !fir.ref // CHECK: } // CHECK: } // CHECK: %[[VAL_17:.*]] = fir.undefined tuple>, i1> @@ -71,7 +71,7 @@ // CHECK: %[[VAL_33:.*]] = fir.insert_value %[[VAL_32]], %[[VAL_31]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> // CHECK: %[[VAL_34:.*]] = fir.insert_value %[[VAL_33]], %[[VAL_30]]#0, [0 : index] : (tuple, i1>, !fir.boxchar<1>) -> tuple, i1> // CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_9]]) typeparams %[[VAL_2]] : (!fir.box>>, 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>>, i1> // CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_36]], %[[VAL_7]], [1 : index] : (tuple>>, i1>, i1) -> tuple>>, i1> @@ -101,7 +101,7 @@ // 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>>, index, index) -> !fir.box> // CHECK: %[[VAL_11:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_9]], %[[VAL_8]]) : (!fir.box>>, index, index) -> !fir.ref> -// CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_11]] : !fir.box>, !fir.ref> +// CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_11]] temporary_lhs : !fir.box>, !fir.ref> // CHECK: } // CHECK: } // CHECK: %[[VAL_12:.*]] = fir.undefined tuple>>, i1> diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir --- a/flang/test/HLFIR/invalid.fir +++ b/flang/test/HLFIR/invalid.fir @@ -644,6 +644,13 @@ return } +// ----- +func.func @bad_assign_3(%arg0: !fir.ref>>>>, %arg1: !fir.box>>) { + // expected-error@+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.ref>>>> + return +} + // ----- func.func @bad_parent_comp1(%arg0: !fir.box>>) { // expected-error@+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 --- a/flang/test/HLFIR/set_length-codegen.fir +++ b/flang/test/HLFIR/set_length-codegen.fir @@ -11,7 +11,7 @@ // 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>, index) -> (!fir.ref>, !fir.ref>) -// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : !fir.boxchar<1>, !fir.ref> +// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 temporary_lhs : !fir.boxchar<1>, !fir.ref> // CHECK: %[[VAL_4:.*]] = arith.constant false // CHECK: %[[VAL_5:.*]] = fir.undefined tuple>, i1> // CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_4]], [1 : index] : (tuple>, i1>, i1) -> tuple>, i1> @@ -26,7 +26,7 @@ // 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>, index) -> (!fir.boxchar<1>, !fir.ref>) -// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 : !fir.ref>, !fir.boxchar<1> +// CHECK: hlfir.assign %[[VAL_0]] to %[[VAL_3]]#0 temporary_lhs : !fir.ref>, !fir.boxchar<1> // CHECK: %[[VAL_4:.*]] = arith.constant false // CHECK: %[[VAL_5:.*]] = fir.undefined tuple, i1> // CHECK: %[[VAL_6:.*]] = fir.insert_value %[[VAL_5]], %[[VAL_4]], [1 : index] : (tuple, i1>, i1) -> tuple, i1> diff --git a/flang/test/Lower/HLFIR/structure-constructor.f90 b/flang/test/Lower/HLFIR/structure-constructor.f90 --- a/flang/test/Lower/HLFIR/structure-constructor.f90 +++ b/flang/test/Lower/HLFIR/structure-constructor.f90 @@ -48,7 +48,7 @@ ! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_8]]#0{"c"} typeparams %[[VAL_15]] : (!fir.ref}>>, index) -> !fir.ref> ! CHECK: %[[VAL_17:.*]] = arith.constant 4 : i64 ! CHECK: %[[VAL_18:.*]] = hlfir.set_length %[[VAL_7]]#0 len %[[VAL_17]] : (!fir.ref>, i64) -> !hlfir.expr> -! CHECK: hlfir.assign %[[VAL_18]] to %[[VAL_16]] : !hlfir.expr>, !fir.ref> +! CHECK: hlfir.assign %[[VAL_18]] to %[[VAL_16]] temporary_lhs : !hlfir.expr>, !fir.ref> ! CHECK: hlfir.assign %[[VAL_8]]#0 to %[[VAL_3]]#0 : !fir.ref}>>, !fir.ref}>> ! CHECK: return ! CHECK: } @@ -77,7 +77,7 @@ ! 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.shape<1>, !fir.shape<1>) -> !fir.ref> -! CHECK: hlfir.assign %[[VAL_6]]#0 to %[[VAL_16]] : !fir.ref>, !fir.ref> +! CHECK: hlfir.assign %[[VAL_6]]#0 to %[[VAL_16]] temporary_lhs : !fir.ref>, !fir.ref> ! CHECK: hlfir.assign %[[VAL_7]]#0 to %[[VAL_3]]#0 : !fir.ref}>>, !fir.ref}>> ! CHECK: return ! CHECK: } @@ -162,7 +162,7 @@ ! CHECK: %[[VAL_34:.*]] = hlfir.set_length %[[VAL_33]] len %[[VAL_22]] : (!fir.ref>, i64) -> !hlfir.expr> ! CHECK: hlfir.yield_element %[[VAL_34]] : !hlfir.expr> ! CHECK: } -! CHECK: hlfir.assign %[[VAL_35:.*]] to %[[VAL_20]] realloc : !hlfir.expr>, !fir.ref>>>> +! CHECK: hlfir.assign %[[VAL_35:.*]] to %[[VAL_20]] realloc temporary_lhs : !hlfir.expr>, !fir.ref>>>> ! CHECK: hlfir.assign %[[VAL_12]]#0 to %[[VAL_3]]#0 : !fir.ref>>>}>>, !fir.ref>>>}>> ! CHECK: hlfir.destroy %[[VAL_35]] : !hlfir.expr> ! CHECK: return @@ -194,7 +194,7 @@ ! CHECK: %[[VAL_16:.*]] = fir.convert %[[VAL_13]] : (!fir.ref>) -> !fir.ref ! CHECK: %[[VAL_17:.*]] = fir.call @_FortranAInitialize(%[[VAL_15]], %[[VAL_16]], %[[VAL_14]]) fastmath : (!fir.box, !fir.ref, i32) -> none ! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_11]]#0{"t5m"} {fortran_attrs = #fir.var_attrs} : (!fir.ref>>>}>>>>}>>) -> !fir.ref>>>}>>>>> -! CHECK: hlfir.assign %[[VAL_10]]#0 to %[[VAL_18]] realloc : !fir.ref>>>}>>>>>, !fir.ref>>>}>>>>> +! CHECK: hlfir.assign %[[VAL_10]]#0 to %[[VAL_18]] realloc temporary_lhs : !fir.ref>>>}>>>>>, !fir.ref>>>}>>>>> ! CHECK: hlfir.assign %[[VAL_11]]#0 to %[[VAL_3]]#0 : !fir.ref>>>}>>>>}>>, !fir.ref>>>}>>>>}>> ! CHECK: return ! CHECK: } @@ -243,8 +243,8 @@ ! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_30]] : (!fir.ref>) -> !fir.ref ! CHECK: %[[VAL_34:.*]] = fir.call @_FortranAInitialize(%[[VAL_32]], %[[VAL_33]], %[[VAL_31]]) fastmath : (!fir.box, !fir.ref, i32) -> none ! CHECK: %[[VAL_35:.*]] = hlfir.designate %[[VAL_28]]#0{"t5m"} {fortran_attrs = #fir.var_attrs} : (!fir.ref>>>}>>>>}>>) -> !fir.ref>>>}>>>>> -! CHECK: hlfir.assign %[[VAL_19]]#0 to %[[VAL_35]] realloc : !fir.ref>>>}>>>>>, !fir.ref>>>}>>>>> -! CHECK: hlfir.assign %[[VAL_28]]#0 to %[[VAL_27]] : !fir.ref>>>}>>>>}>>, !fir.ref>>>}>>>>}>> +! CHECK: hlfir.assign %[[VAL_19]]#0 to %[[VAL_35]] realloc temporary_lhs : !fir.ref>>>}>>>>>, !fir.ref>>>}>>>>> +! CHECK: hlfir.assign %[[VAL_28]]#0 to %[[VAL_27]] temporary_lhs : !fir.ref>>>}>>>>}>>, !fir.ref>>>}>>>>}>> ! 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>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.shape<1>, !fir.shape<1>) -> !fir.ref}>>> @@ -273,12 +273,12 @@ ! CHECK: %[[VAL_60:.*]] = hlfir.designate %[[VAL_52]]#0{"c"} typeparams %[[VAL_59]] : (!fir.ref}>>, index) -> !fir.ref> ! CHECK: %[[VAL_61:.*]] = arith.constant 4 : i64 ! CHECK: %[[VAL_62:.*]] = hlfir.set_length %[[VAL_10]]#0 len %[[VAL_61]] : (!fir.ref>, i64) -> !hlfir.expr> -! CHECK: hlfir.assign %[[VAL_62]] to %[[VAL_60]] : !hlfir.expr>, !fir.ref> +! CHECK: hlfir.assign %[[VAL_62]] to %[[VAL_60]] temporary_lhs : !hlfir.expr>, !fir.ref> ! CHECK: %[[VAL_63:.*]] = fir.convert %[[VAL_52]]#1 : (!fir.ref}>>) -> !fir.llvm_ptr ! CHECK: %[[VAL_64:.*]] = fir.call @_FortranAPushArrayConstructorSimpleScalar(%[[VAL_45]], %[[VAL_63]]) fastmath : (!fir.llvm_ptr, !fir.llvm_ptr) -> none ! CHECK: %[[VAL_65:.*]] = arith.constant true ! CHECK: %[[VAL_66:.*]] = hlfir.as_expr %[[VAL_42]]#0 move %[[VAL_65]] : (!fir.heap}>>>, 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}>>> +! CHECK: hlfir.assign %[[VAL_66]] to %[[VAL_38]] temporary_lhs : !hlfir.expr<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>, !fir.ref}>>> ! CHECK: hlfir.assign %[[VAL_20]]#0 to %[[VAL_12]]#0 : !fir.ref>>>}>>>>,t6m:!fir.array<1x!fir.type<_QMtypesTt1{c:!fir.char<1,4>}>>}>>, !fir.ref>>>}>>>>,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