| 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 | |
| 30 | using namespace llvm; |
| 31 | |
| 32 | #define DEBUG_TYPE "hexagon-global-array-alignment" |
| 33 | |
| 34 | static 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 | |
| 39 | static 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 | |
| 45 | namespace { |
| 46 | |
| 47 | class HexagonAlignGlobalArrays : public ModulePass { |
| 48 | bool ReduceRodataSize; |
| 49 | |
| 50 | public: |
| 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 | |
| 65 | char HexagonAlignGlobalArrays::ID = 0; |
| 66 | |
| 67 | INITIALIZE_PASS(HexagonAlignGlobalArrays, "hexagon-global-array-alignment" , |
| 68 | "Align Global Arrays to 8-byte" , false, false) |
| 69 | |
| 70 | ModulePass *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. |
| 76 | static 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 | |
| 84 | bool 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 | |