[llvm] [Hexagon] Add GlobalArrayAlignment pass (PR #205293)
Akash Agrawal via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 23 23:48:08 PDT 2026
https://github.com/akashagrwl updated https://github.com/llvm/llvm-project/pull/205293
>From 5ff332f6cd003078ba87098bd766f097dd88bb5b Mon Sep 17 00:00:00 2001
From: Akash Agrawal <akashag at qti.qualcomm.com>
Date: Tue, 23 Jun 2026 01:31:56 -0700
Subject: [PATCH 1/2] This pass increases the alignment of global integer
arrays (char, short, int), including multi-dimensional arrays, to an 8-byte
boundary for compatibility with GCC. When optimizing for size (-O1/-O2), byte
and half-word arrays with alignment of 2 bytes or less remain at their native
alignment. This can be changed using -hexagon-disable-align-opt-byte-half.
The pass is registered as "hexagon-global-array-alignment".It is
disabled by default and can be enabled with -hexagon-align-global-arrays.
---
llvm/lib/Target/Hexagon/CMakeLists.txt | 1 +
llvm/lib/Target/Hexagon/Hexagon.h | 4 +
.../Hexagon/HexagonAlignGlobalArrays.cpp | 114 ++++++++++++++++++
.../Target/Hexagon/HexagonTargetMachine.cpp | 5 +
.../CodeGen/Hexagon/align-global-arrays.ll | 27 +++++
5 files changed, 151 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 38dcc09282330..2c4538960be1d 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 1db2326b274dc..57e85fd5734fb 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 &);
@@ -79,6 +81,8 @@ Pass *createHexagonVectorLoopCarriedReuseLegacyPass();
ImmutablePass *
createHexagonTargetTransformInfoPass(const HexagonTargetMachine *TM);
+ModulePass *createHexagonAlignGlobalArrays(bool Os);
+
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..06ccda6b0901a
--- /dev/null
+++ b/llvm/lib/Target/Hexagon/HexagonAlignGlobalArrays.cpp
@@ -0,0 +1,114 @@
+//===- 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 is
+// done to make their alignment compatible with GCC. The pass is disabled by
+// default and can be enabled with -hexagon-align-global-arrays.
+//
+//===----------------------------------------------------------------------===//
+
+#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> EnableGlobalArrayAlignment(
+ "hexagon-align-global-arrays",
+ cl::desc("Align 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 optimizing byte and half-word array alignment when "
+ "optimizing for size"),
+ cl::Hidden);
+
+namespace {
+
+class HexagonAlignGlobalArrays : public ModulePass {
+ bool OptForSize;
+
+public:
+ static char ID;
+
+ explicit HexagonAlignGlobalArrays(bool Os = false)
+ : ModulePass(ID), OptForSize(Os) {}
+
+ 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 Os) {
+ return new HexagonAlignGlobalArrays(Os);
+}
+
+// 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();
+ if (ElTy->isArrayTy())
+ ElTy = getUnderlyingArrayElmTy(ElTy);
+ return ElTy;
+}
+
+bool HexagonAlignGlobalArrays::runOnModule(Module &M) {
+ if (!EnableGlobalArrayAlignment)
+ return false;
+
+ bool Changed = false;
+ const DataLayout &DL = M.getDataLayout();
+
+ for (GlobalVariable &GV : M.globals()) {
+ Type *VT = GV.getValueType();
+
+ // Compute the current alignment, falling back to the ABI alignment.
+ MaybeAlign GVAlign = GV.getAlign();
+ if (!GVAlign && VT->isSized())
+ GVAlign = DL.getABITypeAlign(VT);
+
+ // Align global integer arrays (char, short, int) to an 8-byte boundary.
+ // This makes their alignment compatible with GCC. Chars and shorts keep
+ // their native alignment if not explicitly aligned to a larger size.
+ if (VT->isArrayTy()) {
+ Type *ElTy = getUnderlyingArrayElmTy(VT);
+ if (ElTy->isIntegerTy()) {
+ if (OptForSize && GVAlign && *GVAlign <= Align(2) &&
+ !DisableHexAlignOptByteHalf) {
+ ; // Do nothing.
+ } else {
+ 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 5c72b6cb20883..80cd782fec920 100644
--- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp
@@ -188,6 +188,7 @@ LLVMInitializeHexagonTarget() {
RegisterTargetMachine<HexagonTargetMachine> X(getTheHexagonTarget());
PassRegistry &PR = *PassRegistry::getPassRegistry();
+ initializeHexagonAlignGlobalArraysPass(PR);
initializeHexagonAsmPrinterPass(PR);
initializeHexagonBitSimplifyPass(PR);
initializeHexagonConstExtendersPass(PR);
@@ -367,6 +368,10 @@ void HexagonPassConfig::addIRPasses() {
bool NoOpt = (getOptLevel() == CodeGenOptLevel::None);
if (!NoOpt) {
+ // Set the minimum alignment of global integer arrays (char, short, int) to
+ // 8 bytes. Disabled by default; enabled with -hexagon-align-global-arrays.
+ 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..8ae77e97360d3
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
@@ -0,0 +1,27 @@
+; RUN: llc -mtriple=hexagon -O3 -hexagon-align-global-arrays \
+; RUN: -stop-after=hexagon-global-array-alignment < %s | FileCheck %s
+; RUN: llc -mtriple=hexagon -O3 -stop-after=hexagon-global-array-alignment < %s \
+; RUN: | FileCheck %s --check-prefix=DISABLED
+
+; At -O3 (no opt-for-size), the pass aligns integer arrays (including
+; multi-dimensional ones) to at least 8 bytes, while non-array and non-integer
+; globals are left untouched.
+
+; CHECK: @int_array = global [4 x i32] zeroinitializer, align 8
+; CHECK: @char_array = global [8 x i8] zeroinitializer, align 8
+; CHECK: @multidim = global [3 x [5 x i32]] zeroinitializer, align 8
+; CHECK: @explicit = global [4 x i32] zeroinitializer, align 16
+; CHECK: @scalar = global i32 0, align 4
+
+; Without the flag, the pass makes no changes.
+; DISABLED: @int_array = global [4 x i32] zeroinitializer, align 4
+; DISABLED: @char_array = global [8 x i8] zeroinitializer, align 1
+; DISABLED: @multidim = global [3 x [5 x i32]] zeroinitializer, align 4
+; DISABLED: @explicit = global [4 x i32] zeroinitializer, align 16
+; DISABLED: @scalar = global i32 0, align 4
+
+ at int_array = global [4 x i32] zeroinitializer, align 4
+ at char_array = global [8 x i8] zeroinitializer, align 1
+ at multidim = global [3 x [5 x i32]] zeroinitializer, align 4
+ at explicit = global [4 x i32] zeroinitializer, align 16
+ at scalar = global i32 0, align 4
>From 3d5c304208e483de9b04f38470cf2de42731e1a6 Mon Sep 17 00:00:00 2001
From: Akash Agrawal <akashag at qti.qualcomm.com>
Date: Tue, 23 Jun 2026 23:47:30 -0700
Subject: [PATCH 2/2] added RUN commands for Os (opt for size)
---
.../CodeGen/Hexagon/align-global-arrays.ll | 28 +++++++++++++++----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/llvm/test/CodeGen/Hexagon/align-global-arrays.ll b/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
index 8ae77e97360d3..b90ab0986e923 100644
--- a/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
+++ b/llvm/test/CodeGen/Hexagon/align-global-arrays.ll
@@ -1,27 +1,45 @@
+; At -O3 the pass does not optimize for size, so every global integer array
+; (including multi-dimensional ones) is aligned to at least 8 bytes.
; RUN: llc -mtriple=hexagon -O3 -hexagon-align-global-arrays \
; RUN: -stop-after=hexagon-global-array-alignment < %s | FileCheck %s
+;
+; At -O2 the pass optimizes for size, so byte and half-word arrays with
+; alignment <= 2 keep their native alignment, while word arrays are still
+; aligned to 8 bytes.
+; RUN: llc -mtriple=hexagon -O2 -hexagon-align-global-arrays \
+; RUN: -stop-after=hexagon-global-array-alignment < %s \
+; RUN: | FileCheck %s --check-prefix=OPTSIZE
+;
+; Without the flag the pass makes no changes.
; RUN: llc -mtriple=hexagon -O3 -stop-after=hexagon-global-array-alignment < %s \
; RUN: | FileCheck %s --check-prefix=DISABLED
-; At -O3 (no opt-for-size), the pass aligns integer arrays (including
-; multi-dimensional ones) to at least 8 bytes, while non-array and non-integer
-; globals are left untouched.
-
; CHECK: @int_array = global [4 x i32] zeroinitializer, align 8
; CHECK: @char_array = global [8 x i8] zeroinitializer, align 8
+; CHECK: @short_array = global [4 x i16] zeroinitializer, align 8
; CHECK: @multidim = global [3 x [5 x i32]] zeroinitializer, align 8
; CHECK: @explicit = global [4 x i32] zeroinitializer, align 16
; CHECK: @scalar = global i32 0, align 4
-; Without the flag, the pass makes no changes.
+; When optimizing for size, byte/half arrays at align <= 2 are left alone, but
+; word arrays are still promoted to 8 bytes.
+; OPTSIZE: @int_array = global [4 x i32] zeroinitializer, align 8
+; OPTSIZE: @char_array = global [8 x i8] zeroinitializer, align 1
+; OPTSIZE: @short_array = global [4 x i16] zeroinitializer, align 2
+; OPTSIZE: @multidim = global [3 x [5 x i32]] zeroinitializer, align 8
+; OPTSIZE: @explicit = global [4 x i32] zeroinitializer, align 16
+; OPTSIZE: @scalar = global i32 0, align 4
+
; DISABLED: @int_array = global [4 x i32] zeroinitializer, align 4
; DISABLED: @char_array = global [8 x i8] zeroinitializer, align 1
+; DISABLED: @short_array = global [4 x i16] zeroinitializer, align 2
; DISABLED: @multidim = global [3 x [5 x i32]] zeroinitializer, align 4
; DISABLED: @explicit = global [4 x i32] zeroinitializer, align 16
; DISABLED: @scalar = global i32 0, align 4
@int_array = global [4 x i32] zeroinitializer, align 4
@char_array = global [8 x i8] zeroinitializer, align 1
+ at short_array = global [4 x i16] zeroinitializer, align 2
@multidim = global [3 x [5 x i32]] zeroinitializer, align 4
@explicit = global [4 x i32] zeroinitializer, align 16
@scalar = global i32 0, align 4
More information about the llvm-commits
mailing list