delete the fixme too! :)
[oota-llvm.git] / lib / Target / X86 / AsmPrinter / X86MCInstLower.cpp
1 //===-- X86MCInstLower.cpp - Convert X86 MachineInstr to an MCInst --------===//
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 contains code to lower X86 MachineInstrs to their corresponding
11 // MCInst records.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "X86MCInstLower.h"
16 #include "X86ATTAsmPrinter.h"
17 #include "X86MCAsmInfo.h"
18 #include "llvm/MC/MCContext.h"
19 #include "llvm/MC/MCExpr.h"
20 #include "llvm/MC/MCInst.h"
21 #include "llvm/MC/MCStreamer.h"
22 #include "llvm/Support/FormattedStream.h"
23 #include "llvm/Support/Mangler.h"
24 #include "llvm/ADT/SmallString.h"
25 using namespace llvm;
26
27
28 const X86Subtarget &X86MCInstLower::getSubtarget() const {
29   return AsmPrinter.getSubtarget();
30 }
31
32
33 MCSymbol *X86MCInstLower::GetPICBaseSymbol() const {
34   SmallString<60> Name;
35   raw_svector_ostream(Name) << AsmPrinter.MAI->getPrivateGlobalPrefix()
36     << AsmPrinter.getFunctionNumber() << "$pb";
37   return Ctx.GetOrCreateSymbol(Name.str());
38 }
39
40
41 /// LowerGlobalAddressOperand - Lower an MO_GlobalAddress operand to an
42 /// MCOperand.
43 MCSymbol *X86MCInstLower::
44 GetGlobalAddressSymbol(const MachineOperand &MO) const {
45   const GlobalValue *GV = MO.getGlobal();
46   
47   bool isImplicitlyPrivate = false;
48   if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB ||
49       MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY ||
50       MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE ||
51       MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE)
52     isImplicitlyPrivate = true;
53   
54   SmallString<128> Name;
55   Mang->getNameWithPrefix(Name, GV, isImplicitlyPrivate);
56   
57   if (getSubtarget().isTargetCygMing())
58     AsmPrinter.DecorateCygMingName(Name, GV);
59   
60   switch (MO.getTargetFlags()) {
61   default: llvm_unreachable("Unknown target flag on GV operand");
62   case X86II::MO_NO_FLAG:                // No flag.
63   case X86II::MO_PIC_BASE_OFFSET:        // Doesn't modify symbol name.
64     break;
65   case X86II::MO_DLLIMPORT: {
66     // Handle dllimport linkage.
67     const char *Prefix = "__imp_";
68     Name.insert(Name.begin(), Prefix, Prefix+strlen(Prefix));
69     break;
70   }
71   case X86II::MO_DARWIN_NONLAZY:
72   case X86II::MO_DARWIN_NONLAZY_PIC_BASE: {
73     Name += "$non_lazy_ptr";
74     MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str());
75     MCSymbol *&StubSym = AsmPrinter.GVStubs[Sym];
76     if (StubSym == 0) {
77       Name.clear();
78       Mang->getNameWithPrefix(Name, GV, false);
79       StubSym = Ctx.GetOrCreateSymbol(Name.str());
80     }
81     return Sym;
82   }
83   case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: {
84     Name += "$non_lazy_ptr";
85     MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str());
86     MCSymbol *&StubSym = AsmPrinter.HiddenGVStubs[Sym];
87     if (StubSym == 0) {
88       Name.clear();
89       Mang->getNameWithPrefix(Name, GV, false);
90       StubSym = Ctx.GetOrCreateSymbol(Name.str());
91     }
92     return Sym;
93   }
94   case X86II::MO_DARWIN_STUB: {
95     Name += "$stub";
96     MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str());
97     MCSymbol *&StubSym = AsmPrinter.FnStubs[Sym];
98     if (StubSym == 0) {
99       Name.clear();
100       Mang->getNameWithPrefix(Name, GV, false);
101       StubSym = Ctx.GetOrCreateSymbol(Name.str());
102     }
103     return Sym;
104   }
105   // FIXME: These probably should be a modifier on the symbol or something??
106   case X86II::MO_TLSGD:     Name += "@TLSGD";     break;
107   case X86II::MO_GOTTPOFF:  Name += "@GOTTPOFF";  break;
108   case X86II::MO_INDNTPOFF: Name += "@INDNTPOFF"; break;
109   case X86II::MO_TPOFF:     Name += "@TPOFF";     break;
110   case X86II::MO_NTPOFF:    Name += "@NTPOFF";    break;
111   case X86II::MO_GOTPCREL:  Name += "@GOTPCREL";  break;
112   case X86II::MO_GOT:       Name += "@GOT";       break;
113   case X86II::MO_GOTOFF:    Name += "@GOTOFF";    break;
114   case X86II::MO_PLT:       Name += "@PLT";       break;
115   }
116   
117   return Ctx.GetOrCreateSymbol(Name.str());
118 }
119
120 MCSymbol *X86MCInstLower::
121 GetExternalSymbolSymbol(const MachineOperand &MO) const {
122   SmallString<128> Name;
123   Name += AsmPrinter.MAI->getGlobalPrefix();
124   Name += MO.getSymbolName();
125   
126   switch (MO.getTargetFlags()) {
127   default: llvm_unreachable("Unknown target flag on GV operand");
128   case X86II::MO_NO_FLAG:                // No flag.
129   case X86II::MO_GOT_ABSOLUTE_ADDRESS:   // Doesn't modify symbol name.
130   case X86II::MO_PIC_BASE_OFFSET:        // Doesn't modify symbol name.
131     break;
132   case X86II::MO_DLLIMPORT: {
133     // Handle dllimport linkage.
134     const char *Prefix = "__imp_";
135     Name.insert(Name.begin(), Prefix, Prefix+strlen(Prefix));
136     break;
137   }
138   case X86II::MO_DARWIN_STUB: {
139     Name += "$stub";
140     MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str());
141     MCSymbol *&StubSym = AsmPrinter.FnStubs[Sym];
142     if (StubSym == 0) {
143       Name.erase(Name.end()-5, Name.end());
144       StubSym = Ctx.GetOrCreateSymbol(Name.str());
145     }
146     return Sym;
147   }
148   // FIXME: These probably should be a modifier on the symbol or something??
149   case X86II::MO_TLSGD:     Name += "@TLSGD";     break;
150   case X86II::MO_GOTTPOFF:  Name += "@GOTTPOFF";  break;
151   case X86II::MO_INDNTPOFF: Name += "@INDNTPOFF"; break;
152   case X86II::MO_TPOFF:     Name += "@TPOFF";     break;
153   case X86II::MO_NTPOFF:    Name += "@NTPOFF";    break;
154   case X86II::MO_GOTPCREL:  Name += "@GOTPCREL";  break;
155   case X86II::MO_GOT:       Name += "@GOT";       break;
156   case X86II::MO_GOTOFF:    Name += "@GOTOFF";    break;
157   case X86II::MO_PLT:       Name += "@PLT";       break;
158   }
159   
160   return Ctx.GetOrCreateSymbol(Name.str());
161 }
162
163 MCSymbol *X86MCInstLower::GetJumpTableSymbol(const MachineOperand &MO) const {
164   SmallString<256> Name;
165   raw_svector_ostream(Name) << AsmPrinter.MAI->getPrivateGlobalPrefix() << "JTI"
166     << AsmPrinter.getFunctionNumber() << '_' << MO.getIndex();
167   
168   switch (MO.getTargetFlags()) {
169   default:
170     llvm_unreachable("Unknown target flag on GV operand");
171   case X86II::MO_NO_FLAG:    // No flag.
172   case X86II::MO_PIC_BASE_OFFSET:
173   case X86II::MO_DARWIN_NONLAZY_PIC_BASE:
174   case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE:
175     break;
176     // FIXME: These probably should be a modifier on the symbol or something??
177   case X86II::MO_TLSGD:     Name += "@TLSGD";     break;
178   case X86II::MO_GOTTPOFF:  Name += "@GOTTPOFF";  break;
179   case X86II::MO_INDNTPOFF: Name += "@INDNTPOFF"; break;
180   case X86II::MO_TPOFF:     Name += "@TPOFF";     break;
181   case X86II::MO_NTPOFF:    Name += "@NTPOFF";    break;
182   case X86II::MO_GOTPCREL:  Name += "@GOTPCREL";  break;
183   case X86II::MO_GOT:       Name += "@GOT";       break;
184   case X86II::MO_GOTOFF:    Name += "@GOTOFF";    break;
185   case X86II::MO_PLT:       Name += "@PLT";       break;
186   }
187   
188   // Create a symbol for the name.
189   return Ctx.GetOrCreateSymbol(Name.str());
190 }
191
192
193 MCSymbol *X86MCInstLower::
194 GetConstantPoolIndexSymbol(const MachineOperand &MO) const {
195   SmallString<256> Name;
196   raw_svector_ostream(Name) << AsmPrinter.MAI->getPrivateGlobalPrefix() << "CPI"
197     << AsmPrinter.getFunctionNumber() << '_' << MO.getIndex();
198   
199   switch (MO.getTargetFlags()) {
200   default:
201     llvm_unreachable("Unknown target flag on GV operand");
202   case X86II::MO_NO_FLAG:    // No flag.
203   case X86II::MO_PIC_BASE_OFFSET:
204   case X86II::MO_DARWIN_NONLAZY_PIC_BASE:
205   case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE:
206     break;
207     // FIXME: These probably should be a modifier on the symbol or something??
208   case X86II::MO_TLSGD:     Name += "@TLSGD";     break;
209   case X86II::MO_GOTTPOFF:  Name += "@GOTTPOFF";  break;
210   case X86II::MO_INDNTPOFF: Name += "@INDNTPOFF"; break;
211   case X86II::MO_TPOFF:     Name += "@TPOFF";     break;
212   case X86II::MO_NTPOFF:    Name += "@NTPOFF";    break;
213   case X86II::MO_GOTPCREL:  Name += "@GOTPCREL";  break;
214   case X86II::MO_GOT:       Name += "@GOT";       break;
215   case X86II::MO_GOTOFF:    Name += "@GOTOFF";    break;
216   case X86II::MO_PLT:       Name += "@PLT";       break;
217   }
218   
219   // Create a symbol for the name.
220   return Ctx.GetOrCreateSymbol(Name.str());
221 }
222
223 MCOperand X86MCInstLower::LowerSymbolOperand(const MachineOperand &MO,
224                                              MCSymbol *Sym) const {
225   // FIXME: We would like an efficient form for this, so we don't have to do a
226   // lot of extra uniquing.
227   const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx);
228   
229   switch (MO.getTargetFlags()) {
230   default: llvm_unreachable("Unknown target flag on GV operand");
231   case X86II::MO_NO_FLAG:    // No flag.
232       
233   // These affect the name of the symbol, not any suffix.
234   case X86II::MO_DARWIN_NONLAZY:
235   case X86II::MO_DLLIMPORT:
236   case X86II::MO_DARWIN_STUB:
237   case X86II::MO_TLSGD:
238   case X86II::MO_GOTTPOFF:
239   case X86II::MO_INDNTPOFF:
240   case X86II::MO_TPOFF:
241   case X86II::MO_NTPOFF:
242   case X86II::MO_GOTPCREL:
243   case X86II::MO_GOT:
244   case X86II::MO_GOTOFF:
245   case X86II::MO_PLT:
246     break;
247   case X86II::MO_PIC_BASE_OFFSET:
248   case X86II::MO_DARWIN_NONLAZY_PIC_BASE:
249   case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE:
250     // Subtract the pic base.
251     Expr = MCBinaryExpr::CreateSub(Expr, 
252                                MCSymbolRefExpr::Create(GetPICBaseSymbol(), Ctx),
253                                    Ctx);
254     break;
255   }
256   
257   if (!MO.isJTI() && MO.getOffset())
258     Expr = MCBinaryExpr::CreateAdd(Expr,
259                                    MCConstantExpr::Create(MO.getOffset(), Ctx),
260                                    Ctx);
261   return MCOperand::CreateExpr(Expr);
262 }
263
264
265
266 static void lower_subreg32(MCInst *MI, unsigned OpNo) {
267   // Convert registers in the addr mode according to subreg32.
268   unsigned Reg = MI->getOperand(OpNo).getReg();
269   if (Reg != 0)
270     MI->getOperand(OpNo).setReg(getX86SubSuperRegister(Reg, MVT::i32));
271 }
272
273 static void lower_lea64_32mem(MCInst *MI, unsigned OpNo) {
274   // Convert registers in the addr mode according to subreg64.
275   for (unsigned i = 0; i != 4; ++i) {
276     if (!MI->getOperand(OpNo+i).isReg()) continue;
277     
278     unsigned Reg = MI->getOperand(OpNo+i).getReg();
279     if (Reg == 0) continue;
280     
281     MI->getOperand(OpNo+i).setReg(getX86SubSuperRegister(Reg, MVT::i64));
282   }
283 }
284
285
286
287 void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
288   OutMI.setOpcode(MI->getOpcode());
289   
290   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
291     const MachineOperand &MO = MI->getOperand(i);
292     
293     MCOperand MCOp;
294     switch (MO.getType()) {
295     default:
296       MI->dump();
297       llvm_unreachable("unknown operand type");
298     case MachineOperand::MO_Register:
299       MCOp = MCOperand::CreateReg(MO.getReg());
300       break;
301     case MachineOperand::MO_Immediate:
302       MCOp = MCOperand::CreateImm(MO.getImm());
303       break;
304     case MachineOperand::MO_MachineBasicBlock:
305       MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create(
306                        AsmPrinter.GetMBBSymbol(MO.getMBB()->getNumber()), Ctx));
307       break;
308     case MachineOperand::MO_GlobalAddress:
309       MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
310       break;
311     case MachineOperand::MO_ExternalSymbol:
312       MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
313       break;
314     case MachineOperand::MO_JumpTableIndex:
315       MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO));
316       break;
317     case MachineOperand::MO_ConstantPoolIndex:
318       MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO));
319       break;
320     }
321     
322     OutMI.addOperand(MCOp);
323   }
324   
325   // Handle a few special cases to eliminate operand modifiers.
326   switch (OutMI.getOpcode()) {
327   case X86::LEA64_32r: // Handle 'subreg rewriting' for the lea64_32mem operand.
328     lower_lea64_32mem(&OutMI, 1);
329     break;
330   case X86::MOV16r0:
331     OutMI.setOpcode(X86::MOV32r0);
332     lower_subreg32(&OutMI, 0);
333     break;
334   case X86::MOVZX16rr8:
335     OutMI.setOpcode(X86::MOVZX32rr8);
336     lower_subreg32(&OutMI, 0);
337     break;
338   case X86::MOVZX16rm8:
339     OutMI.setOpcode(X86::MOVZX32rm8);
340     lower_subreg32(&OutMI, 0);
341     break;
342   case X86::MOVSX16rr8:
343     OutMI.setOpcode(X86::MOVSX32rr8);
344     lower_subreg32(&OutMI, 0);
345     break;
346   case X86::MOVSX16rm8:
347     OutMI.setOpcode(X86::MOVSX32rm8);
348     lower_subreg32(&OutMI, 0);
349     break;
350   case X86::MOVZX64rr32:
351     OutMI.setOpcode(X86::MOV32rr);
352     lower_subreg32(&OutMI, 0);
353     break;
354   case X86::MOVZX64rm32:
355     OutMI.setOpcode(X86::MOV32rm);
356     lower_subreg32(&OutMI, 0);
357     break;
358   case X86::MOV64ri64i32:
359     OutMI.setOpcode(X86::MOV32ri);
360     lower_subreg32(&OutMI, 0);
361     break;
362   case X86::MOVZX64rr8:
363     OutMI.setOpcode(X86::MOVZX32rr8);
364     lower_subreg32(&OutMI, 0);
365     break;
366   case X86::MOVZX64rm8:
367     OutMI.setOpcode(X86::MOVZX32rm8);
368     lower_subreg32(&OutMI, 0);
369     break;
370   case X86::MOVZX64rr16:
371     OutMI.setOpcode(X86::MOVZX32rr16);
372     lower_subreg32(&OutMI, 0);
373     break;
374   case X86::MOVZX64rm16:
375     OutMI.setOpcode(X86::MOVZX32rm16);
376     lower_subreg32(&OutMI, 0);
377     break;
378   }
379 }
380
381
382
383 void X86ATTAsmPrinter::
384 printInstructionThroughMCStreamer(const MachineInstr *MI) {
385   X86MCInstLower MCInstLowering(OutContext, Mang, *this);
386   switch (MI->getOpcode()) {
387   case TargetInstrInfo::DBG_LABEL:
388   case TargetInstrInfo::EH_LABEL:
389   case TargetInstrInfo::GC_LABEL:
390     printLabel(MI);
391     return;
392   case TargetInstrInfo::INLINEASM:
393     O << '\t';
394     printInlineAsm(MI);
395     return;
396   case TargetInstrInfo::IMPLICIT_DEF:
397     printImplicitDef(MI);
398     return;
399   case X86::MOVPC32r: {
400     MCInst TmpInst;
401     // This is a pseudo op for a two instruction sequence with a label, which
402     // looks like:
403     //     call "L1$pb"
404     // "L1$pb":
405     //     popl %esi
406     
407     // Emit the call.
408     MCSymbol *PICBase = MCInstLowering.GetPICBaseSymbol();
409     TmpInst.setOpcode(X86::CALLpcrel32);
410     // FIXME: We would like an efficient form for this, so we don't have to do a
411     // lot of extra uniquing.
412     TmpInst.addOperand(MCOperand::CreateExpr(MCSymbolRefExpr::Create(PICBase,
413                                                                  OutContext)));
414     printInstruction(&TmpInst);
415     O << '\n';
416     
417     // Emit the label.
418     OutStreamer.EmitLabel(PICBase);
419     
420     // popl $reg
421     TmpInst.setOpcode(X86::POP32r);
422     TmpInst.getOperand(0) = MCOperand::CreateReg(MI->getOperand(0).getReg());
423     printInstruction(&TmpInst);
424     return;
425   }
426       
427   case X86::ADD32ri: {
428     // Lower the MO_GOT_ABSOLUTE_ADDRESS form of ADD32ri.
429     if (MI->getOperand(2).getTargetFlags() != X86II::MO_GOT_ABSOLUTE_ADDRESS)
430       break;
431     
432     // Okay, we have something like:
433     //  EAX = ADD32ri EAX, MO_GOT_ABSOLUTE_ADDRESS(@MYGLOBAL)
434     
435     // For this, we want to print something like:
436     //   MYGLOBAL + (. - PICBASE)
437     // However, we can't generate a ".", so just emit a new label here and refer
438     // to it.  We know that this operand flag occurs at most once per function.
439     SmallString<64> Name;
440     raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix()
441       << "picbaseref" << getFunctionNumber();
442     MCSymbol *DotSym = OutContext.GetOrCreateSymbol(Name.str());
443     OutStreamer.EmitLabel(DotSym);
444     
445     // Now that we have emitted the label, lower the complex operand expression.
446     MCSymbol *OpSym = MCInstLowering.GetExternalSymbolSymbol(MI->getOperand(2));
447     
448     const MCExpr *DotExpr = MCSymbolRefExpr::Create(DotSym, OutContext);
449     const MCExpr *PICBase =
450       MCSymbolRefExpr::Create(MCInstLowering.GetPICBaseSymbol(), OutContext);
451     DotExpr = MCBinaryExpr::CreateSub(DotExpr, PICBase, OutContext);
452     
453     DotExpr = MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(OpSym,OutContext), 
454                                       DotExpr, OutContext);
455     
456     MCInst TmpInst;
457     TmpInst.setOpcode(X86::ADD32ri);
458     TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
459     TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
460     TmpInst.addOperand(MCOperand::CreateExpr(DotExpr));
461     printInstruction(&TmpInst);
462     return;
463   }
464   }
465   
466   MCInst TmpInst;
467   MCInstLowering.Lower(MI, TmpInst);
468   
469   
470   printInstruction(&TmpInst);
471 }