Remove unsized array support
[oota-llvm.git] / lib / Target / SparcV9 / SparcV9AsmPrinter.cpp
1 //===-- EmitAssembly.cpp - Emit Sparc Specific .s File ---------------------==//
2 //
3 // This file implements all of the stuff neccesary to output a .s file from
4 // LLVM.  The code in this file assumes that the specified module has already
5 // been compiled into the internal data structures of the Module.
6 //
7 // The entry point of this file is the UltraSparc::emitAssembly method.
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "SparcInternals.h"
12 #include "llvm/Analysis/SlotCalculator.h"
13 #include "llvm/Transforms/Linker.h"
14 #include "llvm/CodeGen/MachineInstr.h"
15 #include "llvm/GlobalVariable.h"
16 #include "llvm/GlobalValue.h"
17 #include "llvm/ConstantVals.h"
18 #include "llvm/DerivedTypes.h"
19 #include "llvm/BasicBlock.h"
20 #include "llvm/Method.h"
21 #include "llvm/Module.h"
22 #include "Support/StringExtras.h"
23 #include "Support/HashExtras.h"
24 #include <locale.h>
25
26 namespace {
27
28
29 class SparcAsmPrinter {
30   typedef hash_map<const Value*, int> ValIdMap;
31   typedef ValIdMap::      iterator ValIdMapIterator;
32   typedef ValIdMap::const_iterator ValIdMapConstIterator;
33   
34   ostream &toAsm;
35   SlotCalculator Table;   // map anonymous values to unique integer IDs
36   ValIdMap valToIdMap;    // used for values not handled by SlotCalculator 
37   const UltraSparc &Target;
38   
39   enum Sections {
40     Unknown,
41     Text,
42     ReadOnlyData,
43     InitRWData,
44     UninitRWData,
45   } CurSection;
46   
47 public:
48   inline SparcAsmPrinter(ostream &o, const Module *M, const UltraSparc &t)
49     : toAsm(o), Table(SlotCalculator(M, true)), Target(t), CurSection(Unknown) {
50     emitModule(M);
51   }
52
53 private :
54   void emitModule(const Module *M);
55   void emitMethod(const Method *M);
56   void emitGlobalsAndConstants(const Module* module);
57   //void processMethodArgument(const MethodArgument *MA);
58   void emitBasicBlock(const BasicBlock *BB);
59   void emitMachineInst(const MachineInstr *MI);
60   
61   void printGlobalVariable(   const GlobalVariable* GV);
62   void printSingleConstant(   const Constant* CV);
63   void printConstantValueOnly(const Constant* CV);
64   void printConstant(         const Constant* CV, string valID=string(""));
65   
66   unsigned int printOperands(const MachineInstr *MI, unsigned int opNum);
67   void printOneOperand(const MachineOperand &Op);
68
69   bool OpIsBranchTargetLabel(const MachineInstr *MI, unsigned int opNum);
70   bool OpIsMemoryAddressBase(const MachineInstr *MI, unsigned int opNum);
71   
72   // enterSection - Use this method to enter a different section of the output
73   // executable.  This is used to only output neccesary section transitions.
74   //
75   void enterSection(enum Sections S) {
76     if (S == CurSection) return;        // Only switch section if neccesary
77     CurSection = S;
78
79     toAsm << "\n\t.section ";
80     switch (S)
81       {
82       default: assert(0 && "Bad section name!");
83       case Text:         toAsm << "\".text\""; break;
84       case ReadOnlyData: toAsm << "\".rodata\",#alloc"; break;
85       case InitRWData:   toAsm << "\".data\",#alloc,#write"; break;
86       case UninitRWData: toAsm << "\".bss\",#alloc,#write\nBbss.bss:"; break;
87       }
88     toAsm << "\n";
89   }
90
91   string getValidSymbolName(const string &S) {
92     string Result;
93     
94     // Symbol names in Sparc assembly language have these rules:
95     // (a) Must match { letter | _ | . | $ } { letter | _ | . | $ | digit }*
96     // (b) A name beginning in "." is treated as a local name.
97     // (c) Names beginning with "_" are reserved by ANSI C and shd not be used.
98     // 
99     if (S[0] == '_' || isdigit(S[0]))
100       Result += "ll";
101     
102     for (unsigned i = 0; i < S.size(); ++i)
103       {
104         char C = S[i];
105         if (C == '_' || C == '.' || C == '$' || isalpha(C) || isdigit(C))
106           Result += C;
107         else
108           {
109             Result += '_';
110             Result += char('0' + ((unsigned char)C >> 4));
111             Result += char('0' + (C & 0xF));
112           }
113       }
114     return Result;
115   }
116
117   // getID - Return a valid identifier for the specified value.  Base it on
118   // the name of the identifier if possible, use a numbered value based on
119   // prefix otherwise.  FPrefix is always prepended to the output identifier.
120   //
121   string getID(const Value *V, const char *Prefix, const char *FPrefix = 0) {
122     string Result;
123     string FP(FPrefix ? FPrefix : "");  // "Forced prefix"
124     if (V->hasName()) {
125       Result = FP + V->getName();
126     } else {
127       int valId = Table.getValSlot(V);
128       if (valId == -1) {
129         ValIdMapConstIterator I = valToIdMap.find(V);
130         valId = (I == valToIdMap.end())? (valToIdMap[V] = valToIdMap.size())
131                                        : (*I).second;
132       }
133       Result = FP + string(Prefix) + itostr(valId);
134     }
135     return getValidSymbolName(Result);
136   }
137   
138   // getID Wrappers - Ensure consistent usage...
139   string getID(const Module *M) {
140     return getID(M, "LLVMModule_");
141   }
142   string getID(const Method *M) {
143     return getID(M, "LLVMMethod_");
144   }
145   string getID(const BasicBlock *BB) {
146     return getID(BB, "LL", (".L_"+getID(BB->getParent())+"_").c_str());
147   }
148   string getID(const GlobalVariable *GV) {
149     return getID(GV, "LLVMGlobal_", ".G_");
150   }
151   string getID(const Constant *CV) {
152     return getID(CV, "LLVMConst_", ".C_");
153   }
154   
155   unsigned getOperandMask(unsigned Opcode) {
156     switch (Opcode) {
157     case SUBcc:   return 1 << 3;  // Remove CC argument
158     case BA:      return 1 << 0;  // Remove Arg #0, which is always null or xcc
159     default:      return 0;       // By default, don't hack operands...
160     }
161   }
162 };
163
164
165 // Can we treat the specified array as a string?  Only if it is an array of
166 // ubytes or non-negative sbytes.
167 //
168 static bool isStringCompatible(ConstantArray *CPA) {
169   const Type *ETy = cast<ArrayType>(CPA->getType())->getElementType();
170   if (ETy == Type::UByteTy) return true;
171   if (ETy != Type::SByteTy) return false;
172
173   for (unsigned i = 0; i < CPA->getNumOperands(); ++i)
174     if (cast<ConstantSInt>(CPA->getOperand(i))->getValue() < 0)
175       return false;
176
177   return true;
178 }
179
180 // toOctal - Convert the low order bits of X into an octal letter
181 static inline char toOctal(int X) {
182   return (X&7)+'0';
183 }
184
185 // getAsCString - Return the specified array as a C compatible string, only if
186 // the predicate isStringCompatible is true.
187 //
188 static string getAsCString(ConstantArray *CPA) {
189   if (isStringCompatible(CPA)) {
190     string Result;
191     const Type *ETy = cast<ArrayType>(CPA->getType())->getElementType();
192     Result = "\"";
193     for (unsigned i = 0; i < CPA->getNumOperands(); ++i) {
194       unsigned char C = (ETy == Type::SByteTy) ?
195         (unsigned char)cast<ConstantSInt>(CPA->getOperand(i))->getValue() :
196         (unsigned char)cast<ConstantUInt>(CPA->getOperand(i))->getValue();
197
198       if (isprint(C)) {
199         Result += C;
200       } else {
201         switch(C) {
202         case '\a': Result += "\\a"; break;
203         case '\b': Result += "\\b"; break;
204         case '\f': Result += "\\f"; break;
205         case '\n': Result += "\\n"; break;
206         case '\r': Result += "\\r"; break;
207         case '\t': Result += "\\t"; break;
208         case '\v': Result += "\\v"; break;
209         default:
210           Result += '\\';
211           Result += toOctal(C >> 6);
212           Result += toOctal(C >> 3);
213           Result += toOctal(C >> 0);
214           break;
215         }
216       }
217     }
218     Result += "\"";
219
220     return Result;
221   } else {
222     return CPA->getStrValue();
223   }
224 }
225
226
227 inline bool
228 SparcAsmPrinter::OpIsBranchTargetLabel(const MachineInstr *MI,
229                                        unsigned int opNum) {
230   switch (MI->getOpCode()) {
231   case JMPLCALL:
232   case JMPLRET: return (opNum == 0);
233   default:      return false;
234   }
235 }
236
237
238 inline bool
239 SparcAsmPrinter::OpIsMemoryAddressBase(const MachineInstr *MI,
240                                        unsigned int opNum) {
241   if (Target.getInstrInfo().isLoad(MI->getOpCode()))
242     return (opNum == 0);
243   else if (Target.getInstrInfo().isStore(MI->getOpCode()))
244     return (opNum == 1);
245   else
246     return false;
247 }
248
249
250 #define PrintOp1PlusOp2(Op1, Op2) \
251   printOneOperand(Op1); \
252   toAsm << "+"; \
253   printOneOperand(Op2);
254
255 unsigned int
256 SparcAsmPrinter::printOperands(const MachineInstr *MI,
257                                unsigned int opNum)
258 {
259   const MachineOperand& Op = MI->getOperand(opNum);
260   
261   if (OpIsBranchTargetLabel(MI, opNum))
262     {
263       PrintOp1PlusOp2(Op, MI->getOperand(opNum+1));
264       return 2;
265     }
266   else if (OpIsMemoryAddressBase(MI, opNum))
267     {
268       toAsm << "[";
269       PrintOp1PlusOp2(Op, MI->getOperand(opNum+1));
270       toAsm << "]";
271       return 2;
272     }
273   else
274     {
275       printOneOperand(Op);
276       return 1;
277     }
278 }
279
280
281 void
282 SparcAsmPrinter::printOneOperand(const MachineOperand &op)
283 {
284   switch (op.getOperandType())
285     {
286     case MachineOperand::MO_VirtualRegister:
287     case MachineOperand::MO_CCRegister:
288     case MachineOperand::MO_MachineRegister:
289       {
290         int RegNum = (int)op.getAllocatedRegNum();
291         
292         // ****this code is temporary till NULL Values are fixed
293         if (RegNum == Target.getRegInfo().getInvalidRegNum()) {
294           toAsm << "<NULL VALUE>";
295         } else {
296           toAsm << "%" << Target.getRegInfo().getUnifiedRegName(RegNum);
297         }
298         break;
299       }
300     
301     case MachineOperand::MO_PCRelativeDisp:
302       {
303         const Value *Val = op.getVRegValue();
304         if (!Val)
305           toAsm << "\t<*NULL Value*>";
306         else if (const BasicBlock *BB = dyn_cast<const BasicBlock>(Val))
307           toAsm << getID(BB);
308         else if (const Method *M = dyn_cast<const Method>(Val))
309           toAsm << getID(M);
310         else if (const GlobalVariable *GV=dyn_cast<const GlobalVariable>(Val))
311           toAsm << getID(GV);
312         else if (const Constant *CV = dyn_cast<const Constant>(Val))
313           toAsm << getID(CV);
314         else
315           toAsm << "<unknown value=" << Val << ">";
316         break;
317       }
318     
319     case MachineOperand::MO_SignExtendedImmed:
320     case MachineOperand::MO_UnextendedImmed:
321       toAsm << op.getImmedValue();
322       break;
323     
324     default:
325       toAsm << op;      // use dump field
326       break;
327     }
328 }
329
330
331 void
332 SparcAsmPrinter::emitMachineInst(const MachineInstr *MI)
333 {
334   unsigned Opcode = MI->getOpCode();
335
336   if (TargetInstrDescriptors[Opcode].iclass & M_DUMMY_PHI_FLAG)
337     return;  // IGNORE PHI NODES
338
339   toAsm << "\t" << TargetInstrDescriptors[Opcode].opCodeString << "\t";
340
341   unsigned Mask = getOperandMask(Opcode);
342   
343   bool NeedComma = false;
344   unsigned N = 1;
345   for (unsigned OpNum = 0; OpNum < MI->getNumOperands(); OpNum += N)
346     if (! ((1 << OpNum) & Mask)) {        // Ignore this operand?
347       if (NeedComma) toAsm << ", ";         // Handle comma outputing
348       NeedComma = true;
349       N = printOperands(MI, OpNum);
350     }
351   else
352     N = 1;
353   
354   toAsm << endl;
355 }
356
357 void
358 SparcAsmPrinter::emitBasicBlock(const BasicBlock *BB)
359 {
360   // Emit a label for the basic block
361   toAsm << getID(BB) << ":\n";
362
363   // Get the vector of machine instructions corresponding to this bb.
364   const MachineCodeForBasicBlock &MIs = BB->getMachineInstrVec();
365   MachineCodeForBasicBlock::const_iterator MII = MIs.begin(), MIE = MIs.end();
366
367   // Loop over all of the instructions in the basic block...
368   for (; MII != MIE; ++MII)
369     emitMachineInst(*MII);
370   toAsm << "\n";  // Seperate BB's with newlines
371 }
372
373 void
374 SparcAsmPrinter::emitMethod(const Method *M)
375 {
376   if (M->isExternal()) return;
377
378   // Make sure the slot table has information about this method...
379   Table.incorporateMethod(M);
380
381   string methName = getID(M);
382   toAsm << "!****** Outputing Method: " << methName << " ******\n";
383   enterSection(Text);
384   toAsm << "\t.align\t4\n\t.global\t" << methName << "\n";
385   //toAsm << "\t.type\t" << methName << ",#function\n";
386   toAsm << "\t.type\t" << methName << ", 2\n";
387   toAsm << methName << ":\n";
388
389   // Output code for all of the basic blocks in the method...
390   for (Method::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
391     emitBasicBlock(*I);
392
393   // Output a .size directive so the debugger knows the extents of the function
394   toAsm << ".EndOf_" << methName << ":\n\t.size "
395         << methName << ", .EndOf_"
396         << methName << "-" << methName << endl;
397
398   // Put some spaces between the methods
399   toAsm << "\n\n";
400
401   // Forget all about M.
402   Table.purgeMethod();
403 }
404
405 inline bool
406 ArrayTypeIsString(ArrayType* arrayType)
407 {
408   return (arrayType->getElementType() == Type::UByteTy ||
409           arrayType->getElementType() == Type::SByteTy);
410 }
411
412 inline const string
413 TypeToDataDirective(const Type* type)
414 {
415   switch(type->getPrimitiveID())
416     {
417     case Type::BoolTyID: case Type::UByteTyID: case Type::SByteTyID:
418       return ".byte";
419     case Type::UShortTyID: case Type::ShortTyID:
420       return ".half";
421     case Type::UIntTyID: case Type::IntTyID:
422       return ".word";
423     case Type::ULongTyID: case Type::LongTyID: case Type::PointerTyID:
424       return ".xword";
425     case Type::FloatTyID:
426       return ".single";
427     case Type::DoubleTyID:
428       return ".double";
429     case Type::ArrayTyID:
430       if (ArrayTypeIsString((ArrayType*) type))
431         return ".ascii";
432       else
433         return "<InvaliDataTypeForPrinting>";
434     default:
435       return "<InvaliDataTypeForPrinting>";
436     }
437 }
438
439 // Get the size of the constant for the given target.
440 // If this is an unsized array, return 0.
441 // 
442 inline unsigned int
443 ConstantToSize(const Constant* CV, const TargetMachine& target)
444 {
445   if (ConstantArray* CPA = dyn_cast<ConstantArray>(CV))
446     {
447       ArrayType *aty = cast<ArrayType>(CPA->getType());
448       if (ArrayTypeIsString(aty))
449         return 1 + CPA->getNumOperands();
450     }
451   
452   return target.findOptimalStorageSize(CV->getType());
453 }
454
455 inline
456 unsigned int TypeToSize(const Type* type, const TargetMachine& target)
457 {
458   return target.findOptimalStorageSize(type);
459 }
460
461
462 // Align data larger than one L1 cache line on L1 cache line boundaries.
463 // Align all smaller data on the next higher 2^x boundary (4, 8, ...).
464 // 
465 inline unsigned int
466 SizeToAlignment(unsigned int size, const TargetMachine& target)
467 {
468   unsigned short cacheLineSize = target.getCacheInfo().getCacheLineSize(1); 
469   if (size > (unsigned) cacheLineSize / 2)
470     return cacheLineSize;
471   else
472     for (unsigned sz=1; /*no condition*/; sz *= 2)
473       if (sz >= size)
474         return sz;
475 }
476
477 // Get the size of the type and then use SizeToAlignment.
478 // 
479 inline unsigned int
480 TypeToAlignment(const Type* type, const TargetMachine& target)
481 {
482   return SizeToAlignment(target.findOptimalStorageSize(type), target);
483 }
484
485 // Get the size of the constant and then use SizeToAlignment.
486 // Handles strings as a special case;
487 inline unsigned int
488 ConstantToAlignment(const Constant* CV, const TargetMachine& target)
489 {
490   unsigned int constantSize;
491   if (ConstantArray* CPA = dyn_cast<ConstantArray>(CV))
492     if (ArrayTypeIsString(cast<ArrayType>(CPA->getType())))
493       return SizeToAlignment(1 + CPA->getNumOperands(), target);
494   
495   return TypeToAlignment(CV->getType(), target);
496 }
497
498
499 // Print a single constant value.
500 void
501 SparcAsmPrinter::printSingleConstant(const Constant* CV)
502 {
503   assert(CV->getType() != Type::VoidTy &&
504          CV->getType() != Type::TypeTy &&
505          CV->getType() != Type::LabelTy &&
506          "Unexpected type for Constant");
507   
508   assert((! isa<ConstantArray>( CV) && ! isa<ConstantStruct>(CV))
509          && "Collective types should be handled outside this function");
510   
511   toAsm << "\t"
512         << TypeToDataDirective(CV->getType()) << "\t";
513   
514   if (CV->getType()->isPrimitiveType())
515     {
516       if (CV->getType() == Type::FloatTy || CV->getType() == Type::DoubleTy)
517         toAsm << "0r";                  // FP constants must have this prefix
518       toAsm << CV->getStrValue() << endl;
519     }
520   else if (ConstantPointer* CPP = dyn_cast<ConstantPointer>(CV))
521     {
522       if (! CPP->isNullValue())
523         assert(0 && "Cannot yet print non-null pointer constants to assembly");
524       else
525         toAsm << (void*) NULL << endl;
526     }
527   else if (ConstantPointerRef* CPRef = dyn_cast<ConstantPointerRef>(CV))
528     {
529       assert(0 && "Cannot yet initialize pointer refs in assembly");
530     }
531   else
532     {
533       assert(0 && "Unknown elementary type for constant");
534     }
535 }
536
537 // Print a constant value or values (it may be an aggregate).
538 // Uses printSingleConstant() to print each individual value.
539 void
540 SparcAsmPrinter::printConstantValueOnly(const Constant* CV)
541 {
542   ConstantArray *CPA = dyn_cast<ConstantArray>(CV);
543   
544   if (CPA && isStringCompatible(CPA))
545     { // print the string alone and return
546       toAsm << "\t" << ".ascii" << "\t" << getAsCString(CPA) << endl;
547     }
548   else if (CPA)
549     { // Not a string.  Print the values in successive locations
550       const vector<Use>& constValues = CPA->getValues();
551       for (unsigned i=1; i < constValues.size(); i++)
552         this->printConstantValueOnly(cast<Constant>(constValues[i].get()));
553     }
554   else if (ConstantStruct *CPS = dyn_cast<ConstantStruct>(CV))
555     { // Print the fields in successive locations
556       const vector<Use>& constValues = CPS->getValues();
557       for (unsigned i=1; i < constValues.size(); i++)
558         this->printConstantValueOnly(cast<Constant>(constValues[i].get()));
559     }
560   else
561     this->printSingleConstant(CV);
562 }
563
564 // Print a constant (which may be an aggregate) prefixed by all the
565 // appropriate directives.  Uses printConstantValueOnly() to print the
566 // value or values.
567 void
568 SparcAsmPrinter::printConstant(const Constant* CV, string valID)
569 {
570   if (valID.length() == 0)
571     valID = getID(CV);
572   
573   toAsm << "\t.align\t" << ConstantToAlignment(CV, Target)
574         << endl;
575   
576   // Print .size and .type only if it is not a string.
577   ConstantArray *CPA = dyn_cast<ConstantArray>(CV);
578   if (CPA && isStringCompatible(CPA))
579     { // print it as a string and return
580       toAsm << valID << ":" << endl;
581       toAsm << "\t" << ".ascii" << "\t" << getAsCString(CPA) << endl;
582       return;
583     }
584   
585   toAsm << "\t.type" << "\t" << valID << ",#object" << endl;
586
587   unsigned int constSize = ConstantToSize(CV, Target);
588   if (constSize)
589     toAsm << "\t.size" << "\t" << valID << ","
590           << constSize << endl;
591   
592   toAsm << valID << ":" << endl;
593   
594   this->printConstantValueOnly(CV);
595 }
596
597
598 void
599 SparcAsmPrinter::printGlobalVariable(const GlobalVariable* GV)
600 {
601   toAsm << "\t.global\t" << getID(GV) << endl;
602   
603   if (GV->hasInitializer())
604     printConstant(GV->getInitializer(), getID(GV));
605   else {
606     toAsm << "\t.align\t"
607           << TypeToAlignment(GV->getType()->getElementType(), Target) << endl;
608     toAsm << "\t.type\t" << getID(GV) << ",#object" << endl;
609     toAsm << "\t.reserve\t" << getID(GV) << ","
610           << TypeToSize(GV->getType()->getElementType(), Target)
611           << endl;
612   }
613 }
614
615
616 static void
617 FoldConstants(const Module *M,
618                hash_set<const Constant*>& moduleConstants)
619 {
620   for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
621     if (! (*I)->isExternal())
622       {
623         const hash_set<const Constant*>& pool =
624           MachineCodeForMethod::get(*I).getConstantPoolValues();
625         moduleConstants.insert(pool.begin(), pool.end());
626       }
627 }
628
629
630 void
631 SparcAsmPrinter::emitGlobalsAndConstants(const Module *M)
632 {
633   // First, get the constants there were marked by the code generator for
634   // inclusion in the assembly code data area and fold them all into a
635   // single constant pool since there may be lots of duplicates.  Also,
636   // lets force these constants into the slot table so that we can get
637   // unique names for unnamed constants also.
638   // 
639   hash_set<const Constant*> moduleConstants;
640   FoldConstants(M, moduleConstants);
641   
642   // Now, emit the three data sections separately; the cost of I/O should
643   // make up for the cost of extra passes over the globals list!
644   // 
645   // Read-only data section (implies initialized)
646   for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI)
647     {
648       const GlobalVariable* GV = *GI;
649       if (GV->hasInitializer() && GV->isConstant())
650         {
651           if (GI == M->gbegin())
652             enterSection(ReadOnlyData);
653           printGlobalVariable(GV);
654         }
655   }
656   
657   for (hash_set<const Constant*>::const_iterator I = moduleConstants.begin(),
658          E = moduleConstants.end();  I != E; ++I)
659     printConstant(*I);
660   
661   // Initialized read-write data section
662   for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI)
663     {
664       const GlobalVariable* GV = *GI;
665       if (GV->hasInitializer() && ! GV->isConstant())
666         {
667           if (GI == M->gbegin())
668             enterSection(InitRWData);
669           printGlobalVariable(GV);
670         }
671   }
672
673   // Uninitialized read-write data section
674   for (Module::const_giterator GI=M->gbegin(), GE=M->gend(); GI != GE; ++GI)
675     {
676       const GlobalVariable* GV = *GI;
677       if (! GV->hasInitializer())
678         {
679           if (GI == M->gbegin())
680             enterSection(UninitRWData);
681           printGlobalVariable(GV);
682         }
683   }
684
685   toAsm << endl;
686 }
687
688
689 void
690 SparcAsmPrinter::emitModule(const Module *M)
691 {
692   // TODO: Look for a filename annotation on M to emit a .file directive
693   for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
694     emitMethod(*I);
695   
696   emitGlobalsAndConstants(M);
697 }
698
699 }  // End anonymous namespace
700
701
702 //
703 // emitAssembly - Output assembly language code (a .s file) for the specified
704 // method. The specified method must have been compiled before this may be
705 // used.
706 //
707 void
708 UltraSparc::emitAssembly(const Module *M, ostream &toAsm) const
709 {
710   SparcAsmPrinter Print(toAsm, M, *this);
711 }