Mips MC object code emission improvements:
[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     if (Kind == MCExpr::SymbolRef) {
177       Mips::Fixups FixupKind = Mips::fixup_Mips_NONE;
178       MCSymbolRefExpr::VariantKind SymRefKind =
179           cast<MCSymbolRefExpr>(Expr)->getKind();
180       switch(SymRefKind) {
181       case MCSymbolRefExpr::VK_Mips_GPREL:
182         FixupKind = Mips::fixup_Mips_GPREL16;
183         break;
184       case MCSymbolRefExpr::VK_Mips_GOT_CALL:
185         FixupKind = Mips::fixup_Mips_CALL16;
186         break;
187       case MCSymbolRefExpr::VK_Mips_GOT:
188         FixupKind = Mips::fixup_Mips_GOT16;
189         break;
190       case MCSymbolRefExpr::VK_Mips_ABS_HI:
191         FixupKind = Mips::fixup_Mips_HI16;
192         break;
193       case MCSymbolRefExpr::VK_Mips_ABS_LO:
194         FixupKind = Mips::fixup_Mips_LO16;
195         break;
196       case MCSymbolRefExpr::VK_Mips_TLSGD:
197         FixupKind = Mips::fixup_Mips_TLSGD;
198         break;
199       case MCSymbolRefExpr::VK_Mips_GOTTPREL:
200         FixupKind = Mips::fixup_Mips_GOTTPREL;
201         break;
202       case MCSymbolRefExpr::VK_Mips_TPREL_HI:
203         FixupKind = Mips::fixup_Mips_TPREL_HI;
204         break;
205       case MCSymbolRefExpr::VK_Mips_TPREL_LO:
206         FixupKind = Mips::fixup_Mips_TPREL_LO;
207         break;
208       default:
209         return 0;
210       } // switch
211       Fixups.push_back(MCFixup::Create(0, Expr, MCFixupKind(FixupKind)));
212     } // if SymbolRef
213     // All of the information is in the fixup.
214     return 0;
215   }
216   llvm_unreachable("Unable to encode MCOperand!");
217   // Not reached
218   return 0;
219 }
220
221 /// getMemEncoding - Return binary encoding of memory related operand.
222 /// If the offset operand requires relocation, record the relocation.
223 unsigned
224 MipsMCCodeEmitter::getMemEncoding(const MCInst &MI, unsigned OpNo,
225                                   SmallVectorImpl<MCFixup> &Fixups) const {
226   // Base register is encoded in bits 20-16, offset is encoded in bits 15-0.
227   assert(MI.getOperand(OpNo).isReg());
228   unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo),Fixups) << 16;
229   unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups);
230
231   return (OffBits & 0xFFFF) | RegBits;
232 }
233
234 unsigned
235 MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo,
236                                       SmallVectorImpl<MCFixup> &Fixups) const {
237   // FIXME: implement
238   return 0;
239 }
240
241 unsigned
242 MipsMCCodeEmitter::getSizeInsEncoding(const MCInst &MI, unsigned OpNo,
243                                       SmallVectorImpl<MCFixup> &Fixups) const {
244   // FIXME: implement
245   return 0;
246 }
247
248 #include "MipsGenMCCodeEmitter.inc"
249