Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 1 | //===- MCLinkerOptimizationHint.h - LOH interface ---------------*- C++ -*-===// |
| 2 | // |
| 3 | // |
Andrew Walbran | 16937d0 | 2019-10-22 13:54:20 +0100 | [diff] [blame] | 4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 5 | // See https://llvm.org/LICENSE.txt for license information. |
| 6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file declares some helpers classes to handle Linker Optimization Hint |
| 11 | // (LOH). |
| 12 | // |
| 13 | // FIXME: LOH interface supports only MachO format at the moment. |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #ifndef LLVM_MC_MCLINKEROPTIMIZATIONHINT_H |
| 17 | #define LLVM_MC_MCLINKEROPTIMIZATIONHINT_H |
| 18 | |
| 19 | #include "llvm/ADT/SmallVector.h" |
| 20 | #include "llvm/ADT/StringRef.h" |
| 21 | #include "llvm/ADT/StringSwitch.h" |
| 22 | #include "llvm/Support/raw_ostream.h" |
| 23 | #include <cassert> |
| 24 | #include <cstdint> |
| 25 | |
| 26 | namespace llvm { |
| 27 | |
| 28 | class MachObjectWriter; |
| 29 | class MCAsmLayout; |
| 30 | class MCSymbol; |
| 31 | |
| 32 | /// Linker Optimization Hint Type. |
| 33 | enum MCLOHType { |
| 34 | MCLOH_AdrpAdrp = 0x1u, ///< Adrp xY, _v1@PAGE -> Adrp xY, _v2@PAGE. |
| 35 | MCLOH_AdrpLdr = 0x2u, ///< Adrp _v@PAGE -> Ldr _v@PAGEOFF. |
| 36 | MCLOH_AdrpAddLdr = 0x3u, ///< Adrp _v@PAGE -> Add _v@PAGEOFF -> Ldr. |
| 37 | MCLOH_AdrpLdrGotLdr = 0x4u, ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF -> Ldr. |
| 38 | MCLOH_AdrpAddStr = 0x5u, ///< Adrp _v@PAGE -> Add _v@PAGEOFF -> Str. |
| 39 | MCLOH_AdrpLdrGotStr = 0x6u, ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF -> Str. |
| 40 | MCLOH_AdrpAdd = 0x7u, ///< Adrp _v@PAGE -> Add _v@PAGEOFF. |
| 41 | MCLOH_AdrpLdrGot = 0x8u ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF. |
| 42 | }; |
| 43 | |
| 44 | static inline StringRef MCLOHDirectiveName() { |
| 45 | return StringRef(".loh"); |
| 46 | } |
| 47 | |
| 48 | static inline bool isValidMCLOHType(unsigned Kind) { |
| 49 | return Kind >= MCLOH_AdrpAdrp && Kind <= MCLOH_AdrpLdrGot; |
| 50 | } |
| 51 | |
| 52 | static inline int MCLOHNameToId(StringRef Name) { |
| 53 | #define MCLOHCaseNameToId(Name) .Case(#Name, MCLOH_ ## Name) |
| 54 | return StringSwitch<int>(Name) |
| 55 | MCLOHCaseNameToId(AdrpAdrp) |
| 56 | MCLOHCaseNameToId(AdrpLdr) |
| 57 | MCLOHCaseNameToId(AdrpAddLdr) |
| 58 | MCLOHCaseNameToId(AdrpLdrGotLdr) |
| 59 | MCLOHCaseNameToId(AdrpAddStr) |
| 60 | MCLOHCaseNameToId(AdrpLdrGotStr) |
| 61 | MCLOHCaseNameToId(AdrpAdd) |
| 62 | MCLOHCaseNameToId(AdrpLdrGot) |
| 63 | .Default(-1); |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 64 | #undef MCLOHCaseNameToId |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | static inline StringRef MCLOHIdToName(MCLOHType Kind) { |
| 68 | #define MCLOHCaseIdToName(Name) case MCLOH_ ## Name: return StringRef(#Name); |
| 69 | switch (Kind) { |
| 70 | MCLOHCaseIdToName(AdrpAdrp); |
| 71 | MCLOHCaseIdToName(AdrpLdr); |
| 72 | MCLOHCaseIdToName(AdrpAddLdr); |
| 73 | MCLOHCaseIdToName(AdrpLdrGotLdr); |
| 74 | MCLOHCaseIdToName(AdrpAddStr); |
| 75 | MCLOHCaseIdToName(AdrpLdrGotStr); |
| 76 | MCLOHCaseIdToName(AdrpAdd); |
| 77 | MCLOHCaseIdToName(AdrpLdrGot); |
| 78 | } |
| 79 | return StringRef(); |
Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 80 | #undef MCLOHCaseIdToName |
Andrew Scull | 5e1ddfa | 2018-08-14 10:06:54 +0100 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | static inline int MCLOHIdToNbArgs(MCLOHType Kind) { |
| 84 | switch (Kind) { |
| 85 | // LOH with two arguments |
| 86 | case MCLOH_AdrpAdrp: |
| 87 | case MCLOH_AdrpLdr: |
| 88 | case MCLOH_AdrpAdd: |
| 89 | case MCLOH_AdrpLdrGot: |
| 90 | return 2; |
| 91 | // LOH with three arguments |
| 92 | case MCLOH_AdrpAddLdr: |
| 93 | case MCLOH_AdrpLdrGotLdr: |
| 94 | case MCLOH_AdrpAddStr: |
| 95 | case MCLOH_AdrpLdrGotStr: |
| 96 | return 3; |
| 97 | } |
| 98 | return -1; |
| 99 | } |
| 100 | |
| 101 | /// Store Linker Optimization Hint information (LOH). |
| 102 | class MCLOHDirective { |
| 103 | MCLOHType Kind; |
| 104 | |
| 105 | /// Arguments of this directive. Order matters. |
| 106 | SmallVector<MCSymbol *, 3> Args; |
| 107 | |
| 108 | /// Emit this directive in \p OutStream using the information available |
| 109 | /// in the given \p ObjWriter and \p Layout to get the address of the |
| 110 | /// arguments within the object file. |
| 111 | void emit_impl(raw_ostream &OutStream, const MachObjectWriter &ObjWriter, |
| 112 | const MCAsmLayout &Layout) const; |
| 113 | |
| 114 | public: |
| 115 | using LOHArgs = SmallVectorImpl<MCSymbol *>; |
| 116 | |
| 117 | MCLOHDirective(MCLOHType Kind, const LOHArgs &Args) |
| 118 | : Kind(Kind), Args(Args.begin(), Args.end()) { |
| 119 | assert(isValidMCLOHType(Kind) && "Invalid LOH directive type!"); |
| 120 | } |
| 121 | |
| 122 | MCLOHType getKind() const { return Kind; } |
| 123 | |
| 124 | const LOHArgs &getArgs() const { return Args; } |
| 125 | |
| 126 | /// Emit this directive as: |
| 127 | /// <kind, numArgs, addr1, ..., addrN> |
| 128 | void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const; |
| 129 | |
| 130 | /// Get the size in bytes of this directive if emitted in \p ObjWriter with |
| 131 | /// the given \p Layout. |
| 132 | uint64_t getEmitSize(const MachObjectWriter &ObjWriter, |
| 133 | const MCAsmLayout &Layout) const; |
| 134 | }; |
| 135 | |
| 136 | class MCLOHContainer { |
| 137 | /// Keep track of the emit size of all the LOHs. |
| 138 | mutable uint64_t EmitSize = 0; |
| 139 | |
| 140 | /// Keep track of all LOH directives. |
| 141 | SmallVector<MCLOHDirective, 32> Directives; |
| 142 | |
| 143 | public: |
| 144 | using LOHDirectives = SmallVectorImpl<MCLOHDirective>; |
| 145 | |
| 146 | MCLOHContainer() = default; |
| 147 | |
| 148 | /// Const accessor to the directives. |
| 149 | const LOHDirectives &getDirectives() const { |
| 150 | return Directives; |
| 151 | } |
| 152 | |
| 153 | /// Add the directive of the given kind \p Kind with the given arguments |
| 154 | /// \p Args to the container. |
| 155 | void addDirective(MCLOHType Kind, const MCLOHDirective::LOHArgs &Args) { |
| 156 | Directives.push_back(MCLOHDirective(Kind, Args)); |
| 157 | } |
| 158 | |
| 159 | /// Get the size of the directives if emitted. |
| 160 | uint64_t getEmitSize(const MachObjectWriter &ObjWriter, |
| 161 | const MCAsmLayout &Layout) const { |
| 162 | if (!EmitSize) { |
| 163 | for (const MCLOHDirective &D : Directives) |
| 164 | EmitSize += D.getEmitSize(ObjWriter, Layout); |
| 165 | } |
| 166 | return EmitSize; |
| 167 | } |
| 168 | |
| 169 | /// Emit all Linker Optimization Hint in one big table. |
| 170 | /// Each line of the table is emitted by LOHDirective::emit. |
| 171 | void emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const { |
| 172 | for (const MCLOHDirective &D : Directives) |
| 173 | D.emit(ObjWriter, Layout); |
| 174 | } |
| 175 | |
| 176 | void reset() { |
| 177 | Directives.clear(); |
| 178 | EmitSize = 0; |
| 179 | } |
| 180 | }; |
| 181 | |
| 182 | // Add types for specialized template using MCSymbol. |
| 183 | using MCLOHArgs = MCLOHDirective::LOHArgs; |
| 184 | using MCLOHDirectives = MCLOHContainer::LOHDirectives; |
| 185 | |
| 186 | } // end namespace llvm |
| 187 | |
| 188 | #endif // LLVM_MC_MCLINKEROPTIMIZATIONHINT_H |