[llvm] [Hexagon] Add GlobalArrayAlignment pass (PR #217850)
Akash Agrawal via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 21:07:48 PDT 2026
https://github.com/akashagrwl updated https://github.com/llvm/llvm-project/pull/217850
>From d5f2fc61f13cea4cb25a446c9e2b1f17265b6217 Mon Sep 17 00:00:00 2001
From: Akash Agrawal <akashag at qti.qualcomm.com>
Date: Fri, 21 Aug 2026 01:46:55 -0700
Subject: [PATCH 1/2] [Hexagon] Add GlobalArrayAlignment pass
Add a module pass that raises the alignment of global integer arrays
(char, short, int), including multi-dimensional arrays, to an 8-byte
boundary. This gives their base address a wider alignment, which is
beneficial for the wide (double-word) loads and stores available on
Hexagon.
At -O1/-O2 the pass keeps byte and half-word arrays at their natural
alignment to reduce .rodata size; full 8-byte alignment is applied at
-O3. This size-reduction behavior can be disabled with
-hexagon-disable-align-opt-byte-half.
The pass is enabled by default and can be disabled with
-hexagon-disable-global-array-align.
---
llvm/lib/Target/Hexagon/CMakeLists.txt | 1 +
llvm/lib/Target/Hexagon/Hexagon.h | 4 +
.../Hexagon/HexagonAlignGlobalArrays.cpp | 125 ++++++++++++++++++
.../Target/Hexagon/HexagonTargetMachine.cpp | 6 +
.../CodeGen/Hexagon/align-global-arrays.ll | 72 ++++++++++
5 files changed, 208 insertions(+)
create mode 100644 llvm/lib/Target/Hexagon/HexagonAlignGlobalArrays.cpp
create mode 100644 llvm/test/CodeGen/Hexagon/align-global-arrays.ll
diff --git a/llvm/lib/Target/Hexagon/CMakeLists.txt b/llvm/lib/Target/Hexagon/CMakeLists.txt
index 0f871c1f65cd4..bdd826e7950fe 100644
--- a/llvm/lib/Target/Hexagon/CMakeLists.txt
+++ b/llvm/lib/Target/Hexagon/CMakeLists.txt
@@ -18,6 +18,7 @@ add_public_tablegen_target(HexagonCommonTableGen)
add_llvm_target(HexagonCodeGen
BitTracker.cpp
+ HexagonAlignGlobalArrays.cpp
HexagonAsmPrinter.cpp
HexagonBitSimplify.cpp
HexagonBitTracker.cpp
diff --git a/llvm/lib/Target/Hexagon/Hexagon.h b/llvm/lib/Target/Hexagon/Hexagon.h
index f7242d0d843ed..b0e5041fb850a 100644
--- a/llvm/lib/Target/Hexagon/Hexagon.h
+++ b/llvm/lib/Target/Hexagon/Hexagon.h
@@ -19,6 +19,7 @@
namespace llvm {
class HexagonTargetMachine;
class ImmutablePass;
+class ModulePass;
class PassRegistry;
class FunctionPass;
class Pass;
@@ -27,6 +28,7 @@ extern char &HexagonCopyHoistingID;
extern char &HexagonExpandCondsetsID;
extern char &HexagonTfrCleanupID;
extern char &HexagonLiveVariablesID;
+void initializeHexagonAlignGlobalArraysPass(PassRegistry &);
void initializeHexagonAsmPrinterPass(PassRegistry &);
void initializeHexagonBitSimplifyPass(PassRegistry &);
void initializeHexagonBranchRelaxationPass(PassRegistry &);
@@ -81,6 +83,8 @@ Pass *createHexagonVectorLoopCarriedReuseLegacyPass();
ImmutablePass *
createHexagonTargetTransformInfoPass(const HexagonTargetMachine *TM);
+ModulePass *createHexagonAlignGlobalArrays(bool ReduceRodataSize);
+
FunctionPass *createHexagonBitSimplify();
FunctionPass *createHexagonBranchRelaxation();
FunctionPass *createHexagonCallFrameInformation();
diff --git a/llvm/lib/Target/Hexagon/HexagonAlignGlobalArrays.cpp b/llvm/lib/Target/Hexagon/HexagonAlignGlobalArrays.cpp
new file mode 100644
index 0000000000000..42f5c6ca1df1f
--- /dev/null
+++ b/llvm/lib/Target/Hexagon/HexagonAlignGlobalArrays.cpp
@@ -0,0 +1,125 @@
+//===- HexagonAlignGlobalArrays.cpp - Align Global Arrays -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass increases the alignment of global integer arrays (char, short,
+// int), including multi-dimensional arrays, to an 8-byte boundary. This gives
+// their base address a wider alignment, which is beneficial for the wide
+// (double-word) loads and stores available on Hexagon.
+//
+// When optimizing to reduce .rodata size, byte and half-word arrays already at
+// an alignment of two bytes or less are left at their natural alignment; only
+// word arrays are promoted. This size behavior can be turned off with
+// -hexagon-disable-align-opt-byte-half.
+//
+// The pass is enabled by default and can be disabled with
+// -hexagon-disable-global-array-align.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Hexagon.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "hexagon-global-array-alignment"
+
+static cl::opt<bool> DisableGlobalArrayAlignment(
+ "hexagon-disable-global-array-align",
+ cl::desc("Disable aligning global integer arrays to an 8-byte boundary"),
+ cl::init(false), cl::Hidden);
+
+static cl::opt<bool> DisableHexAlignOptByteHalf(
+ "hexagon-disable-align-opt-byte-half",
+ cl::desc("Disable keeping byte and half-word arrays at their natural "
+ "alignment when reducing .rodata size"),
+ cl::Hidden);
+
+namespace {
+
+class HexagonAlignGlobalArrays : public ModulePass {
+ bool ReduceRodataSize;
+
+public:
+ static char ID;
+
+ explicit HexagonAlignGlobalArrays(bool ReduceRodataSize = false)
+ : ModulePass(ID), ReduceRodataSize(ReduceRodataSize) {}
+
+ StringRef getPassName() const override {
+ return "Hexagon Global Array Alignment";
+ }
+
+ bool runOnModule(Module &M) override;
+};
+
+} // end anonymous namespace
+
+char HexagonAlignGlobalArrays::ID = 0;
+
+INITIALIZE_PASS(HexagonAlignGlobalArrays, "hexagon-global-array-alignment",
+ "Align Global Arrays to 8-byte", false, false)
+
+ModulePass *llvm::createHexagonAlignGlobalArrays(bool ReduceRodataSize) {
+ return new HexagonAlignGlobalArrays(ReduceRodataSize);
+}
+
+// Get the underlying element type of an array. This is useful if the array is
+// multi-dimensional.
+static Type *getUnderlyingArrayElmTy(Type *Ty) {
+ // Ty is guaranteed to be an array type.
+ Type *ElTy = cast<ArrayType>(Ty)->getElementType();
+ while (ElTy->isArrayTy())
+ ElTy = cast<ArrayType>(ElTy)->getElementType();
+ return ElTy;
+}
+
+bool HexagonAlignGlobalArrays::runOnModule(Module &M) {
+ if (DisableGlobalArrayAlignment)
+ return false;
+
+ bool Changed = false;
+ const DataLayout &DL = M.getDataLayout();
+
+ for (GlobalVariable &GV : M.globals()) {
+ Type *VT = GV.getValueType();
+ if (!VT->isArrayTy())
+ continue;
+
+ Type *ElTy = getUnderlyingArrayElmTy(VT);
+ if (!ElTy->isIntegerTy())
+ continue;
+
+ // Skip globals whose alignment cannot be safely raised, e.g. declarations,
+ // weak/interposable definitions, and section-pinned globals.
+ if (!GV.canIncreaseAlignment())
+ continue;
+
+ // Compute the current alignment, falling back to the ABI alignment.
+ MaybeAlign GVAlign = GV.getAlign();
+ if (!GVAlign && VT->isSized())
+ GVAlign = DL.getABITypeAlign(VT);
+
+ // Align integer arrays to an 8-byte boundary. When reducing .rodata size,
+ // leave byte and half-word arrays that are already at an alignment of two
+ // bytes or less at their natural alignment; word arrays are still promoted.
+ if (!ReduceRodataSize || !GVAlign || *GVAlign > Align(2) ||
+ DisableHexAlignOptByteHalf) {
+ MaybeAlign NewAlign = std::max(GVAlign.valueOrOne(), Align(8));
+ if (NewAlign != GVAlign) {
+ GV.setAlignment(NewAlign);
+ Changed = true;
+ LLVM_DEBUG(dbgs() << GV << '\n');
+ }
+ }
+ }
+
+ return Changed;
+}
diff --git a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
index 8728bd996551b..70f6bdaba0511 100644
--- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
@@ -206,6 +206,7 @@ LLVMInitializeHexagonTarget() {
RegisterTargetMachine<HexagonTargetMachine> X(getTheHexagonTarget());
PassRegistry &PR = *PassRegistry::getPassRegistry();
+ initializeHexagonAlignGlobalArraysPass(PR);
initializeHexagonAsmPrinterPass(PR);
initializeHexagonBitSimplifyPass(PR);
initializeHexagonConstExtendersPass(PR);
@@ -389,6 +390,11 @@ void HexagonPassConfig::addIRPasses() {
bool NoOpt = (getOptLevel() == CodeGenOptLevel::None);
if (!NoOpt) {
+ // Raise the alignment of global integer arrays to 8 bytes. At -O1/-O2,
+ // reduce .rodata size by keeping byte/half-word arrays at their natural
+ // alignment; apply full 8-byte alignment at -O3.
+ addPass(createHexagonAlignGlobalArrays(getOptLevel() !=
+ CodeGenOptLevel::Aggressive));
if (EnableInstSimplify)
addPass(createInstSimplifyLegacyPass());
addPass(createDeadCodeEliminationPass());
diff --git a/llvm/test/CodeGen/Hexagon/align-global-arrays.ll b/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
new file mode 100644
index 0000000000000..d1f46c9715f4b
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
@@ -0,0 +1,72 @@
+; The pass is enabled by default. At -O3 it does not reduce .rodata size, so
+; every locally-defined global integer array (including multi-dimensional ones)
+; is aligned to at least 8 bytes.
+; RUN: llc -mtriple=hexagon -O3 \
+; RUN: -stop-after=hexagon-global-array-alignment < %s | FileCheck %s
+;
+; At -O1 and -O2 the pass reduces .rodata size, so byte and half-word arrays
+; with alignment <= 2 keep their natural alignment, while word arrays are
+; still aligned to 8 bytes.
+; RUN: llc -mtriple=hexagon -O1 \
+; RUN: -stop-after=hexagon-global-array-alignment < %s \
+; RUN: | FileCheck %s --check-prefix=RODATA
+; RUN: llc -mtriple=hexagon -O2 \
+; RUN: -stop-after=hexagon-global-array-alignment < %s \
+; RUN: | FileCheck %s --check-prefix=RODATA
+;
+; The pass can be disabled with -hexagon-disable-global-array-align.
+; RUN: llc -mtriple=hexagon -O3 -hexagon-disable-global-array-align \
+; RUN: -stop-after=hexagon-global-array-alignment < %s \
+; RUN: | FileCheck %s --check-prefix=DISABLED
+
+; Locally-defined integer arrays are promoted to at least 8 bytes.
+; CHECK: @int_array = dso_local global [4 x i32] zeroinitializer, align 8
+; CHECK: @char_array = dso_local global [8 x i8] zeroinitializer, align 8
+; CHECK: @short_array = dso_local global [4 x i16] zeroinitializer, align 8
+; CHECK: @multidim = dso_local global [3 x [5 x i32]] zeroinitializer, align 8
+; CHECK: @explicit = dso_local global [4 x i32] zeroinitializer, align 16
+; CHECK: @scalar = dso_local global i32 0, align 4
+
+; When reducing .rodata size, byte/half arrays at align <= 2 are left alone, but
+; word arrays are still promoted to 8 bytes.
+; RODATA: @int_array = dso_local global [4 x i32] zeroinitializer, align 8
+; RODATA: @char_array = dso_local global [8 x i8] zeroinitializer, align 1
+; RODATA: @short_array = dso_local global [4 x i16] zeroinitializer, align 2
+; RODATA: @multidim = dso_local global [3 x [5 x i32]] zeroinitializer, align 8
+; RODATA: @explicit = dso_local global [4 x i32] zeroinitializer, align 16
+; RODATA: @scalar = dso_local global i32 0, align 4
+
+; DISABLED: @int_array = dso_local global [4 x i32] zeroinitializer, align 4
+; DISABLED: @char_array = dso_local global [8 x i8] zeroinitializer, align 1
+; DISABLED: @short_array = dso_local global [4 x i16] zeroinitializer, align 2
+; DISABLED: @multidim = dso_local global [3 x [5 x i32]] zeroinitializer, align 4
+; DISABLED: @explicit = dso_local global [4 x i32] zeroinitializer, align 16
+; DISABLED: @scalar = dso_local global i32 0, align 4
+
+; The alignment of globals whose definition the linker may override or relocate
+; is left untouched (see GlobalObject::canIncreaseAlignment). These must keep
+; their original alignment for both the -O3 and -O2 runs.
+; CHECK: @extern_decl = external dso_local global [4 x i32], align 4
+; CHECK: @weak_arr = weak dso_local global [4 x i32] zeroinitializer, align 4
+; CHECK: @interposable = global [4 x i32] zeroinitializer, align 4
+; CHECK: @sectioned = dso_local global [4 x i32] zeroinitializer, section ".mysec", align 4
+; RODATA: @extern_decl = external dso_local global [4 x i32], align 4
+; RODATA: @weak_arr = weak dso_local global [4 x i32] zeroinitializer, align 4
+; RODATA: @interposable = global [4 x i32] zeroinitializer, align 4
+; RODATA: @sectioned = dso_local global [4 x i32] zeroinitializer, section ".mysec", align 4
+
+ at int_array = dso_local global [4 x i32] zeroinitializer, align 4
+ at char_array = dso_local global [8 x i8] zeroinitializer, align 1
+ at short_array = dso_local global [4 x i16] zeroinitializer, align 2
+ at multidim = dso_local global [3 x [5 x i32]] zeroinitializer, align 4
+ at explicit = dso_local global [4 x i32] zeroinitializer, align 16
+ at scalar = dso_local global i32 0, align 4
+
+; A declaration: the definition (and its alignment) lives in another module.
+ at extern_decl = external dso_local global [4 x i32], align 4
+; A weak definition: the linker may choose a different definition.
+ at weak_arr = weak dso_local global [4 x i32] zeroinitializer, align 4
+; An interposable (non-dso_local) definition subject to COPY relocations.
+ at interposable = global [4 x i32] zeroinitializer, align 4
+; A section-pinned global: raising the alignment could introduce padding.
+ at sectioned = dso_local global [4 x i32] zeroinitializer, section ".mysec", align 4
>From b90a15304626f873b288bc29f8f08876dd88e198 Mon Sep 17 00:00:00 2001
From: Akash Agrawal <akashag at qti.qualcomm.com>
Date: Wed, 26 Aug 2026 23:11:20 -0700
Subject: [PATCH 2/2] address comment - covered the flag with the test case
---
llvm/test/CodeGen/Hexagon/align-global-arrays.ll | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/llvm/test/CodeGen/Hexagon/align-global-arrays.ll b/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
index d1f46c9715f4b..de4be5f7a7966 100644
--- a/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
+++ b/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
@@ -14,6 +14,11 @@
; RUN: -stop-after=hexagon-global-array-alignment < %s \
; RUN: | FileCheck %s --check-prefix=RODATA
;
+; With -hexagon-disable-align-opt-byte-half the .rodata size reduction is off,
+; so byte and half-word arrays are promoted to 8 bytes even at -O2, as at -O3.
+; RUN: llc -mtriple=hexagon -O2 -hexagon-disable-align-opt-byte-half \
+; RUN: -stop-after=hexagon-global-array-alignment < %s | FileCheck %s
+;
; The pass can be disabled with -hexagon-disable-global-array-align.
; RUN: llc -mtriple=hexagon -O3 -hexagon-disable-global-array-align \
; RUN: -stop-after=hexagon-global-array-alignment < %s \
More information about the llvm-commits
mailing list