[flang-commits] [flang] [flang] Preserve the alignment attribute across stack/heap conversions (PR #234898)
via flang-commits
flang-commits at lists.llvm.org
Fri Oct 23 12:46:24 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Eugene Epshteyn (eugeneepshteyn)
<details>
<summary>Changes</summary>
Three places move an allocation between the stack and the heap and drop any `alignment` attribute on the way: `createAllocMemFromAlloca` in MemoryUtils, `insertAlloca` in StackArrays, and the stack-budget accounting in AllocationPlacement. This patch copies the attribute across in the first two and lets the third budget for the padding an over-aligned alloca may need.
Nothing user-visible depends on this today: the only producer of an aligned `fir.allocmem` is an ALLOCATE statement, which StackArrays excludes by design, and flang's own temporaries carry no alignment. It is groundwork for the alignment-directive series, where aligned locals and temporaries will flow through these passes.
Stacked on #<!-- -->234897.
Assisted-by: AI
---
Full diff: https://github.com/llvm/llvm-project/pull/234898.diff
6 Files Affected:
- (modified) flang/lib/Optimizer/Transforms/AllocationPlacement.cpp (+8-2)
- (modified) flang/lib/Optimizer/Transforms/MemoryUtils.cpp (+8-4)
- (modified) flang/lib/Optimizer/Transforms/StackArrays.cpp (+3)
- (modified) flang/test/Fir/memory-allocation-opt.fir (+14)
- (modified) flang/test/Transforms/allocation-placement.fir (+24)
- (modified) flang/test/Transforms/stack-arrays.fir (+15)
``````````diff
diff --git a/flang/lib/Optimizer/Transforms/AllocationPlacement.cpp b/flang/lib/Optimizer/Transforms/AllocationPlacement.cpp
index 89783d7814831..a59c7181a1fef 100644
--- a/flang/lib/Optimizer/Transforms/AllocationPlacement.cpp
+++ b/flang/lib/Optimizer/Transforms/AllocationPlacement.cpp
@@ -215,9 +215,15 @@ void AllocationPlacementPass::runOnOperation() {
? placementHook(info, basePolicy, stackBytesUsed)
: fir::decideAllocationPlacement(info, basePolicy, stackBytesUsed);
- // Account for the decision in the running stack budget.
- if (endsUpOnStack(placement, info.isCurrentlyOnStack) && info.byteSize)
+ // Account for the decision in the running stack budget, including the
+ // worst-case padding a requested alignment may need.
+ if (endsUpOnStack(placement, info.isCurrentlyOnStack) && info.byteSize) {
stackBytesUsed += static_cast<std::size_t>(*info.byteSize);
+ std::optional<std::int64_t> alignment =
+ alloca ? alloca.getAlignment() : allocmem.getAlignment();
+ if (alignment && *alignment > 1)
+ stackBytesUsed += static_cast<std::size_t>(*alignment - 1);
+ }
LLVM_DEBUG({
llvm::dbgs() << "allocation-placement: "
diff --git a/flang/lib/Optimizer/Transforms/MemoryUtils.cpp b/flang/lib/Optimizer/Transforms/MemoryUtils.cpp
index 00a25a7326f2d..6da0c3141b8c4 100644
--- a/flang/lib/Optimizer/Transforms/MemoryUtils.cpp
+++ b/flang/lib/Optimizer/Transforms/MemoryUtils.cpp
@@ -322,10 +322,14 @@ fir::AllocMemOp fir::createAllocMemFromAlloca(mlir::OpBuilder &builder,
return *opt;
return {};
};
- return fir::AllocMemOp::create(builder, alloca.getLoc(), alloca.getInType(),
- unpackName(alloca.getUniqName()),
- unpackName(alloca.getBindcName()),
- alloca.getTypeparams(), alloca.getShape());
+ auto heap = fir::AllocMemOp::create(
+ builder, alloca.getLoc(), alloca.getInType(),
+ unpackName(alloca.getUniqName()), unpackName(alloca.getBindcName()),
+ alloca.getTypeparams(), alloca.getShape());
+ // Keep a requested alignment across the stack-to-heap conversion.
+ if (std::optional<std::int64_t> alignment = alloca.getAlignment())
+ heap.setAlignment(*alignment);
+ return heap;
}
/// Device code keeps its stack allocations: the unified/managed entry points
diff --git a/flang/lib/Optimizer/Transforms/StackArrays.cpp b/flang/lib/Optimizer/Transforms/StackArrays.cpp
index 0674cc2431960..6b8edde0c2d92 100644
--- a/flang/lib/Optimizer/Transforms/StackArrays.cpp
+++ b/flang/lib/Optimizer/Transforms/StackArrays.cpp
@@ -711,6 +711,9 @@ fir::AllocMemConversion::insertAlloca(fir::AllocMemOp &oldAlloc,
auto alloca =
fir::AllocaOp::create(rewriter, loc, varTy, uniqName, bindcName,
oldAlloc.getTypeparams(), oldAlloc.getShape());
+ // Keep a requested alignment across the heap-to-stack conversion.
+ if (std::optional<std::int64_t> alignment = oldAlloc.getAlignment())
+ alloca.setAlignment(*alignment);
if (emitLifetimeMarkers)
insertLifetimeMarkers(oldAlloc, alloca, rewriter);
diff --git a/flang/test/Fir/memory-allocation-opt.fir b/flang/test/Fir/memory-allocation-opt.fir
index 610a3f0b3072a..9993ebc6b7e50 100644
--- a/flang/test/Fir/memory-allocation-opt.fir
+++ b/flang/test/Fir/memory-allocation-opt.fir
@@ -32,3 +32,17 @@ func.func @_QPs2(%arg0: !fir.ref<i32>) {
}
func.func private @_QPs3(!fir.ref<!fir.array<1000123xi32>>)
+// A requested alignment survives the move to the heap.
+
+// CHECK-LABEL: func @_QPs4(
+// CHECK: %[[mem:.*]] = fir.allocmem !fir.array<1000123xi32> <{alignment = 64 : i64, bindc_name = "array", uniq_name = "_QFs4Earray"}>
+// CHECK: fir.call @_QPs3(
+// CHECK: fir.freemem %[[mem]]
+// CHECK-NEXT: return
+
+func.func @_QPs4() {
+ %0 = fir.alloca !fir.array<1000123xi32> {alignment = 64 : i64, bindc_name = "array", uniq_name = "_QFs4Earray"}
+ fir.call @_QPs3(%0) : (!fir.ref<!fir.array<1000123xi32>>) -> ()
+ return
+}
+
diff --git a/flang/test/Transforms/allocation-placement.fir b/flang/test/Transforms/allocation-placement.fir
index aa09d830fd5a5..c9c8f6d65e637 100644
--- a/flang/test/Transforms/allocation-placement.fir
+++ b/flang/test/Transforms/allocation-placement.fir
@@ -63,6 +63,30 @@ func.func @big_temp_alloca() {
return
}
+// A requested alignment survives heap-to-stack ...
+// CHECK-LABEL: func.func @small_temp_aligned
+// CHECK: fir.alloca !fir.array<10xi32> <{alignment = 64 : i64}>
+// CHECK-NOT: fir.allocmem
+func.func @small_temp_aligned() {
+ %0 = fir.allocmem !fir.array<10xi32> {alignment = 64 : i64}
+ %c0 = arith.constant 0 : index
+ %v = arith.constant 0 : i32
+ %r = fir.convert %0 : (!fir.heap<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+ %e = fir.coordinate_of %r, %c0 : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+ fir.store %v to %e : !fir.ref<i32>
+ fir.freemem %0 : !fir.heap<!fir.array<10xi32>>
+ return
+}
+
+// ... and stack-to-heap.
+// CHECK-LABEL: func.func @big_temp_alloca_aligned
+// CHECK: fir.allocmem !fir.array<100xi32> <{alignment = 64 : i64
+// CHECK: fir.freemem
+func.func @big_temp_alloca_aligned() {
+ %0 = fir.alloca !fir.array<100xi32> {alignment = 64 : i64}
+ return
+}
+
// Runtime-sized user variable (automatic array) -> heap.
// CHECK-LABEL: func.func @dyn_user
// CHECK: fir.allocmem !fir.array<?xi32>
diff --git a/flang/test/Transforms/stack-arrays.fir b/flang/test/Transforms/stack-arrays.fir
index 5b149bfd8b621..08d893d5679ea 100644
--- a/flang/test/Transforms/stack-arrays.fir
+++ b/flang/test/Transforms/stack-arrays.fir
@@ -15,6 +15,21 @@ func.func @simple() {
// CHECK: fir.alloca !fir.array<42xi32>
// CHECK: return
+// A requested alignment survives the move to the stack
+func.func @aligned() {
+ %0 = fir.allocmem !fir.array<42xi32> {alignment = 64 : i64}
+ %c0_a = arith.constant 0 : index
+ %c0_i32_a = arith.constant 0 : i32
+ %ref_a = fir.convert %0 : (!fir.heap<!fir.array<42xi32>>) -> !fir.ref<!fir.array<42xi32>>
+ %elt_a = fir.coordinate_of %ref_a, %c0_a : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
+ fir.store %c0_i32_a to %elt_a : !fir.ref<i32>
+ fir.freemem %0 : !fir.heap<!fir.array<42xi32>>
+ return
+}
+// CHECK-LABEL: func.func @aligned()
+// CHECK: fir.alloca !fir.array<42xi32> <{alignment = 64 : i64}>
+// CHECK: return
+
// Check fir.must_be_heap allocations are not moved
func.func @must_be_heap() {
%0 = fir.allocmem !fir.array<42xi32> {fir.must_be_heap = true}
``````````
</details>
https://github.com/llvm/llvm-project/pull/234898
More information about the flang-commits
mailing list