[llvm] [GlobalOpt] Fix alignments of globals introduced for allocations (PR #216480)

Ömer Sinan Ağacan via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 17 01:37:21 PDT 2026


https://github.com/osa1 updated https://github.com/llvm/llvm-project/pull/216480

>From f1c120229948132ab13c621d0b4ce53b276ae65f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Sat, 15 Aug 2026 11:24:49 +0100
Subject: [PATCH 1/3] Add tests

---
 .../Transforms/GlobalOpt/global-align-1.ll    | 44 ++++++++++
 .../Transforms/GlobalOpt/global-align-2.ll    | 47 +++++++++++
 .../Transforms/GlobalOpt/global-align-3.ll    | 48 +++++++++++
 .../Transforms/GlobalOpt/global-align-4.ll    | 48 +++++++++++
 .../GlobalOpt/global-align-dynamic.ll         | 49 +++++++++++
 .../GlobalOpt/global-align-implicit.ll        | 48 +++++++++++
 .../GlobalOpt/global-align-memset.ll          | 82 +++++++++++++++++++
 7 files changed, 366 insertions(+)
 create mode 100644 llvm/test/Transforms/GlobalOpt/global-align-1.ll
 create mode 100644 llvm/test/Transforms/GlobalOpt/global-align-2.ll
 create mode 100644 llvm/test/Transforms/GlobalOpt/global-align-3.ll
 create mode 100644 llvm/test/Transforms/GlobalOpt/global-align-4.ll
 create mode 100644 llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll
 create mode 100644 llvm/test/Transforms/GlobalOpt/global-align-implicit.ll
 create mode 100644 llvm/test/Transforms/GlobalOpt/global-align-memset.ll

diff --git a/llvm/test/Transforms/GlobalOpt/global-align-1.ll b/llvm/test/Transforms/GlobalOpt/global-align-1.ll
new file mode 100644
index 0000000000000..0e4eaa4b54f0b
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/global-align-1.ll
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+; Test from issue #215533.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g10 = internal global ptr null, align 8
+ at g26 = dso_local global <4 x i32> zeroinitializer, align 16
+ at g5 = dso_local global i8 0, align 1
+
+;.
+; CHECK: @g26 = dso_local local_unnamed_addr global <4 x i32> zeroinitializer, align 16
+; CHECK: @g5 = dso_local local_unnamed_addr global i8 0, align 1
+; CHECK: @g10.body = internal unnamed_addr global [16 x i8] undef{{$}}
+;.
+define dso_local i32 @main() {
+; CHECK-LABEL: define dso_local i32 @main() local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, ptr @g26, align 16
+; CHECK-NEXT:    store <4 x i32> [[TMP0]], ptr @g10.body, align 16
+; CHECK-NEXT:    [[BB3_0_COPYLOAD:%.*]] = load i32, ptr @g10.body, align 1
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[BB3_0_COPYLOAD]], 0
+; CHECK-NEXT:    [[STOREDV:%.*]] = zext i1 [[TOBOOL]] to i8
+; CHECK-NEXT:    store i8 [[STOREDV]], ptr @g5, align 1
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %call = call noalias align 16 ptr @aligned_alloc(i64 noundef 16, i64 noundef 16)
+  store ptr %call, ptr @g10, align 8
+  %0 = load <4 x i32>, ptr @g26, align 16
+  store <4 x i32> %0, ptr %call, align 16
+  %1 = load ptr, ptr @g10, align 8
+  %bb3.0.copyload = load i32, ptr %1, align 1
+  %tobool = icmp ne i32 %bb3.0.copyload, 0
+  %storedv = zext i1 %tobool to i8
+  store i8 %storedv, ptr @g5, align 1
+  ret i32 0
+}
+
+declare noalias noundef ptr @aligned_alloc(i64 allocalign noundef, i64 noundef) #0
+
+attributes #0 = { allockind("alloc,uninitialized,aligned") allocsize(1) }
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-2.ll b/llvm/test/Transforms/GlobalOpt/global-align-2.ll
new file mode 100644
index 0000000000000..afc26fca6cb4e
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/global-align-2.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+; Test non-power-of-two aligned global allocations.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = internal global ptr null
+
+;.
+; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef{{$}}
+;.
+define void @init() {
+; CHECK-LABEL: define void @init() local_unnamed_addr {
+; CHECK-NEXT:    ret void
+;
+  %m = call noalias align 64 ptr @aligned_alloc(i64 100, i64 64)
+  store ptr %m, ptr @g, align 8
+  ret void
+}
+
+define void @store(<4 x float> %v, i8 %c) {
+; CHECK-LABEL: define void @store(
+; CHECK-SAME: <4 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store <4 x float> [[V]], ptr @g.body, align 16
+; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
+; CHECK-NEXT:    ret void
+;
+  %p = load ptr, ptr @g, align 8
+  store <4 x float> %v, ptr %p, align 16
+  %q = getelementptr i8, ptr %p, i64 3
+  store i8 %c, ptr %q, align 1
+  ret void
+}
+
+define <4 x float> @load() {
+; CHECK-LABEL: define <4 x float> @load() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load <4 x float>, ptr @g.body, align 16
+; CHECK-NEXT:    ret <4 x float> [[V]]
+;
+  %p = load ptr, ptr @g, align 8
+  %v = load <4 x float>, ptr %p, align 16
+  ret <4 x float> %v
+}
+
+declare noalias ptr @aligned_alloc(i64 allocalign, i64) allockind("alloc,uninitialized,aligned") allocsize(1)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-3.ll b/llvm/test/Transforms/GlobalOpt/global-align-3.ll
new file mode 100644
index 0000000000000..a899ab5761583
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/global-align-3.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+; Check the the alignment is not specified when it's smaller than the preferred
+; alignment of the type.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = internal global ptr null
+
+;.
+; CHECK: @g.body = internal unnamed_addr global [32 x i8] undef{{$}}
+;.
+define void @init() {
+; CHECK-LABEL: define void @init() local_unnamed_addr {
+; CHECK-NEXT:    ret void
+;
+  %m = call noalias ptr @aligned_alloc(i64 8, i64 32)
+  store ptr %m, ptr @g, align 8
+  ret void
+}
+
+define void @store(<4 x float> %v, i8 %c) {
+; CHECK-LABEL: define void @store(
+; CHECK-SAME: <4 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store <4 x float> [[V]], ptr @g.body, align 16
+; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
+; CHECK-NEXT:    ret void
+;
+  %p = load ptr, ptr @g, align 8
+  store <4 x float> %v, ptr %p, align 16
+  %q = getelementptr i8, ptr %p, i64 3
+  store i8 %c, ptr %q, align 1
+  ret void
+}
+
+define <4 x float> @load() {
+; CHECK-LABEL: define <4 x float> @load() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load <4 x float>, ptr @g.body, align 16
+; CHECK-NEXT:    ret <4 x float> [[V]]
+;
+  %p = load ptr, ptr @g, align 8
+  %v = load <4 x float>, ptr %p, align 16
+  ret <4 x float> %v
+}
+
+declare noalias ptr @aligned_alloc(i64 allocalign, i64) allockind("alloc,uninitialized,aligned") allocsize(1)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-4.ll b/llvm/test/Transforms/GlobalOpt/global-align-4.ll
new file mode 100644
index 0000000000000..61c82f4b3b334
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/global-align-4.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+; Without an `allocalign` just use the alignment of the return value as the
+; alignment of the global.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = internal global ptr null
+
+;.
+; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef{{$}}
+;.
+define void @init() {
+; CHECK-LABEL: define void @init() local_unnamed_addr {
+; CHECK-NEXT:    ret void
+;
+  %m = call noalias align 64 ptr @malloc(i64 64)
+  store ptr %m, ptr @g, align 8
+  ret void
+}
+
+define void @store(<8 x float> %v, i8 %c) {
+; CHECK-LABEL: define void @store(
+; CHECK-SAME: <8 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store <8 x float> [[V]], ptr @g.body, align 32
+; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
+; CHECK-NEXT:    ret void
+;
+  %p = load ptr, ptr @g, align 8
+  store <8 x float> %v, ptr %p, align 32
+  %q = getelementptr i8, ptr %p, i64 3
+  store i8 %c, ptr %q, align 1
+  ret void
+}
+
+define <8 x float> @load() {
+; CHECK-LABEL: define <8 x float> @load() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load <8 x float>, ptr @g.body, align 32
+; CHECK-NEXT:    ret <8 x float> [[V]]
+;
+  %p = load ptr, ptr @g, align 8
+  %v = load <8 x float>, ptr %p, align 32
+  ret <8 x float> %v
+}
+
+declare noalias ptr @malloc(i64) allockind("alloc,uninitialized") allocsize(0)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll b/llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll
new file mode 100644
index 0000000000000..899957b876f73
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll
@@ -0,0 +1,49 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+; With dynamic `allocalign` and no alignment on the `ptr` value leave the
+; alignment unspecified.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = internal global ptr null
+
+;.
+; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef{{$}}
+;.
+define void @init(i64 %a) {
+; CHECK-LABEL: define void @init(
+; CHECK-SAME: i64 [[A:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    ret void
+;
+  %m = call noalias ptr @aligned_alloc(i64 %a, i64 64)
+  store ptr %m, ptr @g, align 8
+  ret void
+}
+
+define void @store(<8 x float> %v, i8 %c) {
+; CHECK-LABEL: define void @store(
+; CHECK-SAME: <8 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store <8 x float> [[V]], ptr @g.body, align 1
+; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
+; CHECK-NEXT:    ret void
+;
+  %p = load ptr, ptr @g, align 8
+  store <8 x float> %v, ptr %p, align 1
+  %q = getelementptr i8, ptr %p, i64 3
+  store i8 %c, ptr %q, align 1
+  ret void
+}
+
+define <8 x float> @load() {
+; CHECK-LABEL: define <8 x float> @load() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load <8 x float>, ptr @g.body, align 1
+; CHECK-NEXT:    ret <8 x float> [[V]]
+;
+  %p = load ptr, ptr @g, align 8
+  %v = load <8 x float>, ptr %p, align 1
+  ret <8 x float> %v
+}
+
+declare noalias ptr @aligned_alloc(i64 allocalign, i64) allockind("alloc,uninitialized,aligned") allocsize(1)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-implicit.ll b/llvm/test/Transforms/GlobalOpt/global-align-implicit.ll
new file mode 100644
index 0000000000000..a6589fea1b791
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/global-align-implicit.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+; Without dynamic `allocalign` and alignment on the `ptr` value leave the
+; alignment unspecified.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = internal global ptr null
+
+;.
+; CHECK: @g.body = internal unnamed_addr global [16 x i8] undef{{$}}
+;.
+define void @init() {
+; CHECK-LABEL: define void @init() local_unnamed_addr {
+; CHECK-NEXT:    ret void
+;
+  %m = call noalias ptr @malloc(i64 16)
+  store ptr %m, ptr @g, align 8
+  ret void
+}
+
+define void @store(<4 x float> %v, i8 %c) {
+; CHECK-LABEL: define void @store(
+; CHECK-SAME: <4 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store <4 x float> [[V]], ptr @g.body, align 1
+; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
+; CHECK-NEXT:    ret void
+;
+  %p = load ptr, ptr @g, align 8
+  store <4 x float> %v, ptr %p, align 1
+  %q = getelementptr i8, ptr %p, i64 3
+  store i8 %c, ptr %q, align 1
+  ret void
+}
+
+define <4 x float> @load() {
+; CHECK-LABEL: define <4 x float> @load() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load <4 x float>, ptr @g.body, align 1
+; CHECK-NEXT:    ret <4 x float> [[V]]
+;
+  %p = load ptr, ptr @g, align 8
+  %v = load <4 x float>, ptr %p, align 1
+  ret <4 x float> %v
+}
+
+declare noalias ptr @malloc(i64) allockind("alloc,uninitialized") allocsize(0)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-memset.ll b/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
new file mode 100644
index 0000000000000..f2110b2834d48
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
@@ -0,0 +1,82 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt < %s -passes=globalopt -S | FileCheck %s
+
+; When initializing an aligned global pass the alignment to the memset call.
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at aligned = internal global ptr null
+ at unaligned = internal global ptr null
+
+;.
+; CHECK: @aligned.body = internal unnamed_addr global [64 x i8] undef{{$}}
+; CHECK: @unaligned.body = internal unnamed_addr global [64 x i8] undef{{$}}
+;.
+define void @init_aligned() {
+; CHECK-LABEL: define void @init_aligned() local_unnamed_addr {
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr @aligned.body, i8 0, i64 64, i1 false)
+; CHECK-NEXT:    ret void
+;
+  %m = call noalias ptr @aligned_calloc(i64 32, i64 64)
+  store ptr %m, ptr @aligned, align 8
+  ret void
+}
+
+define void @store_aligned(<8 x float> %v) {
+; CHECK-LABEL: define void @store_aligned(
+; CHECK-SAME: <8 x float> [[V:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store <8 x float> [[V]], ptr @aligned.body, align 32
+; CHECK-NEXT:    ret void
+;
+  %p = load ptr, ptr @aligned, align 8
+  store <8 x float> %v, ptr %p, align 32
+  ret void
+}
+
+define <8 x float> @load_aligned() {
+; CHECK-LABEL: define <8 x float> @load_aligned() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load <8 x float>, ptr @aligned.body, align 32
+; CHECK-NEXT:    ret <8 x float> [[V]]
+;
+  %p = load ptr, ptr @aligned, align 8
+  %v = load <8 x float>, ptr %p, align 32
+  ret <8 x float> %v
+}
+
+define void @init_unaligned() {
+; CHECK-LABEL: define void @init_unaligned() local_unnamed_addr {
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr @unaligned.body, i8 0, i64 64, i1 false)
+; CHECK-NEXT:    ret void
+;
+  %m = call noalias ptr @calloc(i64 1, i64 64)
+  store ptr %m, ptr @unaligned, align 8
+  ret void
+}
+
+define void @store_unaligned(i8 %c) {
+; CHECK-LABEL: define void @store_unaligned(
+; CHECK-SAME: i8 [[C:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store i8 [[C]], ptr @unaligned.body, align 1
+; CHECK-NEXT:    ret void
+;
+  %p = load ptr, ptr @unaligned, align 8
+  store i8 %c, ptr %p, align 1
+  ret void
+}
+
+define i8 @load_unaligned() {
+; CHECK-LABEL: define i8 @load_unaligned() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load i8, ptr @unaligned.body, align 1
+; CHECK-NEXT:    ret i8 [[V]]
+;
+  %p = load ptr, ptr @unaligned, align 8
+  %v = load i8, ptr %p, align 1
+  ret i8 %v
+}
+
+declare noalias ptr @aligned_calloc(i64 allocalign, i64) allockind("alloc,zeroed,aligned") allocsize(1)
+declare noalias ptr @calloc(i64, i64) allockind("alloc,zeroed") allocsize(0,1)
+;.
+; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: write) }
+;.

>From 89e1b1de707427fde7aa1e1335be900f1a4faca8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Sat, 15 Aug 2026 11:25:39 +0100
Subject: [PATCH 2/3] Fix and update tests

---
 llvm/lib/Transforms/IPO/GlobalOpt.cpp         | 26 +++++++++++++++++--
 .../Transforms/GlobalOpt/calloc-promote.ll    |  2 +-
 .../Transforms/GlobalOpt/global-align-1.ll    |  2 +-
 .../Transforms/GlobalOpt/global-align-2.ll    |  2 +-
 .../Transforms/GlobalOpt/global-align-4.ll    |  2 +-
 .../GlobalOpt/global-align-memset.ll          |  4 +--
 6 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index f78b7169a6a26..6d9c43af83dff 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -944,6 +944,29 @@ OptimizeGlobalAddressOfAllocation(GlobalVariable *GV, CallInst *CI,
       UndefValue::get(GlobalType), GV->getName() + ".body", nullptr,
       GV->getThreadLocalMode());
 
+  // Alignment of the return value of the allocator call.
+  Align GVAlign = CI->getPointerAlignment(DL);
+
+  // If the allocation function has a valid constant `allocalign` argument
+  // that's larger, increase the alignment.
+  const Value *AllocAlign = getAllocAlignment(CI, TLI);
+  if (AllocAlign) {
+    const ConstantInt *AllocAlignC = dyn_cast<ConstantInt>(AllocAlign);
+    if (AllocAlignC &&
+        AllocAlignC->getValue().ult(llvm::Value::MaximumAlignment)) {
+      uint64_t AllocAlignVal = AllocAlignC->getZExtValue();
+      if (llvm::isPowerOf2_64(AllocAlignVal)) {
+        GVAlign = std::max(GVAlign, Align(AllocAlignC->getAlignValue()));
+      }
+    }
+  }
+
+  // Only specify the global alignment if it increases the preferred alignment.
+  // Otherwise leave it unset to allow other optimizations to increase it.
+  if (GVAlign > DL.getPreferredAlign(NewGV)) {
+    NewGV->setAlignment(GVAlign);
+  }
+
   // Initialize the global at the point of the original call.  Note that this
   // is a different point from the initialization referred to below for the
   // nullability handling.  Sublety: We have not proven the original global was
@@ -951,8 +974,7 @@ OptimizeGlobalAddressOfAllocation(GlobalVariable *GV, CallInst *CI,
   // of the new global as may need to re-init the storage multiple times.
   if (!isa<UndefValue>(InitVal)) {
     IRBuilder<> Builder(CI->getNextNode());
-    // TODO: Use alignment above if align!=1
-    Builder.CreateMemSet(NewGV, InitVal, AllocSize, std::nullopt);
+    Builder.CreateMemSet(NewGV, InitVal, AllocSize, NewGV->getAlign());
   }
 
   // Update users of the allocation to use the new global instead.
diff --git a/llvm/test/Transforms/GlobalOpt/calloc-promote.ll b/llvm/test/Transforms/GlobalOpt/calloc-promote.ll
index c369ed9b9fc11..d12b4a8f82cad 100644
--- a/llvm/test/Transforms/GlobalOpt/calloc-promote.ll
+++ b/llvm/test/Transforms/GlobalOpt/calloc-promote.ll
@@ -6,7 +6,7 @@
 define signext i32 @f() local_unnamed_addr {
 ; CHECK-LABEL: @f(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr @g.body, i8 0, i64 4, i1 false)
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 16 @g.body, i8 0, i64 4, i1 false)
 ; CHECK-NEXT:    store i16 -1, ptr @g.body, align 2
 ; CHECK-NEXT:    ret i32 0
 ;
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-1.ll b/llvm/test/Transforms/GlobalOpt/global-align-1.ll
index 0e4eaa4b54f0b..0ab7fae067c1d 100644
--- a/llvm/test/Transforms/GlobalOpt/global-align-1.ll
+++ b/llvm/test/Transforms/GlobalOpt/global-align-1.ll
@@ -13,7 +13,7 @@ target triple = "x86_64-unknown-linux-gnu"
 ;.
 ; CHECK: @g26 = dso_local local_unnamed_addr global <4 x i32> zeroinitializer, align 16
 ; CHECK: @g5 = dso_local local_unnamed_addr global i8 0, align 1
-; CHECK: @g10.body = internal unnamed_addr global [16 x i8] undef{{$}}
+; CHECK: @g10.body = internal unnamed_addr global [16 x i8] undef, align 16
 ;.
 define dso_local i32 @main() {
 ; CHECK-LABEL: define dso_local i32 @main() local_unnamed_addr {
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-2.ll b/llvm/test/Transforms/GlobalOpt/global-align-2.ll
index afc26fca6cb4e..894012d489aa5 100644
--- a/llvm/test/Transforms/GlobalOpt/global-align-2.ll
+++ b/llvm/test/Transforms/GlobalOpt/global-align-2.ll
@@ -9,7 +9,7 @@ target triple = "x86_64-unknown-linux-gnu"
 @g = internal global ptr null
 
 ;.
-; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef{{$}}
+; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef, align 64
 ;.
 define void @init() {
 ; CHECK-LABEL: define void @init() local_unnamed_addr {
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-4.ll b/llvm/test/Transforms/GlobalOpt/global-align-4.ll
index 61c82f4b3b334..b55e668ae402e 100644
--- a/llvm/test/Transforms/GlobalOpt/global-align-4.ll
+++ b/llvm/test/Transforms/GlobalOpt/global-align-4.ll
@@ -10,7 +10,7 @@ target triple = "x86_64-unknown-linux-gnu"
 @g = internal global ptr null
 
 ;.
-; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef{{$}}
+; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef, align 64
 ;.
 define void @init() {
 ; CHECK-LABEL: define void @init() local_unnamed_addr {
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-memset.ll b/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
index f2110b2834d48..4f71994a135e2 100644
--- a/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
+++ b/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
@@ -10,12 +10,12 @@ target triple = "x86_64-unknown-linux-gnu"
 @unaligned = internal global ptr null
 
 ;.
-; CHECK: @aligned.body = internal unnamed_addr global [64 x i8] undef{{$}}
+; CHECK: @aligned.body = internal unnamed_addr global [64 x i8] undef, align 32
 ; CHECK: @unaligned.body = internal unnamed_addr global [64 x i8] undef{{$}}
 ;.
 define void @init_aligned() {
 ; CHECK-LABEL: define void @init_aligned() local_unnamed_addr {
-; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr @aligned.body, i8 0, i64 64, i1 false)
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 32 @aligned.body, i8 0, i64 64, i1 false)
 ; CHECK-NEXT:    ret void
 ;
   %m = call noalias ptr @aligned_calloc(i64 32, i64 64)

>From 22cf21074668d0bb7022975bcfdf7622e3aeaa32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= <omer at osa1.net>
Date: Mon, 17 Aug 2026 09:37:05 +0100
Subject: [PATCH 3/3] Ignore allocalign for now

---
 llvm/lib/Transforms/IPO/GlobalOpt.cpp         | 14 ------
 .../Transforms/GlobalOpt/global-align-2.ll    | 26 +++++-----
 .../Transforms/GlobalOpt/global-align-4.ll    | 48 ------------------
 .../GlobalOpt/global-align-dynamic.ll         | 49 -------------------
 .../GlobalOpt/global-align-implicit.ll        | 48 ------------------
 .../GlobalOpt/global-align-memset.ll          |  4 +-
 6 files changed, 15 insertions(+), 174 deletions(-)
 delete mode 100644 llvm/test/Transforms/GlobalOpt/global-align-4.ll
 delete mode 100644 llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll
 delete mode 100644 llvm/test/Transforms/GlobalOpt/global-align-implicit.ll

diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index 6d9c43af83dff..ad611801195c8 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -947,20 +947,6 @@ OptimizeGlobalAddressOfAllocation(GlobalVariable *GV, CallInst *CI,
   // Alignment of the return value of the allocator call.
   Align GVAlign = CI->getPointerAlignment(DL);
 
-  // If the allocation function has a valid constant `allocalign` argument
-  // that's larger, increase the alignment.
-  const Value *AllocAlign = getAllocAlignment(CI, TLI);
-  if (AllocAlign) {
-    const ConstantInt *AllocAlignC = dyn_cast<ConstantInt>(AllocAlign);
-    if (AllocAlignC &&
-        AllocAlignC->getValue().ult(llvm::Value::MaximumAlignment)) {
-      uint64_t AllocAlignVal = AllocAlignC->getZExtValue();
-      if (llvm::isPowerOf2_64(AllocAlignVal)) {
-        GVAlign = std::max(GVAlign, Align(AllocAlignC->getAlignValue()));
-      }
-    }
-  }
-
   // Only specify the global alignment if it increases the preferred alignment.
   // Otherwise leave it unset to allow other optimizations to increase it.
   if (GVAlign > DL.getPreferredAlign(NewGV)) {
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-2.ll b/llvm/test/Transforms/GlobalOpt/global-align-2.ll
index 894012d489aa5..9f8c6be68e4e4 100644
--- a/llvm/test/Transforms/GlobalOpt/global-align-2.ll
+++ b/llvm/test/Transforms/GlobalOpt/global-align-2.ll
@@ -1,7 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
 ; RUN: opt < %s -passes=globalopt -S | FileCheck %s
 
-; Test non-power-of-two aligned global allocations.
+; Use the declared alignment of the allocation as the global's alignment.
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
@@ -15,33 +15,33 @@ define void @init() {
 ; CHECK-LABEL: define void @init() local_unnamed_addr {
 ; CHECK-NEXT:    ret void
 ;
-  %m = call noalias align 64 ptr @aligned_alloc(i64 100, i64 64)
+  %m = call noalias align 64 ptr @malloc(i64 64)
   store ptr %m, ptr @g, align 8
   ret void
 }
 
-define void @store(<4 x float> %v, i8 %c) {
+define void @store(<8 x float> %v, i8 %c) {
 ; CHECK-LABEL: define void @store(
-; CHECK-SAME: <4 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
-; CHECK-NEXT:    store <4 x float> [[V]], ptr @g.body, align 16
+; CHECK-SAME: <8 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
+; CHECK-NEXT:    store <8 x float> [[V]], ptr @g.body, align 32
 ; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
 ; CHECK-NEXT:    ret void
 ;
   %p = load ptr, ptr @g, align 8
-  store <4 x float> %v, ptr %p, align 16
+  store <8 x float> %v, ptr %p, align 32
   %q = getelementptr i8, ptr %p, i64 3
   store i8 %c, ptr %q, align 1
   ret void
 }
 
-define <4 x float> @load() {
-; CHECK-LABEL: define <4 x float> @load() local_unnamed_addr {
-; CHECK-NEXT:    [[V:%.*]] = load <4 x float>, ptr @g.body, align 16
-; CHECK-NEXT:    ret <4 x float> [[V]]
+define <8 x float> @load() {
+; CHECK-LABEL: define <8 x float> @load() local_unnamed_addr {
+; CHECK-NEXT:    [[V:%.*]] = load <8 x float>, ptr @g.body, align 32
+; CHECK-NEXT:    ret <8 x float> [[V]]
 ;
   %p = load ptr, ptr @g, align 8
-  %v = load <4 x float>, ptr %p, align 16
-  ret <4 x float> %v
+  %v = load <8 x float>, ptr %p, align 32
+  ret <8 x float> %v
 }
 
-declare noalias ptr @aligned_alloc(i64 allocalign, i64) allockind("alloc,uninitialized,aligned") allocsize(1)
+declare noalias ptr @malloc(i64) allockind("alloc,uninitialized") allocsize(0)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-4.ll b/llvm/test/Transforms/GlobalOpt/global-align-4.ll
deleted file mode 100644
index b55e668ae402e..0000000000000
--- a/llvm/test/Transforms/GlobalOpt/global-align-4.ll
+++ /dev/null
@@ -1,48 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
-; RUN: opt < %s -passes=globalopt -S | FileCheck %s
-
-; Without an `allocalign` just use the alignment of the return value as the
-; alignment of the global.
-
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
- at g = internal global ptr null
-
-;.
-; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef, align 64
-;.
-define void @init() {
-; CHECK-LABEL: define void @init() local_unnamed_addr {
-; CHECK-NEXT:    ret void
-;
-  %m = call noalias align 64 ptr @malloc(i64 64)
-  store ptr %m, ptr @g, align 8
-  ret void
-}
-
-define void @store(<8 x float> %v, i8 %c) {
-; CHECK-LABEL: define void @store(
-; CHECK-SAME: <8 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
-; CHECK-NEXT:    store <8 x float> [[V]], ptr @g.body, align 32
-; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
-; CHECK-NEXT:    ret void
-;
-  %p = load ptr, ptr @g, align 8
-  store <8 x float> %v, ptr %p, align 32
-  %q = getelementptr i8, ptr %p, i64 3
-  store i8 %c, ptr %q, align 1
-  ret void
-}
-
-define <8 x float> @load() {
-; CHECK-LABEL: define <8 x float> @load() local_unnamed_addr {
-; CHECK-NEXT:    [[V:%.*]] = load <8 x float>, ptr @g.body, align 32
-; CHECK-NEXT:    ret <8 x float> [[V]]
-;
-  %p = load ptr, ptr @g, align 8
-  %v = load <8 x float>, ptr %p, align 32
-  ret <8 x float> %v
-}
-
-declare noalias ptr @malloc(i64) allockind("alloc,uninitialized") allocsize(0)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll b/llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll
deleted file mode 100644
index 899957b876f73..0000000000000
--- a/llvm/test/Transforms/GlobalOpt/global-align-dynamic.ll
+++ /dev/null
@@ -1,49 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
-; RUN: opt < %s -passes=globalopt -S | FileCheck %s
-
-; With dynamic `allocalign` and no alignment on the `ptr` value leave the
-; alignment unspecified.
-
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
- at g = internal global ptr null
-
-;.
-; CHECK: @g.body = internal unnamed_addr global [64 x i8] undef{{$}}
-;.
-define void @init(i64 %a) {
-; CHECK-LABEL: define void @init(
-; CHECK-SAME: i64 [[A:%.*]]) local_unnamed_addr {
-; CHECK-NEXT:    ret void
-;
-  %m = call noalias ptr @aligned_alloc(i64 %a, i64 64)
-  store ptr %m, ptr @g, align 8
-  ret void
-}
-
-define void @store(<8 x float> %v, i8 %c) {
-; CHECK-LABEL: define void @store(
-; CHECK-SAME: <8 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
-; CHECK-NEXT:    store <8 x float> [[V]], ptr @g.body, align 1
-; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
-; CHECK-NEXT:    ret void
-;
-  %p = load ptr, ptr @g, align 8
-  store <8 x float> %v, ptr %p, align 1
-  %q = getelementptr i8, ptr %p, i64 3
-  store i8 %c, ptr %q, align 1
-  ret void
-}
-
-define <8 x float> @load() {
-; CHECK-LABEL: define <8 x float> @load() local_unnamed_addr {
-; CHECK-NEXT:    [[V:%.*]] = load <8 x float>, ptr @g.body, align 1
-; CHECK-NEXT:    ret <8 x float> [[V]]
-;
-  %p = load ptr, ptr @g, align 8
-  %v = load <8 x float>, ptr %p, align 1
-  ret <8 x float> %v
-}
-
-declare noalias ptr @aligned_alloc(i64 allocalign, i64) allockind("alloc,uninitialized,aligned") allocsize(1)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-implicit.ll b/llvm/test/Transforms/GlobalOpt/global-align-implicit.ll
deleted file mode 100644
index a6589fea1b791..0000000000000
--- a/llvm/test/Transforms/GlobalOpt/global-align-implicit.ll
+++ /dev/null
@@ -1,48 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
-; RUN: opt < %s -passes=globalopt -S | FileCheck %s
-
-; Without dynamic `allocalign` and alignment on the `ptr` value leave the
-; alignment unspecified.
-
-target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-unknown-linux-gnu"
-
- at g = internal global ptr null
-
-;.
-; CHECK: @g.body = internal unnamed_addr global [16 x i8] undef{{$}}
-;.
-define void @init() {
-; CHECK-LABEL: define void @init() local_unnamed_addr {
-; CHECK-NEXT:    ret void
-;
-  %m = call noalias ptr @malloc(i64 16)
-  store ptr %m, ptr @g, align 8
-  ret void
-}
-
-define void @store(<4 x float> %v, i8 %c) {
-; CHECK-LABEL: define void @store(
-; CHECK-SAME: <4 x float> [[V:%.*]], i8 [[C:%.*]]) local_unnamed_addr {
-; CHECK-NEXT:    store <4 x float> [[V]], ptr @g.body, align 1
-; CHECK-NEXT:    store i8 [[C]], ptr getelementptr inbounds nuw (i8, ptr @g.body, i64 3), align 1
-; CHECK-NEXT:    ret void
-;
-  %p = load ptr, ptr @g, align 8
-  store <4 x float> %v, ptr %p, align 1
-  %q = getelementptr i8, ptr %p, i64 3
-  store i8 %c, ptr %q, align 1
-  ret void
-}
-
-define <4 x float> @load() {
-; CHECK-LABEL: define <4 x float> @load() local_unnamed_addr {
-; CHECK-NEXT:    [[V:%.*]] = load <4 x float>, ptr @g.body, align 1
-; CHECK-NEXT:    ret <4 x float> [[V]]
-;
-  %p = load ptr, ptr @g, align 8
-  %v = load <4 x float>, ptr %p, align 1
-  ret <4 x float> %v
-}
-
-declare noalias ptr @malloc(i64) allockind("alloc,uninitialized") allocsize(0)
diff --git a/llvm/test/Transforms/GlobalOpt/global-align-memset.ll b/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
index 4f71994a135e2..53716b733caad 100644
--- a/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
+++ b/llvm/test/Transforms/GlobalOpt/global-align-memset.ll
@@ -18,7 +18,7 @@ define void @init_aligned() {
 ; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr align 32 @aligned.body, i8 0, i64 64, i1 false)
 ; CHECK-NEXT:    ret void
 ;
-  %m = call noalias ptr @aligned_calloc(i64 32, i64 64)
+  %m = call noalias align 32 ptr @aligned_calloc(i64 32, i64 64)
   store ptr %m, ptr @aligned, align 8
   ret void
 }
@@ -75,7 +75,7 @@ define i8 @load_unaligned() {
   ret i8 %v
 }
 
-declare noalias ptr @aligned_calloc(i64 allocalign, i64) allockind("alloc,zeroed,aligned") allocsize(1)
+declare noalias ptr @aligned_calloc(i64, i64) allockind("alloc,zeroed,aligned") allocsize(1)
 declare noalias ptr @calloc(i64, i64) allockind("alloc,zeroed") allocsize(0,1)
 ;.
 ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: write) }



More information about the llvm-commits mailing list