[flang-commits] [flang] 2bbf94d - [flang][hlfir] Reset lower bounds to one when bufferizing hlfir.as_expr move (#202406)
via flang-commits
flang-commits at lists.llvm.org
Tue Jun 9 08:56:33 PDT 2026
Author: khaki3
Date: 2026-06-09T08:56:28-07:00
New Revision: 2bbf94d210f73d2e1fd52a4179cd89834198675d
URL: https://github.com/llvm/llvm-project/commit/2bbf94d210f73d2e1fd52a4179cd89834198675d
DIFF: https://github.com/llvm/llvm-project/commit/2bbf94d210f73d2e1fd52a4179cd89834198675d.diff
LOG: [flang][hlfir] Reset lower bounds to one when bufferizing hlfir.as_expr move (#202406)
Example:
```fortran
module m
type t
integer, allocatable :: a(:)
end type
contains
function pf()
integer, allocatable :: pf(:)
allocate(pf(-5:-3)); pf = [1,2,3]
end function
end module
program p
use m
type(t) :: z
z = t(pf())
print *, lbound(z%a,1) ! must be 1
end program
```
In this code, the allocatable function result `pf()` is used in the
structure constructor `t(...)`. As an expression its lower bound is 1,
but lowering wraps the result descriptor in `hlfir.as_expr ... move`,
and bufferization forwarded that descriptor as-is — so its lower bound
`-5` leaked into the reallocated component, printing `-5`.
Fix: when bufferizing `hlfir.as_expr` with `move`, rebox a descriptor
that may carry non-default lower bounds back to lower bound 1
(descriptor only, no data copy).
Added:
Modified:
flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
flang/test/HLFIR/assign-bufferize.fir
flang/test/HLFIR/associate-codegen.fir
flang/test/HLFIR/bufferize01.fir
flang/test/HLFIR/extents-of-shape-of.f90
flang/test/HLFIR/mul_transpose.f90
flang/test/HLFIR/shapeof-lowering.fir
Removed:
################################################################################
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
index 35cbdd59cf5d8..b4d4d42473511 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
@@ -156,8 +156,21 @@ struct AsExprOpConversion : public mlir::OpConversionPattern<hlfir::AsExprOp> {
fir::FirOpBuilder builder(rewriter, module);
if (asExpr.isMove()) {
// Move variable storage for the hlfir.expr buffer.
- mlir::Value bufferizedExpr = packageBufferizedExpr(
- loc, builder, hlfir::Entity{adaptor.getVar()}, adaptor.getMustFree());
+ hlfir::Entity storage{adaptor.getVar()};
+ // An hlfir.expr has lower bounds of one. When the moved storage is a
+ // descriptor that may carry non-default lower bounds (e.g. an allocatable
+ // or pointer function result used in a structure constructor), rebox it
+ // to lower bounds of one so they are not propagated to the users of the
+ // expression. This does not copy the data.
+ if (storage.isArray() && mlir::isa<fir::BaseBoxType>(storage.getType()) &&
+ storage.mayHaveNonDefaultLowerBounds()) {
+ // A rebox without a shape operand resets the lower bounds to one.
+ storage = hlfir::Entity{fir::ReboxOp::create(
+ builder, loc, storage.getType(), storage, /*shape=*/mlir::Value{},
+ /*slice=*/mlir::Value{})};
+ }
+ mlir::Value bufferizedExpr =
+ packageBufferizedExpr(loc, builder, storage, adaptor.getMustFree());
rewriter.replaceOp(asExpr, bufferizedExpr);
return mlir::success();
}
diff --git a/flang/test/HLFIR/assign-bufferize.fir b/flang/test/HLFIR/assign-bufferize.fir
index 7c3a6088347f1..23af63ffa987e 100644
--- a/flang/test/HLFIR/assign-bufferize.fir
+++ b/flang/test/HLFIR/assign-bufferize.fir
@@ -13,4 +13,5 @@ func.func @keep_attributes(%arg0: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.
// CHECK-LABEL: func.func @keep_attributes(
// CHECK-SAME: %[[X:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,8>>>>>,
// CHECK-SAME: %[[Y:.*]]: !fir.box<!fir.array<1x!fir.char<1,?>>>) {
-// CHECK: hlfir.assign %[[Y]] to %[[X]] realloc keep_lhs_len : !fir.box<!fir.array<1x!fir.char<1,?>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,8>>>>>
+// CHECK: %[[REBOX:.*]] = fir.rebox %[[Y]] :
+// CHECK: hlfir.assign %[[REBOX]] to %[[X]] realloc keep_lhs_len : !fir.box<!fir.array<1x!fir.char<1,?>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,8>>>>>
diff --git a/flang/test/HLFIR/associate-codegen.fir b/flang/test/HLFIR/associate-codegen.fir
index b5965431c6d4e..3fad946d4dd37 100644
--- a/flang/test/HLFIR/associate-codegen.fir
+++ b/flang/test/HLFIR/associate-codegen.fir
@@ -154,7 +154,8 @@ func.func @test_result_box_addr(%x : !fir.box<!fir.array<?xi32>>) {
}
// CHECK-LABEL: func.func @test_result_box_addr(
// CHECK-SAME: %[[X:.*]]: !fir.box<!fir.array<?xi32>>) {
-// CHECK: %[[ADDR:.*]] = fir.box_addr %[[X]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
+// CHECK: %[[REBOX:.*]] = fir.rebox %[[X]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[ADDR:.*]] = fir.box_addr %[[REBOX]] : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
// CHECK: fir.call @bar(%[[ADDR]]) : (!fir.ref<!fir.array<?xi32>>) -> ()
func.func private @bar2(!fir.ref<!fir.array<10xi32>>) -> ()
diff --git a/flang/test/HLFIR/bufferize01.fir b/flang/test/HLFIR/bufferize01.fir
index 40e2769e459c1..85d44a1345e3d 100644
--- a/flang/test/HLFIR/bufferize01.fir
+++ b/flang/test/HLFIR/bufferize01.fir
@@ -45,9 +45,10 @@
// CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (!fir.box<!fir.char<1,?>>) -> !fir.box<none>
// CHECK: fir.call @_FortranAPushArrayConstructorValue(%[[VAL_14]], %[[VAL_33]]) fastmath<contract> : (!fir.llvm_ptr<i8>, !fir.box<none>) -> ()
// CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_6]] : !fir.ref<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>>
+// CHECK: %[[REBOX:.*]] = fir.rebox %[[VAL_35]] : (!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>) -> !fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>
// CHECK: %[[VAL_36:.*]] = fir.undefined tuple<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, i1>
// CHECK: %[[VAL_37:.*]] = fir.insert_value %[[VAL_36]], %[[VAL_2]], [1 : index] : (tuple<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, i1>, i1) -> tuple<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, i1>
-// CHECK: %[[VAL_38:.*]] = fir.insert_value %[[VAL_37]], %[[VAL_35]], [0 : index] : (tuple<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, i1>, !fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>) -> tuple<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, i1>
+// CHECK: %[[VAL_38:.*]] = fir.insert_value %[[VAL_37]], %[[REBOX]], [0 : index] : (tuple<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, i1>, !fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>) -> tuple<!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, i1>
// CHECK: %[[VAL_39:.*]] = fir.box_elesize %[[VAL_35]] : (!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>) -> index
// CHECK: %[[VAL_40:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1>
// CHECK: %[[VAL_41:.*]] = fir.allocmem !fir.array<1x!fir.char<1,?>>(%[[VAL_39]] : index) {bindc_name = ".tmp.array", uniq_name = ""}
@@ -56,7 +57,7 @@
// CHECK: %[[VAL_44:.*]] = arith.constant 1 : index
// CHECK: fir.do_loop %[[VAL_45:.*]] = %[[VAL_44]] to %[[VAL_3]] step %[[VAL_44]] {
// CHECK: %[[VAL_46:.*]] = fir.box_elesize %[[VAL_35]] : (!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>) -> index
-// CHECK: %[[VAL_47:.*]] = hlfir.designate %[[VAL_35]] (%[[VAL_45]]) typeparams %[[VAL_46]] : (!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, index, index) -> !fir.boxchar<1>
+// CHECK: %[[VAL_47:.*]] = hlfir.designate %[[REBOX]] (%[[VAL_45]]) typeparams %[[VAL_46]] : (!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>, index, index) -> !fir.boxchar<1>
// CHECK: %[[VAL_48:.*]] = arith.constant false
// CHECK: %[[VAL_49:.*]] = fir.undefined tuple<!fir.boxchar<1>, i1>
// CHECK: %[[VAL_50:.*]] = fir.insert_value %[[VAL_49]], %[[VAL_48]], [1 : index] : (tuple<!fir.boxchar<1>, i1>, i1) -> tuple<!fir.boxchar<1>, i1>
@@ -76,7 +77,7 @@
// CHECK: %[[VAL_62:.*]]:2 = hlfir.declare %[[VAL_60]](%[[VAL_61]]) typeparams %[[VAL_39]] {uniq_name = "_QFtest1Ey"} : (!fir.ref<!fir.array<1x!fir.char<1,?>>>, !fir.shape<1>, index) -> (!fir.box<!fir.array<1x!fir.char<1,?>>>, !fir.ref<!fir.array<1x!fir.char<1,?>>>)
// CHECK: %[[VAL_63:.*]] = fir.convert %[[VAL_60]] : (!fir.ref<!fir.array<1x!fir.char<1,?>>>) -> !fir.heap<!fir.array<1x!fir.char<1,?>>>
// CHECK: fir.freemem %[[VAL_63]] : !fir.heap<!fir.array<1x!fir.char<1,?>>>
-// CHECK: %[[VAL_64:.*]] = fir.box_addr %[[VAL_35]] : (!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>) -> !fir.heap<!fir.array<1x!fir.char<1,?>>>
+// CHECK: %[[VAL_64:.*]] = fir.box_addr %[[REBOX]] : (!fir.box<!fir.heap<!fir.array<1x!fir.char<1,?>>>>) -> !fir.heap<!fir.array<1x!fir.char<1,?>>>
// CHECK: fir.freemem %[[VAL_64]] : !fir.heap<!fir.array<1x!fir.char<1,?>>>
// CHECK: return
// CHECK: }
diff --git a/flang/test/HLFIR/extents-of-shape-of.f90 b/flang/test/HLFIR/extents-of-shape-of.f90
index 1168004597d19..f39c0180cd14b 100644
--- a/flang/test/HLFIR/extents-of-shape-of.f90
+++ b/flang/test/HLFIR/extents-of-shape-of.f90
@@ -39,8 +39,11 @@ elemental subroutine elem_sub(x)
! CHECK-FIR-NEXT: %[[DIMS0:.*]]:3 = fir.box_dims %[[MUL]], %[[C0]]
! CHECK-FIR-NEXT: %[[DIMS1:.*]]:3 = fir.box_dims %[[MUL]], %[[C1]]
! ...
-! CHECK-FIR: %[[SHAPE:.*]] = fir.shape %[[DIMS0]]#1, %[[DIMS1]]#1
-! CHECK-FIR-NEXT: fir.do_loop %[[ARG2:.*]] = %[[C1]] to %[[DIMS1]]#1 step %[[C1]] unordered {
+! CHECK-FIR: %[[REBOX:.*]] = fir.rebox {{.*}} : (!fir.box<!fir.array<?x?xf32>>) -> !fir.box<!fir.array<?x?xf32>>
+! CHECK-FIR: %[[RDIMS0:.*]]:3 = fir.box_dims %[[REBOX]], %{{.*}}
+! CHECK-FIR: %[[RDIMS1:.*]]:3 = fir.box_dims %[[REBOX]], %{{.*}}
+! CHECK-FIR: %[[SHAPE:.*]] = fir.shape %[[RDIMS0]]#1, %[[RDIMS1]]#1
+! CHECK-FIR-NEXT: fir.do_loop %[[ARG2:.*]] = %[[C1]] to %[[RDIMS1]]#1 step %[[C1]] unordered {
! CHECK-FIR-NEXT: fir.do_loop %[[ARG3:.*]] = %[[C1]] to %[[C2]] step %[[C1]] unordered {
! ...
diff --git a/flang/test/HLFIR/mul_transpose.f90 b/flang/test/HLFIR/mul_transpose.f90
index 990b99e6ebb7a..a57815ee839c7 100644
--- a/flang/test/HLFIR/mul_transpose.f90
+++ b/flang/test/HLFIR/mul_transpose.f90
@@ -73,12 +73,13 @@ subroutine mul_transpose(a, b, res)
! CHECK-BUFFERING: %[[TRANSPOSE_RES_LD:.*]] = fir.load %[[TRANSPOSE_RES_BOX:.*]]
! CHECK-BUFFERING: %[[TRANSPOSE_RES_ADDR:.*]] = fir.box_addr %[[TRANSPOSE_RES_LD]]
! CHECK-BUFFERING: %[[TRANSPOSE_RES_VAR:.*]]:2 = hlfir.declare %[[TRANSPOSE_RES_ADDR]]({{.*}}) {uniq_name = ".tmp.intrinsic_result"}
+! CHECK-BUFFERING: %[[TRANSPOSE_REBOX:.*]] = fir.rebox %[[TRANSPOSE_RES_VAR]]#0 : (!fir.box<!fir.array<?x?xf32>>) -> !fir.box<!fir.array<?x?xf32>>
! CHECK-BUFFERING: %[[TUPLE0:.*]] = fir.undefined tuple<!fir.box<!fir.array<?x?xf32>>, i1>
! CHECK-BUFFERING: %[[TUPLE1:.*]] = fir.insert_value %[[TUPLE0]], {{.*}}, [1 : index]
-! CHECK-BUFFERING: %[[TUPLE2:.*]] = fir.insert_value %[[TUPLE1]], %[[TRANSPOSE_RES_VAR]]#0, [0 : index]
+! CHECK-BUFFERING: %[[TUPLE2:.*]] = fir.insert_value %[[TUPLE1]], %[[TRANSPOSE_REBOX]], [0 : index]
-! CHECK-BUFFERING: %[[TRANSPOSE_RES_REF:.*]] = fir.box_addr %[[TRANSPOSE_RES_VAR]]#0
-! CHECK-BUFFERING: %[[TRANSPOSE_RES_REF2:.*]] = fir.convert %[[TRANSPOSE_RES_VAR]]#1
+! CHECK-BUFFERING: %[[TRANSPOSE_RES_REF:.*]] = fir.box_addr %[[TRANSPOSE_REBOX]]
+! CHECK-BUFFERING: %[[TRANSPOSE_RES_REF2:.*]] = fir.box_addr %[[TRANSPOSE_REBOX]]
! CHECK-BUFFERING: %[[TRANSPOSE_RES_BOX:.*]] = fir.embox %[[TRANSPOSE_RES_REF]]({{.*}})
! CHECK-BUFFERING: %[[LHS_CONV:.*]] = fir.convert %[[TRANSPOSE_RES_BOX]] : (!fir.box<!fir.array<1x2xf32>>) -> !fir.box<none>
! [argument handling unchanged]
@@ -86,14 +87,15 @@ subroutine mul_transpose(a, b, res)
! CHECK-BUFFERING: %[[MUL_RES_LD:.*]] = fir.load %[[MUL_RES_BOX:.*]]
! CHECK-BUFFERING: %[[MUL_RES_ADDR:.*]] = fir.box_addr %[[MUL_RES_LD]]
! CHECK-BUFFERING: %[[MUL_RES_VAR:.*]]:2 = hlfir.declare %[[MUL_RES_ADDR]]({{.*}}) {uniq_name = ".tmp.intrinsic_result"}
+! CHECK-BUFFERING: %[[MUL_REBOX:.*]] = fir.rebox %[[MUL_RES_VAR]]#0 : (!fir.box<!fir.array<?x?xf32>>) -> !fir.box<!fir.array<?x?xf32>>
! CHECK-BUFFERING: %[[TUPLE3:.*]] = fir.undefined tuple<!fir.box<!fir.array<?x?xf32>>, i1>
! CHECK-BUFFERING: %[[TUPLE4:.*]] = fir.insert_value %[[TUPLE3]], {{.*}}, [1 : index]
-! CHECK-BUFFERING: %[[TUPLE5:.*]] = fir.insert_value %[[TUPLE4]], %[[MUL_RES_VAR]]#0, [0 : index]
+! CHECK-BUFFERING: %[[TUPLE5:.*]] = fir.insert_value %[[TUPLE4]], %[[MUL_REBOX]], [0 : index]
! CHECK-BUFFERING: %[[TRANSPOSE_RES_HEAP:.*]] = fir.convert %[[TRANSPOSE_RES_REF2]] : (!fir.ref<!fir.array<1x2xf32>>) -> !fir.heap<!fir.array<1x2xf32>>
! CHECK-BUFFERING-NEXT: fir.freemem %[[TRANSPOSE_RES_HEAP]]
-! CHECK-BUFFERING-NEXT: hlfir.assign %[[MUL_RES_VAR]]#0 to %[[RES_DECL]]#0 : !fir.box<!fir.array<?x?xf32>>, !fir.ref<!fir.array<1x2xf32>>
-! CHECK-BUFFERING-NEXT: %[[MUL_RES_HEAP:.*]] = fir.box_addr %[[MUL_RES_VAR]]#0 : (!fir.box<!fir.array<?x?xf32>>) -> !fir.heap<!fir.array<?x?xf32>>
+! CHECK-BUFFERING-NEXT: hlfir.assign %[[MUL_REBOX]] to %[[RES_DECL]]#0 : !fir.box<!fir.array<?x?xf32>>, !fir.ref<!fir.array<1x2xf32>>
+! CHECK-BUFFERING-NEXT: %[[MUL_RES_HEAP:.*]] = fir.box_addr %[[MUL_REBOX]] : (!fir.box<!fir.array<?x?xf32>>) -> !fir.heap<!fir.array<?x?xf32>>
! CHECK-BUFFERING-NEXT: fir.freemem %[[MUL_RES_HEAP]]
! CHECK-ALL-NEXT: return
diff --git a/flang/test/HLFIR/shapeof-lowering.fir b/flang/test/HLFIR/shapeof-lowering.fir
index 73e2270a0cd4a..7ea13d04cfaeb 100644
--- a/flang/test/HLFIR/shapeof-lowering.fir
+++ b/flang/test/HLFIR/shapeof-lowering.fir
@@ -20,10 +20,13 @@ func.func @shapeof_asexpr(%arg0: !fir.box<!fir.heap<!fir.array<?xf32>>>) -> !fir
// CHECK-NEXT: %[[SHPE_SHFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1
// CHECK-NEXT: %[[VAR:.*]]:2 = hlfir.declare %[[BOX_ADDR]](%[[SHPE_SHFT]])
// CHECK-NEXT: %[[TRUE:.*]] = arith.constant true
+// CHECK-NEXT: %[[REBOX:.*]] = fir.rebox %[[VAR]]#0 :
// CHECK-NEXT: %[[TUPLE0:.*]] = fir.undefined tuple
// CHECK-NEXT: %[[TUPLE1:.*]] = fir.insert_value %[[TUPLE0]], %[[TRUE]]
-// CHECK-NEXT: %[[TUPLE2:.*]] = fir.insert_value %[[TUPLE1]], %[[VAR]]#0
-// CHECK-NEXT: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS]]#1
+// CHECK-NEXT: %[[TUPLE2:.*]] = fir.insert_value %[[TUPLE1]], %[[REBOX]]
+// CHECK-NEXT: %[[C0_2:.*]] = arith.constant 0 : index
+// CHECK-NEXT: %[[BOX_DIMS2:.*]]:3 = fir.box_dims %[[REBOX]], %[[C0_2]]
+// CHECK-NEXT: %[[SHAPE:.*]] = fir.shape %[[BOX_DIMS2]]#1
// CHECK-NEXT: return %[[SHAPE]]
func.func @shapeof_elemental() -> !fir.shape<1> {
More information about the flang-commits
mailing list