blob: 563386be1312a9e923e058514d16e6b2c11ba2f5 [file] [log] [blame]
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +00001//===-- MipsAsmPrinter.cpp - Mips LLVM assembly writer --------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Bruno Cardoso Lopes and is distributed under the
6// 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 GAS-format MIPS assembly language.
12//
13//===----------------------------------------------------------------------===//
14
15#define DEBUG_TYPE "mips-asm-printer"
16
17#include "Mips.h"
18#include "MipsInstrInfo.h"
19#include "MipsTargetMachine.h"
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +000020#include "MipsMachineFunction.h"
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +000021#include "llvm/Constants.h"
22#include "llvm/DerivedTypes.h"
23#include "llvm/Module.h"
24#include "llvm/CodeGen/AsmPrinter.h"
25#include "llvm/CodeGen/MachineFunctionPass.h"
26#include "llvm/CodeGen/MachineConstantPool.h"
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +000027#include "llvm/CodeGen/MachineFrameInfo.h"
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +000028#include "llvm/CodeGen/MachineInstr.h"
29#include "llvm/Target/TargetAsmInfo.h"
30#include "llvm/Target/TargetData.h"
31#include "llvm/Target/TargetMachine.h"
32#include "llvm/Support/Mangler.h"
33#include "llvm/ADT/Statistic.h"
34#include "llvm/ADT/StringExtras.h"
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +000035#include "llvm/Support/Debug.h"
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +000036#include "llvm/Support/CommandLine.h"
37#include "llvm/Support/MathExtras.h"
38#include <cctype>
39
40using namespace llvm;
41
42STATISTIC(EmittedInsts, "Number of machine instrs printed");
43
44namespace {
45 struct VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter {
46 MipsAsmPrinter(std::ostream &O, MipsTargetMachine &TM,
47 const TargetAsmInfo *T):
48 AsmPrinter(O, TM, T) {}
49
50 virtual const char *getPassName() const {
51 return "Mips Assembly Printer";
52 }
53
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +000054 enum SetDirectiveFlags {
55 REORDER, // enables instruction reordering.
56 NOREORDER, // disables instruction reordering.
57 MACRO, // enables GAS macros.
58 NOMACRO // disables GAS macros.
59 };
60
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +000061 void printOperand(const MachineInstr *MI, int opNum);
62 void printMemOperand(const MachineInstr *MI, int opNum,
63 const char *Modifier = 0);
64
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +000065 void printHex32(unsigned int Value);
66 void emitFunctionStart(MachineFunction &MF);
67 void emitFunctionEnd();
68 void emitFrameDirective(MachineFunction &MF);
69 void emitMaskDirective(MachineFunction &MF);
70 void emitFMaskDirective();
71 void emitSetDirective(SetDirectiveFlags Flag);
72
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +000073 bool printInstruction(const MachineInstr *MI); // autogenerated.
74 bool runOnMachineFunction(MachineFunction &F);
75 bool doInitialization(Module &M);
76 bool doFinalization(Module &M);
77 };
78} // end of anonymous namespace
79
80#include "MipsGenAsmWriter.inc"
81
82/// createMipsCodePrinterPass - Returns a pass that prints the MIPS
83/// assembly code for a MachineFunction to the given output stream,
84/// using the given target machine description. This should work
85/// regardless of whether the function is in SSA form.
86FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o,
87 MipsTargetMachine &tm)
88{
89 return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo());
90}
91
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +000092/// This pattern will be emitted :
93/// .frame reg1, size, reg2
94/// It describes the stack frame.
95/// reg1 - stack pointer
96/// size - stack size allocated for the function
97/// reg2 - return address register
98void MipsAsmPrinter::
99emitFrameDirective(MachineFunction &MF)
100{
101 const MRegisterInfo &RI = *TM.getRegisterInfo();
102
103 unsigned stackReg = RI.getFrameRegister(MF);
104 unsigned returnReg = RI.getRARegister();
105 unsigned stackSize = MF.getFrameInfo()->getStackSize();
106
107
108 O << "\t.frame\t" << "$" << LowercaseString(RI.get(stackReg).Name)
109 << "," << stackSize << ","
110 << "$" << LowercaseString(RI.get(returnReg).Name)
111 << "\n";
112}
113
114/// This pattern will be emitted :
115/// .mask bitmask, offset
116/// Tells the assembler (and possibly linker) which registers are saved and where.
117/// bitmask - mask of all GPRs (little endian)
118/// offset - negative value. offset+stackSize should give where on the stack
119/// the first GPR is saved.
120/// TODO: consider calle saved GPR regs here, not hardcode register numbers.
121void MipsAsmPrinter::
122emitMaskDirective(MachineFunction &MF)
123{
124 const MRegisterInfo &RI = *TM.getRegisterInfo();
125 MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
126
127 bool hasFP = RI.hasFP(MF);
128 bool saveRA = MF.getFrameInfo()->hasCalls();
129
130 int offset;
131
132 if (!MipsFI->getTopSavedRegOffset())
133 offset = 0;
134 else
135 offset = -(MF.getFrameInfo()->getStackSize()
136 -MipsFI->getTopSavedRegOffset());
137
138 #ifndef NDEBUG
139 DOUT << "<--ASM PRINTER--emitMaskDirective-->" << "\n";
140 DOUT << "StackSize : " << MF.getFrameInfo()->getStackSize() << "\n";
141 DOUT << "getTopSavedRegOffset() : " << MipsFI->getTopSavedRegOffset() << "\n";
142 DOUT << "offset : " << offset << "\n\n";
143 #endif
144
145 unsigned int bitmask = 0;
146
147 if (hasFP)
148 bitmask |= (1 << 30);
149
150 if (saveRA)
151 bitmask |= (1 << 31);
152
153 O << "\t.mask\t";
154 printHex32(bitmask);
155 O << "," << offset << "\n";
156}
157
158/// This pattern will be emitted :
159/// .fmask bitmask, offset
160/// Tells the assembler (and possibly linker) which float registers are saved.
161/// bitmask - mask of all Float Point registers (little endian)
162/// offset - negative value. offset+stackSize should give where on the stack
163/// the first Float Point register is saved.
164/// TODO: implement this, dummy for now
165void MipsAsmPrinter::
166emitFMaskDirective()
167{
168 O << "\t.fmask\t0x00000000,0" << "\n";
169}
170
171/// Print a 32 bit hex number filling with 0's on the left.
172/// TODO: make this setfill and setw
173void MipsAsmPrinter::
174printHex32(unsigned int Value) {
175 O << "0x" << std::hex << Value << std::dec;
176}
177
178/// Emit Set directives.
179void MipsAsmPrinter::
180emitSetDirective(SetDirectiveFlags Flag) {
181
182 O << "\t.set\t";
183 switch(Flag) {
184 case REORDER: O << "reorder" << "\n"; break;
185 case NOREORDER: O << "noreorder" << "\n"; break;
186 case MACRO: O << "macro" << "\n"; break;
187 case NOMACRO: O << "nomacro" << "\n"; break;
188 default: break;
189 }
190}
191
192/// Emit the directives used by GAS on the start of functions
193void MipsAsmPrinter::
194emitFunctionStart(MachineFunction &MF)
195{
196 // Print out the label for the function.
197 const Function *F = MF.getFunction();
198 SwitchToTextSection(getSectionForFunction(*F).c_str(), F);
199
200 // On Mips GAS, if .align #n is present, #n means the number of bits
201 // to be cleared. So, if we want 4 byte alignment, we must have .align 2
202 EmitAlignment(1, F);
203
204 O << "\t.globl\t" << CurrentFnName << "\n";
205 O << "\t.ent\t" << CurrentFnName << "\n";
206 O << "\t.type\t" << CurrentFnName << ", @function\n";
207 O << CurrentFnName << ":\n";
208
209 emitFrameDirective(MF);
210 emitMaskDirective(MF);
211 emitFMaskDirective();
212
213 emitSetDirective(NOREORDER);
214 emitSetDirective(NOMACRO);
215}
216
217/// Emit the directives used by GAS on the end of functions
218void MipsAsmPrinter::
219emitFunctionEnd() {
220 emitSetDirective(MACRO);
221 emitSetDirective(REORDER);
222 O << "\t.end\t" << CurrentFnName << "\n";
223}
224
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +0000225/// runOnMachineFunction - This uses the printMachineInstruction()
226/// method to print assembly for each instruction.
227bool MipsAsmPrinter::
228runOnMachineFunction(MachineFunction &MF)
229{
230 SetupMachineFunction(MF);
231
232 // Print out constants referenced by the function
233 EmitConstantPool(MF.getConstantPool());
234
235 O << "\n\n";
236
237 // What's my mangled name?
238 CurrentFnName = Mang->getValueName(MF.getFunction());
239
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +0000240 // Emit the function start directives
241 emitFunctionStart(MF);
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +0000242
243 // Print out code for the function.
244 for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
245 I != E; ++I) {
246
247 // Print a label for the basic block.
248 if (I != MF.begin()) {
249 printBasicBlockLabel(I, true);
250 O << '\n';
251 }
252
253 for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
254 II != E; ++II) {
255 // Print the assembly for the instruction.
256 O << "\t";
257 printInstruction(II);
258 ++EmittedInsts;
259 }
260 }
261
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +0000262 // Emit function end directives
263 emitFunctionEnd();
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +0000264
265 // We didn't modify anything.
266 return false;
267}
268
269void MipsAsmPrinter::
270printOperand(const MachineInstr *MI, int opNum)
271{
272 const MachineOperand &MO = MI->getOperand(opNum);
273 const MRegisterInfo &RI = *TM.getRegisterInfo();
274 bool closeP=false;
275
276 // %hi and %lo used on mips gas to break large constants
277 if (MI->getOpcode() == Mips::LUi && !MO.isRegister()
278 && !MO.isImmediate()) {
279 O << "%hi(";
280 closeP = true;
281 } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isRegister()
282 && !MO.isImmediate()) {
283 O << "%lo(";
284 closeP = true;
285 }
286
287 switch (MO.getType())
288 {
289 case MachineOperand::MO_Register:
290 if (MRegisterInfo::isPhysicalRegister(MO.getReg()))
291 O << "$" << LowercaseString (RI.get(MO.getReg()).Name);
292 else
293 O << "$" << MO.getReg();
294 break;
295
296 case MachineOperand::MO_Immediate:
297 if ((MI->getOpcode() == Mips::SLTiu) || (MI->getOpcode() == Mips::ORi) ||
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +0000298 (MI->getOpcode() == Mips::LUi) || (MI->getOpcode() == Mips::ANDi))
299 O << (unsigned short int)MO.getImmedValue();
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +0000300 else
Bruno Cardoso Lopesa4e82002007-07-11 23:24:41 +0000301 O << (short int)MO.getImmedValue();
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +0000302 break;
303
304 case MachineOperand::MO_MachineBasicBlock:
305 printBasicBlockLabel(MO.getMachineBasicBlock());
306 return;
307
308 case MachineOperand::MO_GlobalAddress:
309 O << Mang->getValueName(MO.getGlobal());
310 break;
311
312 case MachineOperand::MO_ExternalSymbol:
313 O << MO.getSymbolName();
314 break;
315
316 case MachineOperand::MO_ConstantPoolIndex:
317 O << TAI->getPrivateGlobalPrefix() << "CPI"
318 << getFunctionNumber() << "_" << MO.getConstantPoolIndex();
319 break;
320
321 default:
322 O << "<unknown operand type>"; abort (); break;
323 }
324
325 if (closeP) O << ")";
326}
327
328void MipsAsmPrinter::
329printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier)
330{
331 // lw/sw $reg, MemOperand
332 // will turn into :
333 // lw/sw $reg, imm($reg)
334 printOperand(MI, opNum);
335 O << "(";
336 printOperand(MI, opNum+1);
337 O << ")";
338}
339
340bool MipsAsmPrinter::
341doInitialization(Module &M)
342{
343 Mang = new Mangler(M);
344 return false; // success
345}
346
347bool MipsAsmPrinter::
348doFinalization(Module &M)
349{
350 const TargetData *TD = TM.getTargetData();
351
352 // Print out module-level global variables here.
353 for (Module::const_global_iterator I = M.global_begin(),
354 E = M.global_end(); I != E; ++I)
355
356 // External global require no code
357 if (I->hasInitializer()) {
358
359 // Check to see if this is a special global
360 // used by LLVM, if so, emit it.
361 if (EmitSpecialLLVMGlobal(I))
362 continue;
363
364 O << "\n\n";
365 std::string name = Mang->getValueName(I);
366 Constant *C = I->getInitializer();
367 unsigned Size = TD->getTypeSize(C->getType());
368 unsigned Align = TD->getPrefTypeAlignment(C->getType());
369
370 if (C->isNullValue() && (I->hasLinkOnceLinkage() ||
371 I->hasInternalLinkage() || I->hasWeakLinkage()
372 /* FIXME: Verify correct */)) {
373
374 SwitchToDataSection(".data", I);
375 if (I->hasInternalLinkage())
376 O << "\t.local " << name << "\n";
377
378 O << "\t.comm " << name << ","
379 << TD->getTypeSize(C->getType())
380 << "," << Align << "\n";
381
382 } else {
383
384 switch (I->getLinkage())
385 {
386 case GlobalValue::LinkOnceLinkage:
387 case GlobalValue::WeakLinkage:
388 // FIXME: Verify correct for weak.
389 // Nonnull linkonce -> weak
390 O << "\t.weak " << name << "\n";
391 SwitchToDataSection("", I);
392 O << "\t.section\t\".llvm.linkonce.d." << name
393 << "\",\"aw\",@progbits\n";
394 break;
395 case GlobalValue::AppendingLinkage:
396 // FIXME: appending linkage variables
397 // should go into a section of their name or
398 // something. For now, just emit them as external.
399 case GlobalValue::ExternalLinkage:
400 // If external or appending, declare as a global symbol
401 O << "\t.globl " << name << "\n";
402 case GlobalValue::InternalLinkage:
403 if (C->isNullValue())
404 SwitchToDataSection(".bss", I);
405 else
406 SwitchToDataSection(".data", I);
407 break;
408 case GlobalValue::GhostLinkage:
409 cerr << "Should not have any"
410 << "unmaterialized functions!\n";
411 abort();
412 case GlobalValue::DLLImportLinkage:
413 cerr << "DLLImport linkage is"
414 << "not supported by this target!\n";
415 abort();
416 case GlobalValue::DLLExportLinkage:
417 cerr << "DLLExport linkage is"
418 << "not supported by this target!\n";
419 abort();
420 default:
421 assert(0 && "Unknown linkage type!");
422 }
423 O << "\t.align " << Align << "\n";
424 O << "\t.type " << name << ",@object\n";
425 O << "\t.size " << name << "," << Size << "\n";
426 O << name << ":\n";
427 EmitGlobalConstant(C);
428 }
429 }
430
Dan Gohmanb8275a32007-07-25 19:33:14 +0000431 return AsmPrinter::doFinalization(M);
Bruno Cardoso Lopes972f5892007-06-06 07:42:06 +0000432}