[flang-commits] [flang] [flang] Fix DEALLOCATE of zero-sized pointer array section (PR #206691)
via flang-commits
flang-commits at lists.llvm.org
Tue Jun 30 02:42:13 PDT 2026
https://github.com/ejose02 created https://github.com/llvm/llvm-project/pull/206691
When reboxing a zero-sized array section, keep the original base address instead of applying slice offset adjustments. This matches CFI_section behavior and allows ValidatePointerPayload to succeed on DEALLOCATE.
Fixes #193418
>From 998cd925a068c77d4322419e01706e7df0014edf Mon Sep 17 00:00:00 2001
From: ejose02 <ejose at amd.com>
Date: Tue, 30 Jun 2026 15:04:46 +0530
Subject: [PATCH] [flang] Fix DEALLOCATE of zero-sized pointer array section
When reboxing a zero-sized array section, keep the original base address
instead of applying slice offset adjustments. This matches CFI_section
behavior and allows ValidatePointerPayload to succeed on DEALLOCATE. Fixes
#193418
---
flang/lib/Optimizer/CodeGen/CodeGen.cpp | 13 +++++++++++
flang/test/Fir/convert-to-llvm.fir | 10 +++++++--
flang/test/Fir/rebox.fir | 17 +++++++++-----
.../deallocate-zero-sized-section.f90 | 22 +++++++++++++++++++
4 files changed, 54 insertions(+), 8 deletions(-)
create mode 100644 flang/test/Integration/deallocate-zero-sized-section.f90
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 74ad23a050fae..235546b1e3d9a 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -2558,6 +2558,7 @@ struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
unsigned shiftOps = rebox.getShiftOperandIndex();
auto strideOps = inputStrides.begin();
const unsigned inputRank = inputStrides.size();
+ mlir::Value originalBase = base;
for (unsigned i = 0; i < inputRank;
++i, ++strideOps, ++shiftOps, sliceOps += 3) {
mlir::Value sliceLb =
@@ -2593,6 +2594,18 @@ struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
slicedStrides.emplace_back(stride);
}
}
+ if (!slicedExtents.empty()) {
+ mlir::Value isNonEmpty = mlir::LLVM::ConstantOp::create(
+ rewriter, loc, rewriter.getI1Type(), rewriter.getBoolAttr(true));
+ for (mlir::Value extent : slicedExtents) {
+ mlir::Value notZero = mlir::LLVM::ICmpOp::create(
+ rewriter, loc, mlir::LLVM::ICmpPredicate::ne, extent, zero);
+ isNonEmpty =
+ mlir::LLVM::AndOp::create(rewriter, loc, isNonEmpty, notZero);
+ }
+ base = mlir::LLVM::SelectOp::create(rewriter, loc, isNonEmpty, base,
+ originalBase);
+ }
return finalizeRebox(rebox, adaptor, destBoxTy, dest, base,
/*lbounds*/ {}, slicedExtents, slicedStrides,
rewriter);
diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir
index 5209cb26d782c..33684ad3e31b2 100644
--- a/flang/test/Fir/convert-to-llvm.fir
+++ b/flang/test/Fir/convert-to-llvm.fir
@@ -2497,13 +2497,16 @@ func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
//CHECK: %[[RESULT_PTR_DIM1:.*]] = llvm.getelementptr %[[SOURCE_ARRAY]][%[[DIM1_LB_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
//CHECK: %[[DIM2_LB_DIFF:.*]] = llvm.sub %[[SIX]], %[[FOUR]] : i64
//CHECK: %[[DIM2_LB_OFFSET:.*]] = llvm.mul %[[DIM2_LB_DIFF]], %[[DIM2_STRIDE]] : i64
-//CHECK: %[[RESULT_PTR:.*]] = llvm.getelementptr %[[RESULT_PTR_DIM1]][%[[DIM2_LB_OFFSET]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
+//CHECK: %[[SHIFTED_PTR:.*]] = llvm.getelementptr %[[RESULT_PTR_DIM1]][%{{.*}}] : (!llvm.ptr, i64) -> !llvm.ptr, i8
//CHECK: %[[RESULT_UB_LB_DIFF:.*]] = llvm.sub %[[EIGHTY]], %[[SIX]] : i64
//CHECK: %[[RESULT_UB_LB_DIFF_PLUS_STRIDE:.*]] = llvm.add %[[RESULT_UB_LB_DIFF]], %[[THREE]] : i64
//CHECK: %[[RESULT_NELEMS_TMP:.*]] = llvm.sdiv %[[RESULT_UB_LB_DIFF_PLUS_STRIDE]], %[[THREE]] : i64
//CHECK: %[[RESULT_IF_NON_ZERO:.*]] = llvm.icmp "sgt" %[[RESULT_NELEMS_TMP]], %[[ZERO_ELEMS]] : i64
//CHECK: %[[RESULT_NELEMS:.*]] = llvm.select %[[RESULT_IF_NON_ZERO]], %[[RESULT_NELEMS_TMP]], %[[ZERO_ELEMS]] : i1, i64
//CHECK: %[[RESULT_STRIDE:.*]] = llvm.mul %[[THREE]], %[[DIM2_STRIDE]] : i64
+//CHECK: %[[IS_NONEMPTY:.*]] = llvm.icmp "ne" %[[RESULT_NELEMS]], %[[ZERO_ELEMS]] : i64
+//CHECK: %[[ALL_NONEMPTY:.*]] = llvm.and %{{.*}}, %[[IS_NONEMPTY]] : i1
+//CHECK: %[[RESULT_PTR:.*]] = llvm.select %[[ALL_NONEMPTY]], %[[SHIFTED_PTR]], %[[SOURCE_ARRAY]] : i1, !llvm.ptr
//CHECK: %[[RESULT_LB:.*]] = llvm.mlir.constant(1 : i64) : i64
//CHECK: %[[RBOX_TMP7_1:.*]] = llvm.insertvalue %[[RESULT_LB]], %[[RBOX_TMP6]][7, 0, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
//CHECK: %[[RBOX_TMP7_2:.*]] = llvm.insertvalue %[[RESULT_NELEMS]], %[[RBOX_TMP7_1]][7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
@@ -2564,13 +2567,16 @@ func.func @foo(%arg0: !fir.box<!fir.array<?x!fir.type<t{i:i32,c:!fir.char<1,10>}
//CHECK: %[[SRC_LB:.*]] = llvm.mlir.constant(1 : i64) : i64
//CHECK: %[[RESULT_TMP0:.*]] = llvm.sub %[[RESULT_LB]], %[[SRC_LB]] : i64
//CHECK: %[[RESULT_OFFSET_START:.*]] = llvm.mul %[[RESULT_TMP0]], %[[SRC_STRIDE]] : i64
-//CHECK: %[[RESULT_PTR:.*]] = llvm.getelementptr %[[COMPONENT]][%[[RESULT_OFFSET_START]]] : (!llvm.ptr, i64) -> !llvm.ptr, i8
+//CHECK: %[[SHIFTED_PTR:.*]] = llvm.getelementptr %[[COMPONENT]][%{{.*}}] : (!llvm.ptr, i64) -> !llvm.ptr, i8
//CHECK: %[[RESULT_TMP1:.*]] = llvm.sub %[[RESULT_UB]], %[[RESULT_LB]] : i64
//CHECK: %[[RESULT_TMP2:.*]] = llvm.add %[[RESULT_TMP1]], %[[RESULT_STRIDE]] : i64
//CHECK: %[[RESULT_TMP3:.*]] = llvm.sdiv %[[RESULT_TMP2]], %[[RESULT_STRIDE]] : i64
//CHECK: %[[RESULT_TMP_PRED:.*]] = llvm.icmp "sgt" %[[RESULT_TMP3]], %[[ZERO_6]] : i64
//CHECK: %[[RESULT_NELEMS:.*]] = llvm.select %[[RESULT_TMP_PRED]], %[[RESULT_TMP3]], %[[ZERO_6]] : i1, i64
//CHECK: %[[RESULT_TOTAL_STRIDE:.*]] = llvm.mul %[[RESULT_STRIDE]], %[[SRC_STRIDE]] : i64
+//CHECK: %[[IS_NONEMPTY:.*]] = llvm.icmp "ne" %[[RESULT_NELEMS]], %[[ZERO_6]] : i64
+//CHECK: %[[ALL_NONEMPTY:.*]] = llvm.and %{{.*}}, %[[IS_NONEMPTY]] : i1
+//CHECK: %[[RESULT_PTR:.*]] = llvm.select %[[ALL_NONEMPTY]], %[[SHIFTED_PTR]], %[[COMPONENT]] : i1, !llvm.ptr
//CHECK: %[[RESULT_LB:.*]] = llvm.mlir.constant(1 : i64) : i64
//CHECK: %[[RBOX_TMP7_1:.*]] = llvm.insertvalue %[[RESULT_LB]], %[[RBOX_TMP6]][7, 0, 0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
//CHECK: %[[RBOX_TMP7_2:.*]] = llvm.insertvalue %[[RESULT_NELEMS]], %[[RBOX_TMP7_1]][7, 0, 1] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
diff --git a/flang/test/Fir/rebox.fir b/flang/test/Fir/rebox.fir
index 0c9f6d9bb94ad..8ede68e63d6cf 100644
--- a/flang/test/Fir/rebox.fir
+++ b/flang/test/Fir/rebox.fir
@@ -35,10 +35,11 @@ func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
// CHECK: %[[OFFSET_0:.*]] = mul i64 2, %[[INSTRIDE_0]]
// CHECK: %[[VOIDBASE0:.*]] = getelementptr i8, ptr %[[INBASE]], i64 %[[OFFSET_0]]
// CHECK: %[[OFFSET_1:.*]] = mul i64 2, %[[INSTRIDE_1]]
- // CHECK: %[[VOIDBASE1:.*]] = getelementptr i8, ptr %[[VOIDBASE0]], i64 %[[OFFSET_1]]
+ // CHECK: %[[VOIDBASE1:.*]] = getelementptr i8, ptr %[[VOIDBASE0]], i64 %{{.*}}
// CHECK: %[[OUTSTRIDE0:.*]] = mul i64 3, %[[INSTRIDE_1]]
+ // CHECK: %[[VOIDBASE2:.*]] = select i1 {{.*}}, ptr %[[VOIDBASE1]], ptr %[[INBASE]]
// CHECK: %[[OUTBOX1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %{{.*}}, i64 %[[OUTSTRIDE0]], 7, 0, 2
- // CHECK: %[[OUTBOX2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[OUTBOX1]], ptr %[[VOIDBASE1]], 0
+ // CHECK: %[[OUTBOX2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[OUTBOX1]], ptr %[[VOIDBASE2]], 0
// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[OUTBOX2]], ptr %[[OUTBOX_ALLOC]], align 8
%2 = fir.rebox %arg0(%1) [%0] : (!fir.box<!fir.array<?x?xf32>>, !fir.shift<2>, !fir.slice<2>) -> !fir.box<!fir.array<?xf32>>
// CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]])
@@ -161,16 +162,19 @@ func.func @test_cmplx_1(%arg0: !fir.box<!fir.array<?xcomplex<f32>>>) {
// CHECK: %[[FRONT_PTR:.*]] = load ptr, ptr %[[FRONT_GEP]]
// CHECK: %[[FIELD_OFFSET_GEP:.*]] = getelementptr { float, float }, ptr %[[FRONT_PTR]], i64 0, i32 0
// CHECK: %[[FRONT_OFFSET:.*]] = mul i64 0, %[[INSTRIDE_1]]
- // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %[[FRONT_OFFSET]]
+ // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %{{.*}}
// CHECK: %[[SUB_1:.*]] = sub i64 %[[INSTRIDE_0]], 1
// CHECK: %[[ADD_1:.*]] = add i64 %[[SUB_1]], 1
// CHECK: %[[DIV_1:.*]] = sdiv i64 %[[ADD_1]], 1
// CHECK: %[[CHECK_NONZERO:.*]] = icmp sgt i64 %[[DIV_1]], 0
// CHECK: %[[CHECKED_BOUND:.*]] = select i1 %[[CHECK_NONZERO]], i64 %[[DIV_1]], i64 0
// CHECK: %[[STRIDE:.*]] = mul i64 1, %[[INSTRIDE_1]]
+ // CHECK: %[[IS_NONEMPTY:.*]] = icmp ne i64 %[[CHECKED_BOUND]], 0
+ // CHECK: %[[ALL_NONEMPTY:.*]] = and i1 {{.*}}, %[[IS_NONEMPTY]]
+ // CHECK: %[[RESULT_BASE:.*]] = select i1 %[[ALL_NONEMPTY]], ptr %[[OFFSET_GEP]], ptr %[[FIELD_OFFSET_GEP]]
// CHECK: %[[VAL_BUILD_1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %{{.*}}, i64 %[[CHECKED_BOUND]], 7, 0, 1
// CHECK: %[[VAL_BUILD_2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_1]], i64 %[[STRIDE]], 7, 0, 2
- // CHECK: %[[VAL_BUILD_3:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_2]], ptr %[[OFFSET_GEP]], 0
+ // CHECK: %[[VAL_BUILD_3:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_2]], ptr %[[RESULT_BASE]], 0
// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_3]], ptr %[[OUTBOX_ALLOC]]
fir.call @bar1(%2) : (!fir.box<!fir.array<?xf32>>) -> ()
// CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]])
@@ -200,10 +204,11 @@ func.func @test_cmplx_2(%arg0: !fir.box<!fir.array<?xcomplex<f32>>>) {
// CHECK: %[[FRONT_PTR:.*]] = load ptr, ptr %[[FRONT_GEP]]
// CHECK: %[[FIELD_OFFSET_GEP:.*]] = getelementptr { float, float }, ptr %[[FRONT_PTR]], i64 0, i32 1
// CHECK: %[[FRONT_OFFSET:.*]] = mul i64 6, %[[INSTRIDE_0]]
- // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %[[FRONT_OFFSET]]
+ // CHECK: %[[OFFSET_GEP:.*]] = getelementptr i8, ptr %[[FIELD_OFFSET_GEP]], i64 %{{.*}}
// CHECK: %[[STRIDE:.*]] = mul i64 5, %[[INSTRIDE_0]]
+ // CHECK: %[[RESULT_BASE:.*]] = select i1 {{.*}}, ptr %[[OFFSET_GEP]], ptr %[[FIELD_OFFSET_GEP]]
// CHECK: %[[VAL_BUILD_1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %{{.*}}, i64 %[[STRIDE]], 7, 0, 2
- // CHECK: %[[VAL_BUILD_2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_1]], ptr %[[OFFSET_GEP]], 0
+ // CHECK: %[[VAL_BUILD_2:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_1]], ptr %[[RESULT_BASE]], 0
// CHECK: store { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } %[[VAL_BUILD_2]], ptr %[[OUTBOX_ALLOC]]
fir.call @bar1(%2) fastmath<contract> : (!fir.box<!fir.array<?xf32>>) -> ()
// CHECK: call void @bar1(ptr %[[OUTBOX_ALLOC]])
diff --git a/flang/test/Integration/deallocate-zero-sized-section.f90 b/flang/test/Integration/deallocate-zero-sized-section.f90
new file mode 100644
index 0000000000000..54a1394e717c2
--- /dev/null
+++ b/flang/test/Integration/deallocate-zero-sized-section.f90
@@ -0,0 +1,22 @@
+! RUN: %flang %s -o %t 2>&1 && %t 2>&1 | FileCheck %s
+
+! DEALLOCATE of a pointer to a zero-sized array section that covers the whole
+! allocated object must succeed
+
+program deallocate_section
+ implicit none
+ integer :: size = 0, lbnd = 0, ubnd = 100, stride = -1
+ integer, pointer :: a1(:), a2(:)
+ character(10) :: str = 'abcdeabcde'
+ allocate(a1(size))
+ a2 => a1(lbnd:ubnd:stride)
+ write(str, '(I0)') a2
+ deallocate(a2)
+ if (str /= '') then
+ print '(a)', str
+ stop 'FAIL'
+ end if
+ print '("ok")'
+end program deallocate_section
+
+! CHECK: ok
More information about the flang-commits
mailing list