[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