[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