Start using SwitchSection, allowing globals and functions to be emitted
[oota-llvm.git] / lib / Target / IA64 / IA64AsmPrinter.cpp
1 //===-- IA64AsmPrinter.cpp - Print out IA64 LLVM as assembly --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Duraid Madina 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 assembly accepted by the GNU binutils 'gas'
12 // assembler. The Intel 'ias' and HP-UX 'as' assemblers *may* choke on this
13 // output, but if so that's a bug I'd like to hear about: please file a bug
14 // report in bugzilla. FYI, the not too bad 'ias' assembler is bundled with
15 // the Intel C/C++ compiler for Itanium Linux.
16 //
17 //===----------------------------------------------------------------------===//
18
19 #include "IA64.h"
20 #include "IA64TargetMachine.h"
21 #include "llvm/Module.h"
22 #include "llvm/Type.h"
23 #include "llvm/Assembly/Writer.h"
24 #include "llvm/CodeGen/AsmPrinter.h"
25 #include "llvm/CodeGen/MachineConstantPool.h"
26 #include "llvm/CodeGen/MachineFunctionPass.h"
27 #include "llvm/CodeGen/ValueTypes.h"
28 #include "llvm/Target/TargetMachine.h"
29 #include "llvm/Support/Mangler.h"
30 #include "llvm/ADT/Statistic.h"
31 #include "llvm/Support/CommandLine.h"
32 using namespace llvm;
33
34 namespace {
35   Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed");
36
37   struct IA64SharedAsmPrinter : public AsmPrinter {
38
39     std::set<std::string> ExternalFunctionNames, ExternalObjectNames;
40
41     IA64SharedAsmPrinter(std::ostream &O, TargetMachine &TM)
42       : AsmPrinter(O, TM) { }
43
44     void printConstantPool(MachineConstantPool *MCP);
45     bool doFinalization(Module &M);
46   };
47 }
48
49 /// printConstantPool - Print to the current output stream assembly
50 /// representations of the constants in the constant pool MCP. This is
51 /// used to print out constants which have been "spilled to memory" by
52 /// the code generator.
53 ///
54 void IA64SharedAsmPrinter::printConstantPool(MachineConstantPool *MCP) {
55   const std::vector<Constant*> &CP = MCP->getConstants();
56   const TargetData &TD = TM.getTargetData();
57
58   if (CP.empty()) return;
59
60   // FIXME: would be nice to have rodata (no 'w') when appropriate?
61   SwitchSection("\n\t.section .data, \"aw\", \"progbits\"\n", 0);
62   for (unsigned i = 0, e = CP.size(); i != e; ++i) {
63     emitAlignment(TD.getTypeAlignmentShift(CP[i]->getType()));
64     O << PrivateGlobalPrefix << "CPI" << CurrentFnName << "_" << i
65       << ":\t\t\t\t\t" << CommentString << *CP[i] << "\n";
66     emitGlobalConstant(CP[i]);
67   }
68 }
69
70 bool IA64SharedAsmPrinter::doFinalization(Module &M) {
71   const TargetData &TD = TM.getTargetData();
72
73   // Print out module-level global variables here.
74   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
75        I != E; ++I)
76     if (I->hasInitializer()) {   // External global require no code
77       O << "\n\n";
78       std::string name = Mang->getValueName(I);
79       Constant *C = I->getInitializer();
80       unsigned Size = TD.getTypeSize(C->getType());
81       unsigned Align = TD.getTypeAlignmentShift(C->getType());
82
83       if (C->isNullValue() &&
84           (I->hasLinkOnceLinkage() || I->hasInternalLinkage() ||
85            I->hasWeakLinkage() /* FIXME: Verify correct */)) {
86         SwitchSection(".data", I);
87         if (I->hasInternalLinkage()) {
88           O << "\t.lcomm " << name << "," << TD.getTypeSize(C->getType())
89             << "," << (1 << Align);
90           O << "\t\t// ";
91         } else {
92           O << "\t.common " << name << "," << TD.getTypeSize(C->getType())
93             << "," << (1 << Align);
94           O << "\t\t// ";
95         }
96         WriteAsOperand(O, I, true, true, &M);
97         O << "\n";
98       } else {
99         switch (I->getLinkage()) {
100         case GlobalValue::LinkOnceLinkage:
101         case GlobalValue::WeakLinkage:   // FIXME: Verify correct for weak.
102           // Nonnull linkonce -> weak
103           O << "\t.weak " << name << "\n";
104           O << "\t.section\t.llvm.linkonce.d." << name
105             << ", \"aw\", \"progbits\"\n";
106           SwitchSection("", I);
107           break;
108         case GlobalValue::AppendingLinkage:
109           // FIXME: appending linkage variables should go into a section of
110           // their name or something.  For now, just emit them as external.
111         case GlobalValue::ExternalLinkage:
112           // If external or appending, declare as a global symbol
113           O << "\t.global " << name << "\n";
114           // FALL THROUGH
115         case GlobalValue::InternalLinkage:
116           SwitchSection(C->isNullValue() ? ".bss" : ".data", I);
117           break;
118         case GlobalValue::GhostLinkage:
119           std::cerr << "GhostLinkage cannot appear in IA64AsmPrinter!\n";
120           abort();
121         }
122
123         emitAlignment(Align);
124         O << "\t.type " << name << ",@object\n";
125         O << "\t.size " << name << "," << Size << "\n";
126         O << name << ":\t\t\t\t// ";
127         WriteAsOperand(O, I, true, true, &M);
128         O << " = ";
129         WriteAsOperand(O, C, false, false, &M);
130         O << "\n";
131         emitGlobalConstant(C);
132       }
133     }
134
135   // we print out ".global X \n .type X, @function" for each external function
136   O << "\n\n// br.call targets referenced (and not defined) above: \n";
137   for (std::set<std::string>::iterator i = ExternalFunctionNames.begin(),
138        e = ExternalFunctionNames.end(); i!=e; ++i) {
139     O << "\t.global " << *i << "\n\t.type " << *i << ", @function\n";
140   }
141   O << "\n\n";
142
143   // we print out ".global X \n .type X, @object" for each external object
144   O << "\n\n// (external) symbols referenced (and not defined) above: \n";
145   for (std::set<std::string>::iterator i = ExternalObjectNames.begin(),
146        e = ExternalObjectNames.end(); i!=e; ++i) {
147     O << "\t.global " << *i << "\n\t.type " << *i << ", @object\n";
148   }
149   O << "\n\n";
150
151   AsmPrinter::doFinalization(M);
152   return false; // success
153 }
154
155 namespace {
156   struct IA64AsmPrinter : public IA64SharedAsmPrinter {
157     IA64AsmPrinter(std::ostream &O, TargetMachine &TM)
158       : IA64SharedAsmPrinter(O, TM) {
159
160       CommentString = "//";
161       Data8bitsDirective = "\tdata1\t";     // FIXME: check that we are
162       Data16bitsDirective = "\tdata2.ua\t"; // disabling auto-alignment
163       Data32bitsDirective = "\tdata4.ua\t"; // properly
164       Data64bitsDirective = "\tdata8.ua\t";
165       ZeroDirective = "\t.skip\t";
166       AsciiDirective = "\tstring\t";
167
168       GlobalVarAddrPrefix="";
169       GlobalVarAddrSuffix="";
170       FunctionAddrPrefix="@fptr(";
171       FunctionAddrSuffix=")";
172
173     }
174
175     virtual const char *getPassName() const {
176       return "IA64 Assembly Printer";
177     }
178
179     /// printInstruction - This method is automatically generated by tablegen
180     /// from the instruction set description.  This method returns true if the
181     /// machine instruction was sufficiently described to print it, otherwise it
182     /// returns false.
183     bool printInstruction(const MachineInstr *MI);
184
185     // This method is used by the tablegen'erated instruction printer.
186     void printOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT){
187       const MachineOperand &MO = MI->getOperand(OpNo);
188       if (MO.getType() == MachineOperand::MO_MachineRegister) {
189         assert(MRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physref??");
190         //XXX Bug Workaround: See note in Printer::doInitialization about %.
191         O << TM.getRegisterInfo()->get(MO.getReg()).Name;
192       } else {
193         printOp(MO);
194       }
195     }
196
197     void printS8ImmOperand(const MachineInstr *MI, unsigned OpNo,
198                             MVT::ValueType VT) {
199       int val=(unsigned int)MI->getOperand(OpNo).getImmedValue();
200       if(val>=128) val=val-256; // if negative, flip sign
201       O << val;
202     }
203     void printS14ImmOperand(const MachineInstr *MI, unsigned OpNo,
204                             MVT::ValueType VT) {
205       int val=(unsigned int)MI->getOperand(OpNo).getImmedValue();
206       if(val>=8192) val=val-16384; // if negative, flip sign
207       O << val;
208     }
209     void printS22ImmOperand(const MachineInstr *MI, unsigned OpNo,
210                             MVT::ValueType VT) {
211       int val=(unsigned int)MI->getOperand(OpNo).getImmedValue();
212       if(val>=2097152) val=val-4194304; // if negative, flip sign
213       O << val;
214     }
215     void printU64ImmOperand(const MachineInstr *MI, unsigned OpNo,
216                             MVT::ValueType VT) {
217       O << (uint64_t)MI->getOperand(OpNo).getImmedValue();
218     }
219     void printS64ImmOperand(const MachineInstr *MI, unsigned OpNo,
220                             MVT::ValueType VT) {
221 // XXX : nasty hack to avoid GPREL22 "relocation truncated to fit" linker
222 // errors - instead of add rX = @gprel(CPI<whatever>), r1;; we now
223 // emit movl rX = @gprel(CPI<whatever);;
224 //      add  rX = rX, r1; 
225 // this gives us 64 bits instead of 22 (for the add long imm) to play
226 // with, which shuts up the linker. The problem is that the constant
227 // pool entries aren't immediates at this stage, so we check here. 
228 // If it's an immediate, print it the old fashioned way. If it's
229 // not, we print it as a constant pool index. 
230       if(MI->getOperand(OpNo).isImmediate()) {
231         O << (int64_t)MI->getOperand(OpNo).getImmedValue();
232       } else { // this is a constant pool reference: FIXME: assert this
233         printOp(MI->getOperand(OpNo));
234       }
235     }
236
237     void printGlobalOperand(const MachineInstr *MI, unsigned OpNo,
238                           MVT::ValueType VT) {
239       printOp(MI->getOperand(OpNo), false); // this is NOT a br.call instruction
240     }
241
242     void printCallOperand(const MachineInstr *MI, unsigned OpNo,
243                           MVT::ValueType VT) {
244       printOp(MI->getOperand(OpNo), true); // this is a br.call instruction
245     }
246
247     void printMachineInstruction(const MachineInstr *MI);
248     void printOp(const MachineOperand &MO, bool isBRCALLinsn= false);
249     bool runOnMachineFunction(MachineFunction &F);
250     bool doInitialization(Module &M);
251   };
252 } // end of anonymous namespace
253
254
255 // Include the auto-generated portion of the assembly writer.
256 #include "IA64GenAsmWriter.inc"
257
258
259 /// runOnMachineFunction - This uses the printMachineInstruction()
260 /// method to print assembly for each instruction.
261 ///
262 bool IA64AsmPrinter::runOnMachineFunction(MachineFunction &MF) {
263   setupMachineFunction(MF);
264   O << "\n\n";
265
266   // Print out constants referenced by the function
267   printConstantPool(MF.getConstantPool());
268
269   // Print out labels for the function.
270   SwitchSection("\n\t.section .text, \"ax\", \"progbits\"\n", MF.getFunction());
271   // ^^  means "Allocated instruXions in mem, initialized"
272   emitAlignment(5);
273   O << "\t.global\t" << CurrentFnName << "\n";
274   O << "\t.type\t" << CurrentFnName << ", @function\n";
275   O << CurrentFnName << ":\n";
276
277   // Print out code for the function.
278   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
279        I != E; ++I) {
280     // Print a label for the basic block if there are any predecessors.
281     if (I->pred_begin() != I->pred_end())
282       O << ".LBB" << CurrentFnName << "_" << I->getNumber() << ":\t"
283         << CommentString << " " << I->getBasicBlock()->getName() << "\n";
284     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
285          II != E; ++II) {
286       // Print the assembly for the instruction.
287       O << "\t";
288       printMachineInstruction(II);
289     }
290   }
291
292   // We didn't modify anything.
293   return false;
294 }
295
296 void IA64AsmPrinter::printOp(const MachineOperand &MO,
297                                  bool isBRCALLinsn /* = false */) {
298   const MRegisterInfo &RI = *TM.getRegisterInfo();
299   switch (MO.getType()) {
300   case MachineOperand::MO_VirtualRegister:
301     if (Value *V = MO.getVRegValueOrNull()) {
302       O << "<" << V->getName() << ">";
303       return;
304     }
305     // FALLTHROUGH
306   case MachineOperand::MO_MachineRegister:
307   case MachineOperand::MO_CCRegister: {
308     O << RI.get(MO.getReg()).Name;
309     return;
310   }
311
312   case MachineOperand::MO_SignExtendedImmed:
313   case MachineOperand::MO_UnextendedImmed:
314     O << /*(unsigned int)*/MO.getImmedValue();
315     return;
316   case MachineOperand::MO_MachineBasicBlock: {
317     MachineBasicBlock *MBBOp = MO.getMachineBasicBlock();
318     O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction())
319       << "_" << MBBOp->getNumber () << "\t// "
320       << MBBOp->getBasicBlock ()->getName ();
321     return;
322   }
323   case MachineOperand::MO_PCRelativeDisp:
324     std::cerr << "Shouldn't use addPCDisp() when building IA64 MachineInstrs";
325     abort ();
326     return;
327
328   case MachineOperand::MO_ConstantPoolIndex: {
329     O << "@gprel(" << PrivateGlobalPrefix << "CPI" << CurrentFnName << "_"
330       << MO.getConstantPoolIndex() << ")";
331     return;
332   }
333
334   case MachineOperand::MO_GlobalAddress: {
335
336     // functions need @ltoff(@fptr(fn_name)) form
337     GlobalValue *GV = MO.getGlobal();
338     Function *F = dyn_cast<Function>(GV);
339
340     bool Needfptr=false; // if we're computing an address @ltoff(X), do
341                          // we need to decorate it so it becomes
342                          // @ltoff(@fptr(X)) ?
343     if (F && !isBRCALLinsn /*&& F->isExternal()*/)
344       Needfptr=true;
345
346     // if this is the target of a call instruction, we should define
347     // the function somewhere (GNU gas has no problem without this, but
348     // Intel ias rightly complains of an 'undefined symbol')
349
350     if (F /*&& isBRCALLinsn*/ && F->isExternal())
351       ExternalFunctionNames.insert(Mang->getValueName(MO.getGlobal()));
352     else
353       if (GV->isExternal()) // e.g. stuff like 'stdin'
354         ExternalObjectNames.insert(Mang->getValueName(MO.getGlobal()));
355
356     if (!isBRCALLinsn)
357       O << "@ltoff(";
358     if (Needfptr)
359       O << "@fptr(";
360     O << Mang->getValueName(MO.getGlobal());
361     if (Needfptr)
362       O << ")"; // close fptr(
363     if (!isBRCALLinsn)
364       O << ")"; // close ltoff(
365     int Offset = MO.getOffset();
366     if (Offset > 0)
367       O << " + " << Offset;
368     else if (Offset < 0)
369       O << " - " << -Offset;
370     return;
371   }
372   case MachineOperand::MO_ExternalSymbol:
373     O << MO.getSymbolName();
374     ExternalFunctionNames.insert(MO.getSymbolName());
375     return;
376   default:
377     O << "<AsmPrinter: unknown operand type: " << MO.getType() << " >"; return;
378   }
379 }
380
381 /// printMachineInstruction -- Print out a single IA64 LLVM instruction
382 /// MI to the current output stream.
383 ///
384 void IA64AsmPrinter::printMachineInstruction(const MachineInstr *MI) {
385   ++EmittedInsts;
386
387   // Call the autogenerated instruction printer routines.
388   printInstruction(MI);
389 }
390
391 bool IA64AsmPrinter::doInitialization(Module &M) {
392   AsmPrinter::doInitialization(M);
393
394   O << "\n.ident \"LLVM-ia64\"\n\n"
395     << "\t.psr    lsb\n"  // should be "msb" on HP-UX, for starters
396     << "\t.radix  C\n"
397     << "\t.psr    abi64\n"; // we only support 64 bits for now
398   return false;
399 }
400
401 /// createIA64CodePrinterPass - Returns a pass that prints the IA64
402 /// assembly code for a MachineFunction to the given output stream, using
403 /// the given target machine description.
404 ///
405 FunctionPass *llvm::createIA64CodePrinterPass(std::ostream &o,TargetMachine &tm){
406   return new IA64AsmPrinter(o, tm);
407 }
408
409