aboutsummaryrefslogtreecommitdiffstats
path: root/include/llvm/MC/MCLinkerOptimizationHint.h
blob: 890d6385aacde34ce3cd369018f283fe5e171554 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//===- MCLinkerOptimizationHint.h - LOH interface ---------------*- C++ -*-===//
//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares some helpers classes to handle Linker Optimization Hint
// (LOH).
//
// FIXME: LOH interface supports only MachO format at the moment.
//===----------------------------------------------------------------------===//

#ifndef LLVM_MC_MCLINKEROPTIMIZATIONHINT_H
#define LLVM_MC_MCLINKEROPTIMIZATIONHINT_H

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCMachObjectWriter.h"
#include "llvm/Support/raw_ostream.h"

namespace llvm {

// Forward declarations.
class MCAsmLayout;
class MCSymbol;

/// Linker Optimization Hint Type.
enum MCLOHType {
  MCLOH_AdrpAdrp = 0x1u,      ///< Adrp xY, _v1@PAGE -> Adrp xY, _v2@PAGE.
  MCLOH_AdrpLdr = 0x2u,       ///< Adrp _v@PAGE -> Ldr _v@PAGEOFF.
  MCLOH_AdrpAddLdr = 0x3u,    ///< Adrp _v@PAGE -> Add _v@PAGEOFF -> Ldr.
  MCLOH_AdrpLdrGotLdr = 0x4u, ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF -> Ldr.
  MCLOH_AdrpAddStr = 0x5u,    ///< Adrp _v@PAGE -> Add _v@PAGEOFF -> Str.
  MCLOH_AdrpLdrGotStr = 0x6u, ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF -> Str.
  MCLOH_AdrpAdd = 0x7u,       ///< Adrp _v@PAGE -> Add _v@PAGEOFF.
  MCLOH_AdrpLdrGot = 0x8u     ///< Adrp _v@GOTPAGE -> Ldr _v@GOTPAGEOFF.
};

static inline StringRef MCLOHDirectiveName() {
  return StringRef(".loh");
}

static inline bool isValidMCLOHType(unsigned Kind) {
  return Kind >= MCLOH_AdrpAdrp && Kind <= MCLOH_AdrpLdrGot;
}

static inline int MCLOHNameToId(StringRef Name) {
#define MCLOHCaseNameToId(Name)     .Case(#Name, MCLOH_ ## Name)
  return StringSwitch<int>(Name)
    MCLOHCaseNameToId(AdrpAdrp)
    MCLOHCaseNameToId(AdrpLdr)
    MCLOHCaseNameToId(AdrpAddLdr)
    MCLOHCaseNameToId(AdrpLdrGotLdr)
    MCLOHCaseNameToId(AdrpAddStr)
    MCLOHCaseNameToId(AdrpLdrGotStr)
    MCLOHCaseNameToId(AdrpAdd)
    MCLOHCaseNameToId(AdrpLdrGot)
    .Default(-1);
}

static inline StringRef MCLOHIdToName(MCLOHType Kind) {
#define MCLOHCaseIdToName(Name)      case MCLOH_ ## Name: return StringRef(#Name);
  switch (Kind) {
    MCLOHCaseIdToName(AdrpAdrp);
    MCLOHCaseIdToName(AdrpLdr);
    MCLOHCaseIdToName(AdrpAddLdr);
    MCLOHCaseIdToName(AdrpLdrGotLdr);
    MCLOHCaseIdToName(AdrpAddStr);
    MCLOHCaseIdToName(AdrpLdrGotStr);
    MCLOHCaseIdToName(AdrpAdd);
    MCLOHCaseIdToName(AdrpLdrGot);
  }
  return StringRef();
}

static inline int MCLOHIdToNbArgs(MCLOHType Kind) {
  switch (Kind) {
    // LOH with two arguments
  case MCLOH_AdrpAdrp:
  case MCLOH_AdrpLdr:
  case MCLOH_AdrpAdd:
  case MCLOH_AdrpLdrGot:
    return 2;
    // LOH with three arguments
  case MCLOH_AdrpAddLdr:
  case MCLOH_AdrpLdrGotLdr:
  case MCLOH_AdrpAddStr:
  case MCLOH_AdrpLdrGotStr:
    return 3;
  }
  return -1;
}

/// Store Linker Optimization Hint information (LOH).
class MCLOHDirective {
  MCLOHType Kind;

