Add a few moreLocal/Global R_MIPS_GOT related fixups and
[oota-llvm.git] / lib / Target / Mips / MCTargetDesc / MipsMCCodeEmitter.cpp
1 //===-- MipsMCCodeEmitter.cpp - Convert Mips code to machine code ---------===//
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 MipsMCCodeEmitter class.
11 //
12 //===----------------------------------------------------------------------===//
13 //
14 #define DEBUG_TYPE "mccodeemitter"
15 #include "MCTargetDesc/MipsBaseInfo.h"
16 #include "MCTargetDesc/MipsFixupKinds.h"
17 #include "MCTargetDesc/MipsMCTargetDesc.h"
18 #include "llvm/ADT/APFloat.h"
19 #include "llvm/ADT/Statistic.h"
20 #include "llvm/MC/MCCodeEmitter.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrInfo.h"
24 #include "llvm/MC/MCRegisterInfo.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/Support/raw_ostream.h"
27
28 using namespace llvm;
29
30 namespace {
31 class MipsMCCodeEmitter : public MCCodeEmitter {
32   MipsMCCodeEmitter(const MipsMCCodeEmitter &); // DO NOT IMPLEMENT
33   void operator=(const MipsMCCodeEmitter &); // DO NOT IMPLEMENT
34   const MCInstrInfo &MCII;
35   const MCSubtargetInfo &STI;
36   MCContext &Ctx;
37
38 public:
39   MipsMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti,
40                     MCContext &ctx) : MCII(mcii), STI(sti) , Ctx(ctx) {}
41
42   ~MipsMCCodeEmitter() {}
43
44   void EmitByte(unsigned char C, raw_ostream &OS) const {
45     OS << (char)C;
46   }
47
48   void EmitInstruction(uint64_t Val, unsigned Size, raw_ostream &OS) const {
49     // Output the instruction encoding in little endian byte order.
50     for (unsigned i = 0; i != Size; ++i) {
51       EmitByte(Val & 255, OS);
52       Val >>= 8;
53     }
54   }
55
56   void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
57                          SmallVectorImpl<MCFixup> &Fixups) const;
58
59   // getBinaryCodeForInstr - TableGen'erated function for getting the
60   // binary encoding for an instruction.
61   unsigned getBinaryCodeForInstr(const MCInst &MI,
62                                  SmallVectorImpl<MCFixup> &Fixups) const;
63
64   // getBranchJumpOpValue - Return binary encoding of the jump
65   // target operand. If the machine operand requires relocation,
66   // record the relocation and return zero.
67    unsigned getJumpTargetOpValue(const MCInst &MI, unsigned OpNo,
68                                  SmallVectorImpl<MCFixup> &Fixups) const;
69
70    // getBranchTargetOpValue - Return binary encoding of the branch
71    // target operand. If the machine operand requires relocation,
72    // record the relocation and return zero.
73   unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
74                                   SmallVectorImpl<MCFixup> &Fixups) const;
75
76    // getMachineOpValue - Return binary encoding of operand. If the machin
77    // operand requires relocation, record the relocation and return zero.
78   unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO,
79                              SmallVectorImpl<MCFixup> &Fixups) const;
80
81   unsigned getMemEncoding(const MCInst &MI, unsigned OpNo,
82                           SmallVectorImpl<MCFixup> &Fixups) const;
83   unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo,
84                               SmallVectorImpl<MCFixup> &Fixups) const;
85   unsigned getSizeInsEncoding(const MCInst &MI, unsigned OpNo,
86                               SmallVectorImpl<MCFixup> &Fixups) const;
87
88 }; // class MipsMCCodeEmitter
89 }  // namespace
90
91 MCCodeEmitter *llvm::createMipsMCCodeEmitter(const MCInstrInfo &MCII,
92                                              const MCSubtargetInfo &STI,
93                                              MCContext &Ctx)
94 {
95   return new MipsMCCodeEmitter(MCII, STI, Ctx);
96 }
97
98 /// EncodeInstruction - Emit the instruction.
99 /// Size the instruction (currently only 4 bytes
100 void MipsMCCodeEmitter::
101 EncodeInstruction(const MCInst &MI, raw_ostream &OS,
102                   SmallVectorImpl<MCFixup> &Fixups) const
103 {
104   uint32_t Binary = getBinaryCodeForInstr(MI, Fixups);
105
106   // Check for unimplemented opcodes.
107   // Unfortunately in MIPS both NOT and SLL will come in with Binary == 0
108   // so we have to special check for them.
109   unsigned Opcode = MI.getOpcode();
110   if ((Opcode != Mips::NOP) && (Opcode != Mips::SLL) && !Binary)
111     llvm_unreachable("unimplemented opcode in EncodeInstruction()");
112
113   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
114   uint64_t TSFlags = Desc.TSFlags;
115
116   // Pseudo instructions don't get encoded and shouldn't be here
117   // in the first place!
118   if ((TSFlags & MipsII::FormMask) == MipsII::Pseudo)
119     llvm_unreachable("Pseudo opcode found in EncodeInstruction()");
120
121   // For now all instructions are 4 bytes
122   int Size = 4; // FIXME: Have Desc.getSize() return the correct value!
123
124   EmitInstruction(Binary, Size, OS);
125 }
126
127 /// getBranchTargetOpValue - Return binary encoding of the branch
128 /// target operand. If the machine operand requires relocation,
129 /// record the relocation and return zero.
130 unsigned MipsMCCodeEmitter::
131 getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
132                        SmallVectorImpl<MCFixup> &Fixups) const {
133
134   const MCOperand &MO = MI.getOperand(OpNo);
135   assert(MO.isExpr() && "getBranchTargetOpValue expects only expressions");
136
137   const MCExpr *Expr = MO.getExpr();
138   Fixups.push_back(MCFixup::Create(0, Expr,
139                                    MCFixupKind(Mips::fixup_Mips_PC16)));
140   return 0;
141 }
142
143 /// getJumpTargetOpValue - Return binary encoding of the jump
144 /// target operand. If the machine operand requires relocation,
145 /// record the relocation and return zero.
146 unsigned MipsMCCodeEmitter::
147 getJumpTargetOpValue(const MCInst &MI, unsigned OpNo,
148                      SmallVectorImpl<MCFixup> &Fixups) const {
149
150   const MCOperand &MO = MI.getOperand(OpNo);
151   assert(MO.isExpr() && "getJumpTargetOpValue expects only expressions");
152
153   const MCExpr *Expr = MO.getExpr();
154   Fixups.push_back(MCFixup::Create(0, Expr,
155                                    MCFixupKind(Mips::fixup_Mips_26)));
156   return 0;
157 }
158
159 /// getMachineOpValue - Return binary encoding of operand. If the machine
160 /// operand requires relocation, record the relocation and return zero.
161 unsigned MipsMCCodeEmitter::
162 getMachineOpValue(const MCInst &MI, const MCOperand &MO,
163                   SmallVectorImpl<MCFixup> &Fixups) const {
164   if (MO.isReg()) {
165     unsigned Reg = MO.getReg();
166     unsigned RegNo = getMipsRegisterNumbering(Reg);
167     return RegNo;
168   } else if (MO.isImm()) {
169     return static_cast<unsigned>(MO.getImm());
170   } else if (MO.isFPImm()) {
171     return static_cast<unsigned>(APFloat(MO.getFPImm())
172         .bitcastToAPInt().getHiBits(32).getLimitedValue());
173   } else if (MO.isExpr()) {
174     const MCExpr *Expr = MO.getExpr();
175     MCExpr::ExprKind Kind = Expr->getKind();
176     unsigned Ret = 0;
177
178     if (Kind == MCExpr::Binary) {
179       const MCBinaryExpr *BE = static_cast<const MCBinaryExpr*>(Expr);
180       Expr = BE->getLHS();
181       Kind = Expr->getKind();
182       const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(BE->getRHS());
183       assert((Kind == MCExpr::SymbolRef) && CE &&
184              "Binary expression must be sym+const.");
185       Ret = CE->getValue();
186     }
187
188     if (Kind == MCExpr::SymbolRef) {
189       Mips::Fixups FixupKind;
190       switch(cast<MCSymbolRefExpr>(Expr)->getKind()) {
191       case MCSymbolRefExpr::VK_Mips_GPREL:
192         FixupKind = Mips::fixup_Mips_GPREL16;
193         break;
194       case MCSymbolRefExpr::VK_Mips_GOT_CALL:
195         FixupKind = Mips::fixup_Mips_CALL16;
196         break;
197       case MCSymbolRefExpr::VK_Mips_GOT16:
198         FixupKind = Mips::fixup_Mips_GOT_Global;
199         break;
200       case MCSymbolRefExpr::VK_Mips_GOT:
201         FixupKind = Mips::fixup_Mips_GOT_Local;
202         break;
203       case MCSymbolRefExpr::VK_Mips_ABS_HI:
204         FixupKind = Mips::fixup_Mips_HI16;
205         break;
206       case MCSymbolRefExpr::VK_Mips_ABS_LO:
207         FixupKind = Mips::fixup_Mips_LO16;
208         break;
209       case MCSymbolRefExpr::VK_Mips_TLSGD:
210         FixupKind = Mips::fixup_Mips_TLSGD;
211         break;
212       case MCSymbolRefExpr::VK_Mips_GOTTPREL:
213         FixupKind = Mips::fixup_Mips_GOTTPREL;
214         break;
215       case MCSymbolRefExpr::VK_Mips_TPREL_HI:
216         FixupKind = Mips::fixup_Mips_TPREL_HI;
217         break;
218       case MCSymbolRefExpr::VK_Mips_TPREL_LO:
219         FixupKind = Mips::fixup_Mips_TPREL_LO;
220         break;
221       default:
222         return Ret;
223       } // switch
224       Fixups.push_back(MCFixup::Create(0, Expr, MCFixupKind(FixupKind)));
225     } // if SymbolRef
226     // All of the information is in the fixup.
227     return Ret;
228   }
229   llvm_unreachable("Unable to encode MCOperand!");
230   // Not reached
231   return 0;
232 }
233
234 /// getMemEncoding - Return binary encoding of memory related operand.
235 /// If the offset operand requires relocation, record the relocation.
236 unsigned
237 MipsMCCodeEmitter::getMemEncoding(const MCInst &MI, unsigned OpNo,
238                                   SmallVectorImpl<MCFixup> &Fixups) const {
239   // Base register is encoded in bits 20-16, offset is encoded in bits 15-0.
240   assert(MI.getOperand(OpNo).isReg());
241   unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo),Fixups) << 16;
242   unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups);
243
244   return (OffBits & 0xFFFF) | RegBits;
245 }
246
247 unsigned
248 MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo,
249                                       SmallVectorImpl<MCFixup> &Fixups) const {
250   assert(MI.getOperand(OpNo).isImm());
251   unsigned szEncoding = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups);
252   return szEncoding - 1;
253 }
254
255 // FIXME: should be called getMSBEncoding
256 //
257 unsigned
258 MipsMCCodeEmitter::getSizeInsEncoding(const MCInst &MI, unsigned OpNo,
259                                       SmallVectorImpl<MCFixup> &Fixups) const {
260   assert(MI.getOperand(OpNo-1).isImm());
261   assert(MI.getOperand(OpNo).isImm());
262   unsigned pos = getMachineOpValue(MI, MI.getOperand(OpNo-1), Fixups);
263   unsigned sz = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups);
264
265   return pos + sz - 1;
266 }
267
268 #include "MipsGenMCCodeEmitter.inc"
269