MipsAsmBackend.cpp revision 39ae36337f87b1530c1680ae561c952c827d6e88
1//===-- MipsASMBackend.cpp - Mips Asm Backend  ----------------------------===//
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//===----------------------------------------------------------------------===//
9//
10// This file implements the MipsAsmBackend and MipsELFObjectWriter classes.
11//
12//===----------------------------------------------------------------------===//
13//
14
15#include "MipsFixupKinds.h"
16#include "MCTargetDesc/MipsMCTargetDesc.h"
17#include "llvm/MC/MCAsmBackend.h"
18#include "llvm/MC/MCAssembler.h"
19#include "llvm/MC/MCDirectives.h"
20#include "llvm/MC/MCELFObjectWriter.h"
21#include "llvm/MC/MCFixupKindInfo.h"
22#include "llvm/MC/MCObjectWriter.h"
23#include "llvm/MC/MCSubtargetInfo.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Support/raw_ostream.h"
26
27using namespace llvm;
28
29// Prepare value for the target space for it
30static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
31
32  // Add/subtract and shift
33  switch (Kind) {
34  default:
35    return 0;
36  case FK_GPRel_4:
37  case FK_Data_4:
38  case Mips::fixup_Mips_LO16:
39  case Mips::fixup_Mips_GPOFF_HI:
40  case Mips::fixup_Mips_GPOFF_LO:
41  case Mips::fixup_Mips_GOT_PAGE:
42  case Mips::fixup_Mips_GOT_OFST:
43    break;
44  case Mips::fixup_Mips_PC16:
45    // So far we are only using this type for branches.
46    // For branches we start 1 instruction after the branch
47    // so the displacement will be one instruction size less.
48    Value -= 4;
49    // The displacement is then divided by 4 to give us an 18 bit
50    // address range.
51    Value >>= 2;
52    break;
53  case Mips::fixup_Mips_26:
54    // So far we are only using this type for jumps.
55    // The displacement is then divided by 4 to give us an 28 bit
56    // address range.
57    Value >>= 2;
58    break;
59  case Mips::fixup_Mips_HI16:
60  case Mips::fixup_Mips_GOT_Local:
61    // Get the higher 16-bits. Also add 1 if bit 15 is 1.
62    Value = ((Value + 0x8000) >> 16) & 0xffff;
63    break;
64  }
65
66  return Value;
67}
68
69namespace {
70class MipsAsmBackend : public MCAsmBackend {
71  Triple::OSType OSType;
72  bool IsLittle; // Big or little endian
73  bool Is64Bit;  // 32 or 64 bit words
74
75public:
76  MipsAsmBackend(const Target &T,  Triple::OSType _OSType,
77                 bool _isLittle, bool _is64Bit)
78    :MCAsmBackend(), OSType(_OSType), IsLittle(_isLittle), Is64Bit(_is64Bit) {}
79
80  MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
81    return createMipsELFObjectWriter(OS,
82      MCELFObjectTargetWriter::getOSABI(OSType), IsLittle, Is64Bit);
83  }
84
85  /// ApplyFixup - Apply the \arg Value for given \arg Fixup into the provided
86  /// data fragment, at the offset specified by the fixup and following the
87  /// fixup kind as appropriate.
88  void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
89                  uint64_t Value) const {
90    MCFixupKind Kind = Fixup.getKind();
91    Value = adjustFixupValue((unsigned)Kind, Value);
92
93    if (!Value)
94      return; // Doesn't change encoding.
95
96    // Where do we start in the object
97    unsigned Offset = Fixup.getOffset();
98    // Number of bytes we need to fixup
99    unsigned NumBytes = (getFixupKindInfo(Kind).TargetSize + 7) / 8;
100    // Used to point to big endian bytes
101    unsigned FullSize;
102
103    switch ((unsigned)Kind) {
104    case Mips::fixup_Mips_16:
105      FullSize = 2;
106      break;
107    case Mips::fixup_Mips_64:
108      FullSize = 8;
109      break;
110    default:
111      FullSize = 4;
112      break;
113    }
114
115    // Grab current value, if any, from bits.
116    uint64_t CurVal = 0;
117
118    for (unsigned i = 0; i != NumBytes; ++i) {
119      unsigned Idx = IsLittle ? i : (FullSize - 1 - i);
120      CurVal |= (uint64_t)((uint8_t)Data[Offset + Idx]) << (i*8);
121    }
122
123    uint64_t Mask = ((uint64_t)(-1) >>
124                     (64 - getFixupKindInfo(Kind).TargetSize));
125    CurVal |= Value & Mask;
126
127    // Write out the fixed up bytes back to the code/data bits.
128    for (unsigned i = 0; i != NumBytes; ++i) {
129      unsigned Idx = IsLittle ? i : (FullSize - 1 - i);
130      Data[Offset + Idx] = (uint8_t)((CurVal >> (i*8)) & 0xff);
131    }
132  }
133
134  unsigned getNumFixupKinds() const { return Mips::NumTargetFixupKinds; }
135
136  const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
137    const static MCFixupKindInfo Infos[Mips::NumTargetFixupKinds] = {
138      // This table *must* be in same the order of fixup_* kinds in
139      // MipsFixupKinds.h.
140      //
141      // name                    offset  bits  flags
142      { "fixup_Mips_16",           0,     16,   0 },
143      { "fixup_Mips_32",           0,     32,   0 },
144      { "fixup_Mips_REL32",        0,     32,   0 },
145      { "fixup_Mips_26",           0,     26,   0 },
146      { "fixup_Mips_HI16",         0,     16,   0 },
147      { "fixup_Mips_LO16",         0,     16,   0 },
148      { "fixup_Mips_GPREL16",      0,     16,   0 },
149      { "fixup_Mips_LITERAL",      0,     16,   0 },
150      { "fixup_Mips_GOT_Global",   0,     16,   0 },
151      { "fixup_Mips_GOT_Local",    0,     16,   0 },
152      { "fixup_Mips_PC16",         0,     16,  MCFixupKindInfo::FKF_IsPCRel },
153      { "fixup_Mips_CALL16",       0,     16,   0 },
154      { "fixup_Mips_GPREL32",      0,     32,   0 },
155      { "fixup_Mips_SHIFT5",       6,      5,   0 },
156      { "fixup_Mips_SHIFT6",       6,      5,   0 },
157      { "fixup_Mips_64",           0,     64,   0 },
158      { "fixup_Mips_TLSGD",        0,     16,   0 },
159      { "fixup_Mips_GOTTPREL",     0,     16,   0 },
160      { "fixup_Mips_TPREL_HI",     0,     16,   0 },
161      { "fixup_Mips_TPREL_LO",     0,     16,   0 },
162      { "fixup_Mips_TLSLDM",       0,     16,   0 },
163      { "fixup_Mips_DTPREL_HI",    0,     16,   0 },
164      { "fixup_Mips_DTPREL_LO",    0,     16,   0 },
165      { "fixup_Mips_Branch_PCRel", 0,     16,  MCFixupKindInfo::FKF_IsPCRel },
166      { "fixup_Mips_GPOFF_HI",     0,     16,   0 },
167      { "fixup_Mips_GPOFF_LO",     0,     16,   0 },
168      { "fixup_Mips_GOT_PAGE",     0,     16,   0 },
169      { "fixup_Mips_GOT_OFST",     0,     16,   0 }
170    };
171
172    if (Kind < FirstTargetFixupKind)
173      return MCAsmBackend::getFixupKindInfo(Kind);
174
175    assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
176           "Invalid kind!");
177    return Infos[Kind - FirstTargetFixupKind];
178  }
179
180  /// @name Target Relaxation Interfaces
181  /// @{
182
183  /// MayNeedRelaxation - Check whether the given instruction may need
184  /// relaxation.
185  ///
186  /// \param Inst - The instruction to test.
187  bool mayNeedRelaxation(const MCInst &Inst) const {
188    return false;
189  }
190
191  /// fixupNeedsRelaxation - Target specific predicate for whether a given
192  /// fixup requires the associated instruction to be relaxed.
193  bool fixupNeedsRelaxation(const MCFixup &Fixup,
194                            uint64_t Value,
195                            const MCInstFragment *DF,
196                            const MCAsmLayout &Layout) const {
197    // FIXME.
198    assert(0 && "RelaxInstruction() unimplemented");
199    return false;
200  }
201
202  /// RelaxInstruction - Relax the instruction in the given fragment
203  /// to the next wider instruction.
204  ///
205  /// \param Inst - The instruction to relax, which may be the same
206  /// as the output.
207  /// \parm Res [output] - On return, the relaxed instruction.
208  void relaxInstruction(const MCInst &Inst, MCInst &Res) const {
209  }
210
211  /// @}
212
213  /// WriteNopData - Write an (optimal) nop sequence of Count bytes
214  /// to the given output. If the target cannot generate such a sequence,
215  /// it should return an error.
216  ///
217  /// \return - True on success.
218  bool writeNopData(uint64_t Count, MCObjectWriter *OW) const {
219    return true;
220  }
221}; // class MipsAsmBackend
222
223} // namespace
224
225// MCAsmBackend
226MCAsmBackend *llvm::createMipsAsmBackendEL32(const Target &T, StringRef TT) {
227  return new MipsAsmBackend(T, Triple(TT).getOS(),
228                            /*IsLittle*/true, /*Is64Bit*/false);
229}
230
231MCAsmBackend *llvm::createMipsAsmBackendEB32(const Target &T, StringRef TT) {
232  return new MipsAsmBackend(T, Triple(TT).getOS(),
233                            /*IsLittle*/false, /*Is64Bit*/false);
234}
235
236MCAsmBackend *llvm::createMipsAsmBackendEL64(const Target &T, StringRef TT) {
237  return new MipsAsmBackend(T, Triple(TT).getOS(),
238                            /*IsLittle*/true, /*Is64Bit*/true);
239}
240
241MCAsmBackend *llvm::createMipsAsmBackendEB64(const Target &T, StringRef TT) {
242  return new MipsAsmBackend(T, Triple(TT).getOS(),
243                            /*IsLittle*/false, /*Is64Bit*/true);
244}
245
246