Use BranchProbability instead of floating points in IfConverter.
[llvm/stm8.git] / lib / Target / ARM / ARMMachObjectWriter.cpp
bloba36e47da06d4d941a96844d2cf71d4610c654a36
1 //===-- ARMMachObjectWriter.cpp - ARM Mach Object Writer ------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
10 #include "ARM.h"
11 #include "ARMFixupKinds.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAssembler.h"
14 #include "llvm/MC/MCAsmLayout.h"
15 #include "llvm/MC/MCMachObjectWriter.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCFixup.h"
18 #include "llvm/MC/MCFixupKindInfo.h"
19 #include "llvm/MC/MCValue.h"
20 #include "llvm/Object/MachOFormat.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Target/TargetAsmBackend.h"
23 using namespace llvm;
24 using namespace llvm::object;
26 namespace {
27 class ARMMachObjectWriter : public MCMachObjectTargetWriter {
28 void RecordARMScatteredRelocation(MachObjectWriter *Writer,
29 const MCAssembler &Asm,
30 const MCAsmLayout &Layout,
31 const MCFragment *Fragment,
32 const MCFixup &Fixup,
33 MCValue Target,
34 unsigned Log2Size,
35 uint64_t &FixedValue);
36 void RecordARMMovwMovtRelocation(MachObjectWriter *Writer,
37 const MCAssembler &Asm,
38 const MCAsmLayout &Layout,
39 const MCFragment *Fragment,
40 const MCFixup &Fixup, MCValue Target,
41 uint64_t &FixedValue);
43 public:
44 ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
45 uint32_t CPUSubtype)
46 : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype,
47 /*UseAggressiveSymbolFolding=*/true) {}
49 void RecordRelocation(MachObjectWriter *Writer,
50 const MCAssembler &Asm, const MCAsmLayout &Layout,
51 const MCFragment *Fragment, const MCFixup &Fixup,
52 MCValue Target, uint64_t &FixedValue);
56 static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
57 unsigned &Log2Size) {
58 RelocType = unsigned(macho::RIT_Vanilla);
59 Log2Size = ~0U;
61 switch (Kind) {
62 default:
63 return false;
65 case FK_Data_1:
66 Log2Size = llvm::Log2_32(1);
67 return true;
68 case FK_Data_2:
69 Log2Size = llvm::Log2_32(2);
70 return true;
71 case FK_Data_4:
72 Log2Size = llvm::Log2_32(4);
73 return true;
74 case FK_Data_8:
75 Log2Size = llvm::Log2_32(8);
76 return true;
78 // Handle 24-bit branch kinds.
79 case ARM::fixup_arm_ldst_pcrel_12:
80 case ARM::fixup_arm_pcrel_10:
81 case ARM::fixup_arm_adr_pcrel_12:
82 case ARM::fixup_arm_condbranch:
83 case ARM::fixup_arm_uncondbranch:
84 RelocType = unsigned(macho::RIT_ARM_Branch24Bit);
85 // Report as 'long', even though that is not quite accurate.
86 Log2Size = llvm::Log2_32(4);
87 return true;
89 // Handle Thumb branches.
90 case ARM::fixup_arm_thumb_br:
91 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
92 Log2Size = llvm::Log2_32(2);
93 return true;
95 case ARM::fixup_t2_uncondbranch:
96 case ARM::fixup_arm_thumb_bl:
97 case ARM::fixup_arm_thumb_blx:
98 RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit);
99 Log2Size = llvm::Log2_32(4);
100 return true;
102 case ARM::fixup_arm_movt_hi16:
103 case ARM::fixup_arm_movt_hi16_pcrel:
104 case ARM::fixup_t2_movt_hi16:
105 case ARM::fixup_t2_movt_hi16_pcrel:
106 RelocType = unsigned(macho::RIT_ARM_HalfDifference);
107 // Report as 'long', even though that is not quite accurate.
108 Log2Size = llvm::Log2_32(4);
109 return true;
111 case ARM::fixup_arm_movw_lo16:
112 case ARM::fixup_arm_movw_lo16_pcrel:
113 case ARM::fixup_t2_movw_lo16:
114 case ARM::fixup_t2_movw_lo16_pcrel:
115 RelocType = unsigned(macho::RIT_ARM_Half);
116 // Report as 'long', even though that is not quite accurate.
117 Log2Size = llvm::Log2_32(4);
118 return true;
122 void ARMMachObjectWriter::
123 RecordARMMovwMovtRelocation(MachObjectWriter *Writer,
124 const MCAssembler &Asm,
125 const MCAsmLayout &Layout,
126 const MCFragment *Fragment,
127 const MCFixup &Fixup,
128 MCValue Target,
129 uint64_t &FixedValue) {
130 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
131 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
132 unsigned Type = macho::RIT_ARM_Half;
134 // See <reloc.h>.
135 const MCSymbol *A = &Target.getSymA()->getSymbol();
136 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
138 if (!A_SD->getFragment())
139 report_fatal_error("symbol '" + A->getName() +
140 "' can not be undefined in a subtraction expression");
142 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
143 uint32_t Value2 = 0;
144 uint64_t SecAddr =
145 Writer->getSectionAddress(A_SD->getFragment()->getParent());
146 FixedValue += SecAddr;
148 if (const MCSymbolRefExpr *B = Target.getSymB()) {
149 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
151 if (!B_SD->getFragment())
152 report_fatal_error("symbol '" + B->getSymbol().getName() +
153 "' can not be undefined in a subtraction expression");
155 // Select the appropriate difference relocation type.
156 Type = macho::RIT_ARM_HalfDifference;
157 Value2 = Writer->getSymbolAddress(B_SD, Layout);
158 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
161 // Relocations are written out in reverse order, so the PAIR comes first.
162 // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field:
164 // For these two r_type relocations they always have a pair following them and
165 // the r_length bits are used differently. The encoding of the r_length is as
166 // follows:
167 // low bit of r_length:
168 // 0 - :lower16: for movw instructions
169 // 1 - :upper16: for movt instructions
170 // high bit of r_length:
171 // 0 - arm instructions
172 // 1 - thumb instructions
173 // the other half of the relocated expression is in the following pair
174 // relocation entry in the the low 16 bits of r_address field.
175 unsigned ThumbBit = 0;
176 unsigned MovtBit = 0;
177 switch ((unsigned)Fixup.getKind()) {
178 default: break;
179 case ARM::fixup_arm_movt_hi16:
180 case ARM::fixup_arm_movt_hi16_pcrel:
181 MovtBit = 1;
182 break;
183 case ARM::fixup_t2_movt_hi16:
184 case ARM::fixup_t2_movt_hi16_pcrel:
185 MovtBit = 1;
186 // Fallthrough
187 case ARM::fixup_t2_movw_lo16:
188 case ARM::fixup_t2_movw_lo16_pcrel:
189 ThumbBit = 1;
190 break;
194 if (Type == macho::RIT_ARM_HalfDifference) {
195 uint32_t OtherHalf = MovtBit
196 ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16);
198 macho::RelocationEntry MRE;
199 MRE.Word0 = ((OtherHalf << 0) |
200 (macho::RIT_Pair << 24) |
201 (MovtBit << 28) |
202 (ThumbBit << 29) |
203 (IsPCRel << 30) |
204 macho::RF_Scattered);
205 MRE.Word1 = Value2;
206 Writer->addRelocation(Fragment->getParent(), MRE);
209 macho::RelocationEntry MRE;
210 MRE.Word0 = ((FixupOffset << 0) |
211 (Type << 24) |
212 (MovtBit << 28) |
213 (ThumbBit << 29) |
214 (IsPCRel << 30) |
215 macho::RF_Scattered);
216 MRE.Word1 = Value;
217 Writer->addRelocation(Fragment->getParent(), MRE);
220 void ARMMachObjectWriter::RecordARMScatteredRelocation(MachObjectWriter *Writer,
221 const MCAssembler &Asm,
222 const MCAsmLayout &Layout,
223 const MCFragment *Fragment,
224 const MCFixup &Fixup,
225 MCValue Target,
226 unsigned Log2Size,
227 uint64_t &FixedValue) {
228 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
229 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
230 unsigned Type = macho::RIT_Vanilla;
232 // See <reloc.h>.
233 const MCSymbol *A = &Target.getSymA()->getSymbol();
234 MCSymbolData *A_SD = &Asm.getSymbolData(*A);
236 if (!A_SD->getFragment())
237 report_fatal_error("symbol '" + A->getName() +
238 "' can not be undefined in a subtraction expression");
240 uint32_t Value = Writer->getSymbolAddress(A_SD, Layout);
241 uint64_t SecAddr = Writer->getSectionAddress(A_SD->getFragment()->getParent());
242 FixedValue += SecAddr;
243 uint32_t Value2 = 0;
245 if (const MCSymbolRefExpr *B = Target.getSymB()) {
246 MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol());
248 if (!B_SD->getFragment())
249 report_fatal_error("symbol '" + B->getSymbol().getName() +
250 "' can not be undefined in a subtraction expression");
252 // Select the appropriate difference relocation type.
253 Type = macho::RIT_Difference;
254 Value2 = Writer->getSymbolAddress(B_SD, Layout);
255 FixedValue -= Writer->getSectionAddress(B_SD->getFragment()->getParent());
258 // Relocations are written out in reverse order, so the PAIR comes first.
259 if (Type == macho::RIT_Difference ||
260 Type == macho::RIT_Generic_LocalDifference) {
261 macho::RelocationEntry MRE;
262 MRE.Word0 = ((0 << 0) |
263 (macho::RIT_Pair << 24) |
264 (Log2Size << 28) |
265 (IsPCRel << 30) |
266 macho::RF_Scattered);
267 MRE.Word1 = Value2;
268 Writer->addRelocation(Fragment->getParent(), MRE);
271 macho::RelocationEntry MRE;
272 MRE.Word0 = ((FixupOffset << 0) |
273 (Type << 24) |
274 (Log2Size << 28) |
275 (IsPCRel << 30) |
276 macho::RF_Scattered);
277 MRE.Word1 = Value;
278 Writer->addRelocation(Fragment->getParent(), MRE);
281 void ARMMachObjectWriter::RecordRelocation(MachObjectWriter *Writer,
282 const MCAssembler &Asm,
283 const MCAsmLayout &Layout,
284 const MCFragment *Fragment,
285 const MCFixup &Fixup,
286 MCValue Target,
287 uint64_t &FixedValue) {
288 unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
289 unsigned Log2Size;
290 unsigned RelocType = macho::RIT_Vanilla;
291 if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) {
292 report_fatal_error("unknown ARM fixup kind!");
293 return;
296 // If this is a difference or a defined symbol plus an offset, then we need a
297 // scattered relocation entry. Differences always require scattered
298 // relocations.
299 if (Target.getSymB()) {
300 if (RelocType == macho::RIT_ARM_Half ||
301 RelocType == macho::RIT_ARM_HalfDifference)
302 return RecordARMMovwMovtRelocation(Writer, Asm, Layout, Fragment, Fixup,
303 Target, FixedValue);
304 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
305 Target, Log2Size, FixedValue);
308 // Get the symbol data, if any.
309 MCSymbolData *SD = 0;
310 if (Target.getSymA())
311 SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
313 // FIXME: For other platforms, we need to use scattered relocations for
314 // internal relocations with offsets. If this is an internal relocation with
315 // an offset, it also needs a scattered relocation entry.
317 // Is this right for ARM?
318 uint32_t Offset = Target.getConstant();
319 if (IsPCRel && RelocType == macho::RIT_Vanilla)
320 Offset += 1 << Log2Size;
321 if (Offset && SD && !Writer->doesSymbolRequireExternRelocation(SD))
322 return RecordARMScatteredRelocation(Writer, Asm, Layout, Fragment, Fixup,
323 Target, Log2Size, FixedValue);
325 // See <reloc.h>.
326 uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
327 unsigned Index = 0;
328 unsigned IsExtern = 0;
329 unsigned Type = 0;
331 if (Target.isAbsolute()) { // constant
332 // FIXME!
333 report_fatal_error("FIXME: relocations to absolute targets "
334 "not yet implemented");
335 } else {
336 // Resolve constant variables.
337 if (SD->getSymbol().isVariable()) {
338 int64_t Res;
339 if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
340 Res, Layout, Writer->getSectionAddressMap())) {
341 FixedValue = Res;
342 return;
346 // Check whether we need an external or internal relocation.
347 if (Writer->doesSymbolRequireExternRelocation(SD)) {
348 IsExtern = 1;
349 Index = SD->getIndex();
351 // For external relocations, make sure to offset the fixup value to
352 // compensate for the addend of the symbol address, if it was
353 // undefined. This occurs with weak definitions, for example.
354 if (!SD->Symbol->isUndefined())
355 FixedValue -= Layout.getSymbolOffset(SD);
356 } else {
357 // The index is the section ordinal (1-based).
358 const MCSectionData &SymSD = Asm.getSectionData(
359 SD->getSymbol().getSection());
360 Index = SymSD.getOrdinal() + 1;
361 FixedValue += Writer->getSectionAddress(&SymSD);
363 if (IsPCRel)
364 FixedValue -= Writer->getSectionAddress(Fragment->getParent());
366 // The type is determined by the fixup kind.
367 Type = RelocType;
370 // struct relocation_info (8 bytes)
371 macho::RelocationEntry MRE;
372 MRE.Word0 = FixupOffset;
373 MRE.Word1 = ((Index << 0) |
374 (IsPCRel << 24) |
375 (Log2Size << 25) |
376 (IsExtern << 27) |
377 (Type << 28));
378 Writer->addRelocation(Fragment->getParent(), MRE);
381 MCObjectWriter *llvm::createARMMachObjectWriter(raw_ostream &OS,
382 bool Is64Bit,
383 uint32_t CPUType,
384 uint32_t CPUSubtype) {
385 return createMachObjectWriter(new ARMMachObjectWriter(Is64Bit,
386 CPUType,
387 CPUSubtype),
388 OS, /*IsLittleEndian=*/true);