1//===- HexagonAlignGlobalArrays.cpp - Align Global Arrays -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass increases the alignment of global integer arrays (char, short,
10// int), including multi-dimensional arrays, to an 8-byte boundary. This gives
11// their base address a wider alignment, which is beneficial for the wide
12// (double-word) loads and stores available on Hexagon.
13//
14// When optimizing to reduce .rodata size, byte and half-word arrays already at
15// an alignment of two bytes or less are left at their natural alignment; only
16// word arrays are promoted. This size behavior can be turned off with
17// -hexagon-disable-align-opt-byte-half.
18//
19// The pass is enabled by default and can be disabled with
20// -hexagon-disable-global-array-align.
21//
22//===----------------------------------------------------------------------===//
23
24#include "Hexagon.h"
25#include "llvm/IR/Module.h"
26#include "llvm/Pass.h"
27#include "llvm/Support/CommandLine.h"
28#include "llvm/Support/Debug.h"
29
30using namespace llvm;
31
32#define DEBUG_TYPE "hexagon-global-array-alignment"
33
34static cl::opt<bool> DisableGlobalArrayAlignment(
35 "hexagon-disable-global-array-align",
36 cl::desc("Disable aligning global integer arrays to an 8-byte boundary"),
37 cl::init(Val: false), cl::Hidden);
38
39static cl::opt<bool> DisableHexAlignOptByteHalf(
40 "hexagon-disable-align-opt-byte-half",
41 cl::desc("Disable keeping byte and half-word arrays at their natural "
42 "alignment when reducing .rodata size"),
43 cl::Hidden);
44
45namespace {
46
47class HexagonAlignGlobalArrays : public ModulePass {
48 bool ReduceRodataSize;
49
50public:
51 static char ID;
52
53 explicit HexagonAlignGlobalArrays(bool ReduceRodataSize = false)
54 : ModulePass(ID), ReduceRodataSize(ReduceRodataSize) {}
55
56 StringRef getPassName() const override {
57 return "Hexagon Global Array Alignment";
58 }
59
60 bool runOnModule(Module &M) override;
61};
62
63} // end anonymous namespace
64
65char HexagonAlignGlobalArrays::ID = 0;
66
67INITIALIZE_PASS(HexagonAlignGlobalArrays, "hexagon-global-array-alignment",
68 "Align Global Arrays to 8-byte", false, false)
69
70ModulePass *llvm::createHexagonAlignGlobalArrays(bool ReduceRodataSize) {
71 return new HexagonAlignGlobalArrays(ReduceRodataSize);
72}
73
74// Get the underlying element type of an array. This is useful if the array is
75// multi-dimensional.
76static Type *getUnderlyingArrayElmTy(Type *Ty) {
77 // Ty is guaranteed to be an array type.
78 Type *ElTy = cast<ArrayType>(Val: Ty)->getElementType();
79 while (ElTy->isArrayTy())
80 ElTy = cast<ArrayType>(Val: ElTy)->getElementType();
81 return ElTy;
82}
83
84bool HexagonAlignGlobalArrays::runOnModule(Module &M) {
85 if (DisableGlobalArrayAlignment)
86 return false;
87
88 bool Changed = false;
89 const DataLayout &DL = M.getDataLayout();
90
91 for (GlobalVariable &GV : M.globals()) {
92 Type *VT = GV.getValueType();
93 if (!VT->isArrayTy())
94 continue;
95
96 Type *ElTy = getUnderlyingArrayElmTy(Ty: VT);
97 if (!ElTy->isIntegerTy())
98 continue;
99
100 // Skip globals whose alignment cannot be safely raised, e.g. declarations,
101 // weak/interposable definitions, and section-pinned globals.
102 if (!GV.canIncreaseAlignment())
103 continue;
104
105 // Compute the current alignment, falling back to the ABI alignment.
106 MaybeAlign GVAlign = GV.getAlign();
107 if (!GVAlign && VT->isSized())
108 GVAlign = DL.getABITypeAlign(Ty: VT);
109
110 // Align integer arrays to an 8-byte boundary. When reducing .rodata size,
111 // leave byte and half-word arrays that are already at an alignment of two
112 // bytes or less at their natural alignment; word arrays are still promoted.
113 if (!ReduceRodataSize || !GVAlign || *GVAlign > Align(2) ||
114 DisableHexAlignOptByteHalf) {
115 MaybeAlign NewAlign = std::max(a: GVAlign.valueOrOne(), b: Align(8));
116 if (NewAlign != GVAlign) {
117 GV.setAlignment(NewAlign);
118 Changed = true;
119 LLVM_DEBUG(dbgs() << GV << '\n');
120 }
121 }
122 }
123
124 return Changed;
125}
126