blob: c8bcc59b6285f153adbc5b2fcb5ead6f6c5413ac [file] [log] [blame]
Chris Lattnerb36cbd02005-07-01 22:44:09 +00001//===-- X86IntelAsmPrinter.cpp - Convert X86 LLVM code to Intel assembly --===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains a printer that converts from our internal representation
11// of machine-dependent LLVM code to Intel format assembly language.
12// This printer is the output mechanism used by `llc'.
13//
14//===----------------------------------------------------------------------===//
15
16#include "X86IntelAsmPrinter.h"
17#include "X86.h"
Jeff Cohenc884db42006-05-02 01:16:28 +000018#include "llvm/Constants.h"
Chris Lattnerb36cbd02005-07-01 22:44:09 +000019#include "llvm/Module.h"
20#include "llvm/Assembly/Writer.h"
21#include "llvm/Support/Mangler.h"
Evan Cheng7ccced62006-02-18 00:15:05 +000022#include "llvm/Target/TargetOptions.h"
Chris Lattnerb36cbd02005-07-01 22:44:09 +000023using namespace llvm;
Chris Lattnerb36cbd02005-07-01 22:44:09 +000024
Jeff Cohenc884db42006-05-02 01:16:28 +000025X86IntelAsmPrinter::X86IntelAsmPrinter(std::ostream &O, X86TargetMachine &TM)
26 : X86SharedAsmPrinter(O, TM) {
Jeff Cohenc884db42006-05-02 01:16:28 +000027}
28
Chris Lattnerb36cbd02005-07-01 22:44:09 +000029/// runOnMachineFunction - This uses the printMachineInstruction()
30/// method to print assembly for each instruction.
31///
32bool X86IntelAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
Chris Lattner8b8b9512005-11-21 07:51:23 +000033 SetupMachineFunction(MF);
Chris Lattnerb36cbd02005-07-01 22:44:09 +000034 O << "\n\n";
35
36 // Print out constants referenced by the function
Chris Lattnerd939f6c2005-11-21 08:32:23 +000037 EmitConstantPool(MF.getConstantPool());
Chris Lattnerb36cbd02005-07-01 22:44:09 +000038
39 // Print out labels for the function.
Chris Lattnerdad9c5a2006-05-09 05:12:53 +000040 SwitchToTextSection("_text", MF.getFunction());
Chris Lattner8b8b9512005-11-21 07:51:23 +000041 EmitAlignment(4);
Jeff Cohenc884db42006-05-02 01:16:28 +000042 if (MF.getFunction()->getLinkage() == GlobalValue::ExternalLinkage)
43 O << "\tpublic " << CurrentFnName << "\n";
44 O << CurrentFnName << "\tproc near\n";
Jim Laskey6b92b8e2006-04-07 20:44:42 +000045
Chris Lattnerb36cbd02005-07-01 22:44:09 +000046 // Print out code for the function.
47 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
48 I != E; ++I) {
49 // Print a label for the basic block if there are any predecessors.
Nate Begemancdf38c42006-05-02 05:37:32 +000050 if (I->pred_begin() != I->pred_end()) {
51 printBasicBlockLabel(I, true);
52 O << '\n';
53 }
Chris Lattnerb36cbd02005-07-01 22:44:09 +000054 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
55 II != E; ++II) {
56 // Print the assembly for the instruction.
57 O << "\t";
58 printMachineInstruction(II);
59 }
60 }
61
Jeff Cohenc884db42006-05-02 01:16:28 +000062 O << CurrentFnName << "\tendp\n";
63
Chris Lattnerb36cbd02005-07-01 22:44:09 +000064 // We didn't modify anything.
65 return false;
66}
67
Nate Begeman391c5d22005-11-30 18:54:35 +000068void X86IntelAsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op) {
Nate Begeman6c7cb292005-07-14 22:52:25 +000069 unsigned char value = MI->getOperand(Op).getImmedValue();
70 assert(value <= 7 && "Invalid ssecc argument!");
71 switch (value) {
72 case 0: O << "eq"; break;
73 case 1: O << "lt"; break;
74 case 2: O << "le"; break;
75 case 3: O << "unord"; break;
76 case 4: O << "neq"; break;
77 case 5: O << "nlt"; break;
78 case 6: O << "nle"; break;
79 case 7: O << "ord"; break;
80 }
81}
82
Chris Lattnera3b8c572006-02-06 23:41:19 +000083void X86IntelAsmPrinter::printOp(const MachineOperand &MO,
84 const char *Modifier) {
Chris Lattnerb36cbd02005-07-01 22:44:09 +000085 const MRegisterInfo &RI = *TM.getRegisterInfo();
86 switch (MO.getType()) {
Chris Lattner2d90ac72006-05-04 18:05:43 +000087 case MachineOperand::MO_Register:
Evan Cheng8f7f7122006-05-05 05:40:20 +000088 if (MRegisterInfo::isPhysicalRegister(MO.getReg())) {
89 unsigned Reg = MO.getReg();
Evan Chengcbe70e12006-05-31 22:34:26 +000090 if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) {
91 MVT::ValueType VT = (strcmp(Modifier,"subreg16") == 0)
Evan Cheng403be7e2006-05-08 08:01:26 +000092 ? MVT::i16 : MVT::i8;
Evan Cheng8f7f7122006-05-05 05:40:20 +000093 Reg = getX86SubSuperRegister(Reg, VT);
94 }
95 O << RI.get(Reg).Name;
96 } else
Chris Lattner99f26322006-05-01 05:53:50 +000097 O << "reg" << MO.getReg();
Chris Lattnerb36cbd02005-07-01 22:44:09 +000098 return;
99
Chris Lattner63b3d712006-05-04 17:21:20 +0000100 case MachineOperand::MO_Immediate:
Evan Cheng138a24e2006-05-26 08:04:31 +0000101 O << MO.getImmedValue();
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000102 return;
Nate Begeman37efe672006-04-22 18:53:45 +0000103 case MachineOperand::MO_MachineBasicBlock:
104 printBasicBlockLabel(MO.getMachineBasicBlock());
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000105 return;
Evan Chenga09bd812006-02-26 08:28:12 +0000106 case MachineOperand::MO_ConstantPoolIndex: {
107 bool isMemOp = Modifier && !strcmp(Modifier, "mem");
108 if (!isMemOp) O << "OFFSET ";
109 O << "[" << PrivateGlobalPrefix << "CPI" << getFunctionNumber() << "_"
110 << MO.getConstantPoolIndex();
Evan Chenga09bd812006-02-26 08:28:12 +0000111 int Offset = MO.getOffset();
112 if (Offset > 0)
113 O << " + " << Offset;
114 else if (Offset < 0)
115 O << Offset;
116 O << "]";
117 return;
118 }
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000119 case MachineOperand::MO_GlobalAddress: {
Evan Cheng7ccced62006-02-18 00:15:05 +0000120 bool isCallOp = Modifier && !strcmp(Modifier, "call");
121 bool isMemOp = Modifier && !strcmp(Modifier, "mem");
122 if (!isMemOp && !isCallOp) O << "OFFSET ";
Jeff Cohend43b18d2006-05-06 21:27:14 +0000123 O << Mang->getValueName(MO.getGlobal());
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000124 int Offset = MO.getOffset();
125 if (Offset > 0)
126 O << " + " << Offset;
127 else if (Offset < 0)
Evan Cheng345c3f32005-11-30 01:59:00 +0000128 O << Offset;
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000129 return;
130 }
Evan Cheng7ccced62006-02-18 00:15:05 +0000131 case MachineOperand::MO_ExternalSymbol: {
132 bool isCallOp = Modifier && !strcmp(Modifier, "call");
Evan Cheng4c1aa862006-02-22 20:19:42 +0000133 if (!isCallOp) O << "OFFSET ";
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000134 O << GlobalPrefix << MO.getSymbolName();
135 return;
Evan Cheng7ccced62006-02-18 00:15:05 +0000136 }
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000137 default:
138 O << "<unknown operand type>"; return;
139 }
140}
141
142void X86IntelAsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op){
143 assert(isMem(MI, Op) && "Invalid memory reference!");
144
145 const MachineOperand &BaseReg = MI->getOperand(Op);
146 int ScaleVal = MI->getOperand(Op+1).getImmedValue();
147 const MachineOperand &IndexReg = MI->getOperand(Op+2);
148 const MachineOperand &DispSpec = MI->getOperand(Op+3);
149
150 if (BaseReg.isFrameIndex()) {
151 O << "[frame slot #" << BaseReg.getFrameIndex();
152 if (DispSpec.getImmedValue())
153 O << " + " << DispSpec.getImmedValue();
154 O << "]";
155 return;
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000156 }
157
158 O << "[";
159 bool NeedPlus = false;
160 if (BaseReg.getReg()) {
Evan Cheng2338c5c2006-02-07 08:38:37 +0000161 printOp(BaseReg, "mem");
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000162 NeedPlus = true;
163 }
164
165 if (IndexReg.getReg()) {
166 if (NeedPlus) O << " + ";
167 if (ScaleVal != 1)
168 O << ScaleVal << "*";
169 printOp(IndexReg);
170 NeedPlus = true;
171 }
172
Evan Chenga09bd812006-02-26 08:28:12 +0000173 if (DispSpec.isGlobalAddress() || DispSpec.isConstantPoolIndex()) {
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000174 if (NeedPlus)
175 O << " + ";
Evan Cheng2338c5c2006-02-07 08:38:37 +0000176 printOp(DispSpec, "mem");
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000177 } else {
178 int DispVal = DispSpec.getImmedValue();
179 if (DispVal || (!BaseReg.getReg() && !IndexReg.getReg())) {
180 if (NeedPlus)
181 if (DispVal > 0)
182 O << " + ";
183 else {
184 O << " - ";
185 DispVal = -DispVal;
186 }
187 O << DispVal;
188 }
189 }
190 O << "]";
191}
192
Evan Cheng7ccced62006-02-18 00:15:05 +0000193void X86IntelAsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op) {
194 O << "\"L" << getFunctionNumber() << "$pb\"\n";
195 O << "\"L" << getFunctionNumber() << "$pb\":";
196}
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000197
Evan Cheng55c25f22006-04-28 23:19:39 +0000198bool X86IntelAsmPrinter::printAsmMRegister(const MachineOperand &MO,
Evan Cheng62f27002006-04-28 23:11:40 +0000199 const char Mode) {
200 const MRegisterInfo &RI = *TM.getRegisterInfo();
201 unsigned Reg = MO.getReg();
Evan Cheng62f27002006-04-28 23:11:40 +0000202 switch (Mode) {
203 default: return true; // Unknown mode.
204 case 'b': // Print QImode register
Evan Cheng8f7f7122006-05-05 05:40:20 +0000205 Reg = getX86SubSuperRegister(Reg, MVT::i8);
Evan Cheng62f27002006-04-28 23:11:40 +0000206 break;
207 case 'h': // Print QImode high register
Evan Cheng8f7f7122006-05-05 05:40:20 +0000208 Reg = getX86SubSuperRegister(Reg, MVT::i8, true);
Evan Cheng62f27002006-04-28 23:11:40 +0000209 break;
210 case 'w': // Print HImode register
Evan Cheng8f7f7122006-05-05 05:40:20 +0000211 Reg = getX86SubSuperRegister(Reg, MVT::i16);
Evan Cheng62f27002006-04-28 23:11:40 +0000212 break;
213 case 'k': // Print SImode register
Evan Cheng8f7f7122006-05-05 05:40:20 +0000214 Reg = getX86SubSuperRegister(Reg, MVT::i32);
Evan Cheng62f27002006-04-28 23:11:40 +0000215 break;
216 }
217
Evan Cheng8f7f7122006-05-05 05:40:20 +0000218 O << '%' << RI.get(Reg).Name;
Evan Cheng62f27002006-04-28 23:11:40 +0000219 return false;
220}
221
Evan Cheng3d48a902006-04-28 21:19:05 +0000222/// PrintAsmOperand - Print out an operand for an inline asm expression.
223///
224bool X86IntelAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
225 unsigned AsmVariant,
226 const char *ExtraCode) {
227 // Does this asm operand have a single letter operand modifier?
228 if (ExtraCode && ExtraCode[0]) {
229 if (ExtraCode[1] != 0) return true; // Unknown modifier.
230
231 switch (ExtraCode[0]) {
232 default: return true; // Unknown modifier.
Evan Cheng62f27002006-04-28 23:11:40 +0000233 case 'b': // Print QImode register
234 case 'h': // Print QImode high register
235 case 'w': // Print HImode register
236 case 'k': // Print SImode register
Evan Cheng55c25f22006-04-28 23:19:39 +0000237 return printAsmMRegister(MI->getOperand(OpNo), ExtraCode[0]);
Evan Cheng3d48a902006-04-28 21:19:05 +0000238 }
239 }
240
241 printOperand(MI, OpNo);
242 return false;
243}
244
245bool X86IntelAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
246 unsigned OpNo,
247 unsigned AsmVariant,
248 const char *ExtraCode) {
249 if (ExtraCode && ExtraCode[0])
250 return true; // Unknown modifier.
251 printMemReference(MI, OpNo);
252 return false;
253}
254
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000255/// printMachineInstruction -- Print out a single X86 LLVM instruction
256/// MI in Intel syntax to the current output stream.
257///
258void X86IntelAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
259 ++EmittedInsts;
260
Evan Cheng8f7f7122006-05-05 05:40:20 +0000261 // See if a truncate instruction can be turned into a nop.
262 switch (MI->getOpcode()) {
263 default: break;
Evan Cheng069287d2006-05-16 07:21:53 +0000264 case X86::TRUNC_GR32_GR16:
265 case X86::TRUNC_GR32_GR8:
266 case X86::TRUNC_GR16_GR8: {
Evan Cheng8f7f7122006-05-05 05:40:20 +0000267 const MachineOperand &MO0 = MI->getOperand(0);
268 const MachineOperand &MO1 = MI->getOperand(1);
269 unsigned Reg0 = MO0.getReg();
270 unsigned Reg1 = MO1.getReg();
Evan Cheng069287d2006-05-16 07:21:53 +0000271 if (MI->getOpcode() == X86::TRUNC_GR32_GR16)
Evan Cheng403be7e2006-05-08 08:01:26 +0000272 Reg1 = getX86SubSuperRegister(Reg1, MVT::i16);
Evan Cheng8f7f7122006-05-05 05:40:20 +0000273 else
Evan Cheng403be7e2006-05-08 08:01:26 +0000274 Reg1 = getX86SubSuperRegister(Reg1, MVT::i8);
275 O << CommentString << " TRUNCATE ";
276 if (Reg0 != Reg1)
277 O << "\n\t";
Evan Cheng8f7f7122006-05-05 05:40:20 +0000278 break;
279 }
280 }
281
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000282 // Call the autogenerated instruction printer routines.
283 printInstruction(MI);
284}
285
286bool X86IntelAsmPrinter::doInitialization(Module &M) {
Jeff Cohen10efcfa2006-05-04 16:20:22 +0000287 GlobalPrefix = "_";
Jeff Cohend43b18d2006-05-06 21:27:14 +0000288 CommentString = ";";
289
290 X86SharedAsmPrinter::doInitialization(M);
291
Jeff Cohen10efcfa2006-05-04 16:20:22 +0000292 PrivateGlobalPrefix = "$";
293 AlignDirective = "\talign\t";
Jeff Cohen10efcfa2006-05-04 16:20:22 +0000294 ZeroDirective = "\tdb\t";
295 ZeroDirectiveSuffix = " dup(0)";
296 AsciiDirective = "\tdb\t";
297 AscizDirective = 0;
Jeff Cohend43b18d2006-05-06 21:27:14 +0000298 Data8bitsDirective = "\tdb\t";
299 Data16bitsDirective = "\tdw\t";
300 Data32bitsDirective = "\tdd\t";
301 Data64bitsDirective = "\tdq\t";
Jeff Cohen10efcfa2006-05-04 16:20:22 +0000302 HasDotTypeDotSizeDirective = false;
Jeff Cohenc884db42006-05-02 01:16:28 +0000303 Mang->markCharUnacceptable('.');
Chris Lattnerdad9c5a2006-05-09 05:12:53 +0000304
305 DefaultTextSection = "_text";
306 DefaultDataSection = "_data";
Chris Lattnerc9260a12006-05-09 05:21:47 +0000307 SwitchToSectionDirective = "";
Chris Lattner7faec9b2006-05-09 05:33:48 +0000308 TextSectionStartSuffix = "\tsegment 'CODE'";
309 DataSectionStartSuffix = "\tsegment 'DATA'";
310 SectionEndDirectiveSuffix = "\tends\n";
Jeff Cohen10efcfa2006-05-04 16:20:22 +0000311
Jeff Cohen4f1ea1e2006-05-02 03:11:50 +0000312 O << "\t.686\n\t.model flat\n\n";
313
314 // Emit declarations for external functions.
315 for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
316 if (I->isExternal())
317 O << "\textern " << Mang->getValueName(I) << ":near\n";
318
Jeff Cohend43b18d2006-05-06 21:27:14 +0000319 // Emit declarations for external globals. Note that VC++ always declares
320 // external globals to have type byte, and if that's good enough for VC++...
Jeff Cohen4f1ea1e2006-05-02 03:11:50 +0000321 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
322 I != E; ++I) {
323 if (I->isExternal())
324 O << "\textern " << Mang->getValueName(I) << ":byte\n";
325 }
326
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000327 return false;
328}
329
Jeff Cohen4f1ea1e2006-05-02 03:11:50 +0000330bool X86IntelAsmPrinter::doFinalization(Module &M) {
Jeff Cohend43b18d2006-05-06 21:27:14 +0000331 const TargetData *TD = TM.getTargetData();
332
333 // Print out module-level global variables here.
334 for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
335 I != E; ++I) {
336 if (I->isExternal()) continue; // External global require no code
337
338 // Check to see if this is a special global used by LLVM, if so, emit it.
339 if (EmitSpecialLLVMGlobal(I))
340 continue;
341
342 std::string name = Mang->getValueName(I);
343 Constant *C = I->getInitializer();
344 unsigned Size = TD->getTypeSize(C->getType());
345 unsigned Align = getPreferredAlignmentLog(I);
346 bool bCustomSegment = false;
347
348 switch (I->getLinkage()) {
349 case GlobalValue::LinkOnceLinkage:
350 case GlobalValue::WeakLinkage:
Chris Lattner4632d7a2006-05-09 04:59:56 +0000351 SwitchToDataSection("", 0);
Jeff Cohend43b18d2006-05-06 21:27:14 +0000352 O << name << "?\tsegment common 'COMMON'\n";
353 bCustomSegment = true;
354 // FIXME: the default alignment is 16 bytes, but 1, 2, 4, and 256
355 // are also available.
356 break;
357 case GlobalValue::AppendingLinkage:
Chris Lattner4632d7a2006-05-09 04:59:56 +0000358 SwitchToDataSection("", 0);
Jeff Cohend43b18d2006-05-06 21:27:14 +0000359 O << name << "?\tsegment public 'DATA'\n";
360 bCustomSegment = true;
361 // FIXME: the default alignment is 16 bytes, but 1, 2, 4, and 256
362 // are also available.
363 break;
364 case GlobalValue::ExternalLinkage:
365 O << "\tpublic " << name << "\n";
366 // FALL THROUGH
367 case GlobalValue::InternalLinkage:
Chris Lattnerdad9c5a2006-05-09 05:12:53 +0000368 SwitchToDataSection(DefaultDataSection, I);
Jeff Cohend43b18d2006-05-06 21:27:14 +0000369 break;
370 default:
371 assert(0 && "Unknown linkage type!");
372 }
373
374 if (!bCustomSegment)
375 EmitAlignment(Align, I);
376
377 O << name << ":\t\t\t\t" << CommentString << " " << I->getName() << '\n';
378
379 EmitGlobalConstant(C);
380
381 if (bCustomSegment)
382 O << name << "?\tends\n";
383 }
384
385 // Bypass X86SharedAsmPrinter::doFinalization().
386 AsmPrinter::doFinalization(M);
Chris Lattnere7027d52006-05-09 05:15:24 +0000387 SwitchToDataSection("", 0);
Jeff Cohen4f1ea1e2006-05-02 03:11:50 +0000388 O << "\tend\n";
Jeff Cohend43b18d2006-05-06 21:27:14 +0000389 return false; // success
Jeff Cohen4f1ea1e2006-05-02 03:11:50 +0000390}
391
Jeff Cohenc884db42006-05-02 01:16:28 +0000392void X86IntelAsmPrinter::EmitString(const ConstantArray *CVA) const {
393 unsigned NumElts = CVA->getNumOperands();
394 if (NumElts) {
395 // ML does not have escape sequences except '' for '. It also has a maximum
396 // string length of 255.
397 unsigned len = 0;
398 bool inString = false;
399 for (unsigned i = 0; i < NumElts; i++) {
400 int n = cast<ConstantInt>(CVA->getOperand(i))->getRawValue() & 255;
401 if (len == 0)
402 O << "\tdb ";
403
404 if (n >= 32 && n <= 127) {
405 if (!inString) {
406 if (len > 0) {
407 O << ",'";
408 len += 2;
409 } else {
410 O << "'";
411 len++;
412 }
413 inString = true;
414 }
415 if (n == '\'') {
416 O << "'";
417 len++;
418 }
419 O << char(n);
420 } else {
421 if (inString) {
422 O << "'";
423 len++;
424 inString = false;
425 }
426 if (len > 0) {
427 O << ",";
428 len++;
429 }
430 O << n;
431 len += 1 + (n > 9) + (n > 99);
432 }
433
434 if (len > 60) {
435 if (inString) {
436 O << "'";
437 inString = false;
438 }
439 O << "\n";
440 len = 0;
441 }
442 }
443
444 if (len > 0) {
445 if (inString)
446 O << "'";
447 O << "\n";
448 }
449 }
450}
451
Chris Lattnerb36cbd02005-07-01 22:44:09 +0000452// Include the auto-generated portion of the assembly writer.
453#include "X86GenAsmWriter1.inc"