  /// Arguments of this directive. Order matters.
  SmallVector<MCSymbol *, 3> Args;

  /// Emit this directive in @p OutStream using the information available
  /// in the given @p ObjWriter and @p Layout to get the address of the
  /// arguments within the object file.
  void Emit_impl(raw_ostream &OutStream, const MachObjectWriter &ObjWriter,
                 const MCAsmLayout &Layout) const;

public:
  typedef SmallVectorImpl<MCSymbol *> LOHArgs;

  MCLOHDirective(MCLOHType Kind, const LOHArgs &Args)
      : Kind(Kind), Args(Args.begin(), Args.end()) {
    assert(isValidMCLOHType(Kind) && "Invalid LOH directive type!");
  }

  MCLOHType getKind() const { return Kind; }

  const LOHArgs &getArgs() const { return Args; }

  /// Emit this directive as:
  /// <kind, numArgs, addr1, ..., addrN>
  void Emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const {
    raw_ostream &OutStream = ObjWriter.getStream();
    Emit_impl(OutStream, ObjWriter, Layout);
  }

  /// Get the size in bytes of this directive if emitted in @p ObjWriter with
  /// the given @p Layout.
  uint64_t getEmitSize(const MachObjectWriter &ObjWriter,
                       const MCAsmLayout &Layout) const {
    class raw_counting_ostream : public raw_ostream {
      uint64_t Count;

      void write_impl(const char *, size_t size) override { Count += size; }

      uint64_t current_pos() const override { return Count; }

    public:
      raw_counting_ostream() : Count(0) {}
      ~raw_counting_ostream() { flush(); }
    };

    raw_counting_ostream OutStream;
    Emit_impl(OutStream, ObjWriter, Layout);
    return OutStream.tell();
  }
};

class MCLOHContainer {
  /// Keep track of the emit size of all the LOHs.
  mutable uint64_t EmitSize;

  /// Keep track of all LOH directives.
  SmallVector<MCLOHDirective, 32> Directives;

public:
  typedef SmallVectorImpl<MCLOHDirective> LOHDirectives;

  MCLOHContainer() : EmitSize(0) {};

  /// Const accessor to the directives.
  const LOHDirectives &getDirectives() const {
    return Directives;
  }

  /// Add the directive of the given kind @p Kind with the given arguments
  /// @p Args to the container.
  void addDirective(MCLOHType Kind, const MCLOHDirective::LOHArgs &Args) {
    Directives.push_back(MCLOHDirective(Kind, Args));
  }

  /// Get the size of the directives if emitted.
  uint64_t getEmitSize(const MachObjectWriter &ObjWriter,
                       const MCAsmLayout &Layout) const {
    if (!EmitSize) {
      for (const MCLOHDirective &D : Directives)
        EmitSize += D.getEmitSize(ObjWriter, Layout);
    }
    return EmitSize;
  }

  /// Emit all Linker Optimization Hint in one big table.
  /// Each line of the table is emitted by LOHDirective::Emit.
  void Emit(MachObjectWriter &ObjWriter, const MCAsmLayout &Layout) const {
    for (const MCLOHDirective &D : Directives)
      D.Emit(ObjWriter, Layout);
  }

  void reset() {
    Directives.clear();
    EmitSize = 0;
  }
};

// Add types for specialized template using MCSymbol.
typedef MCLOHDirective::LOHArgs MCLOHArgs;
typedef MCLOHContainer::LOHDirectives MCLOHDirectives;

} // end namespace llvm

#endif