1 | //===- MCLinkerOptimizationHint.h - LOH interface ---------------*- C++ -*-===// |
2 | // |
3 | // |
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 |
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 <cassert> |
23 | #include <cstdint> |
24 | |
25 | namespace llvm { |
26 | |
27 | class MachObjectWriter; |
28 | class MCAsmLayout; |
29 | class MCSymbol; |
30 | class raw_ostream; |
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(Value: -1); |
64 | #undef MCLOHCaseNameToId |
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(); |
80 | #undef MCLOHCaseIdToName |
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(Elt: 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 |
189 | |