| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 1 | //===-- 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 Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 20 | #include "MipsMachineFunction.h" | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 21 | #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 Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 27 | #include "llvm/CodeGen/MachineFrameInfo.h" | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 28 | #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 Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 35 | #include "llvm/Support/Debug.h" | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 36 | #include "llvm/Support/CommandLine.h" | 
 | 37 | #include "llvm/Support/MathExtras.h" | 
 | 38 | #include <cctype> | 
 | 39 |  | 
 | 40 | using namespace llvm; | 
 | 41 |  | 
 | 42 | STATISTIC(EmittedInsts, "Number of machine instrs printed"); | 
 | 43 |  | 
 | 44 | namespace { | 
 | 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 Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 54 |     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 Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 61 |     void printOperand(const MachineInstr *MI, int opNum); | 
 | 62 |     void printMemOperand(const MachineInstr *MI, int opNum,  | 
 | 63 |                          const char *Modifier = 0); | 
 | 64 |  | 
| Bruno Cardoso Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 65 |     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 Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 73 |     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. | 
 | 86 | FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o, | 
 | 87 |                                               MipsTargetMachine &tm)  | 
 | 88 | { | 
 | 89 |   return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo()); | 
 | 90 | } | 
 | 91 |  | 
| Bruno Cardoso Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 92 | /// 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 | 
 | 98 | void MipsAsmPrinter:: | 
 | 99 | emitFrameDirective(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. | 
 | 121 | void MipsAsmPrinter:: | 
 | 122 | emitMaskDirective(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 | 
 | 165 | void MipsAsmPrinter:: | 
 | 166 | emitFMaskDirective() | 
 | 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 | 
 | 173 | void MipsAsmPrinter:: | 
 | 174 | printHex32(unsigned int Value) { | 
 | 175 |   O << "0x" << std::hex << Value << std::dec;   | 
 | 176 | } | 
 | 177 |  | 
 | 178 | /// Emit Set directives. | 
 | 179 | void MipsAsmPrinter:: | 
 | 180 | emitSetDirective(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 | 
 | 193 | void MipsAsmPrinter:: | 
 | 194 | emitFunctionStart(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(); | 
| Bruno Cardoso Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 212 |   emitSetDirective(NOREORDER); | 
 | 213 |   emitSetDirective(NOMACRO); | 
| Bruno Cardoso Lopes | 250a171 | 2007-08-18 02:05:24 +0000 | [diff] [blame^] | 214 |   O << "\n"; | 
| Bruno Cardoso Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 215 | } | 
 | 216 |  | 
 | 217 | /// Emit the directives used by GAS on the end of functions | 
 | 218 | void MipsAsmPrinter:: | 
 | 219 | emitFunctionEnd() { | 
 | 220 |   emitSetDirective(MACRO); | 
 | 221 |   emitSetDirective(REORDER); | 
 | 222 |   O << "\t.end\t" << CurrentFnName << "\n"; | 
 | 223 | } | 
 | 224 |  | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 225 | /// runOnMachineFunction - This uses the printMachineInstruction() | 
 | 226 | /// method to print assembly for each instruction. | 
 | 227 | bool MipsAsmPrinter:: | 
 | 228 | runOnMachineFunction(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 Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 240 |   // Emit the function start directives | 
 | 241 |   emitFunctionStart(MF); | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 242 |  | 
 | 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 Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 262 |   // Emit function end directives | 
 | 263 |   emitFunctionEnd(); | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 264 |  | 
 | 265 |   // We didn't modify anything. | 
 | 266 |   return false; | 
 | 267 | } | 
 | 268 |  | 
 | 269 | void MipsAsmPrinter:: | 
 | 270 | printOperand(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 Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 298 |           (MI->getOpcode() == Mips::LUi)   || (MI->getOpcode() == Mips::ANDi)) | 
 | 299 |         O << (unsigned short int)MO.getImmedValue(); | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 300 |       else | 
| Bruno Cardoso Lopes | a4e8200 | 2007-07-11 23:24:41 +0000 | [diff] [blame] | 301 |         O << (short int)MO.getImmedValue(); | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 302 |       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 |  | 
 | 328 | void MipsAsmPrinter:: | 
 | 329 | printMemOperand(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 |  | 
 | 340 | bool MipsAsmPrinter:: | 
 | 341 | doInitialization(Module &M)  | 
 | 342 | { | 
 | 343 |   Mang = new Mangler(M); | 
 | 344 |   return false; // success | 
 | 345 | } | 
 | 346 |  | 
 | 347 | bool MipsAsmPrinter:: | 
 | 348 | doFinalization(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 Gohman | b8275a3 | 2007-07-25 19:33:14 +0000 | [diff] [blame] | 431 |   return AsmPrinter::doFinalization(M); | 
| Bruno Cardoso Lopes | 972f589 | 2007-06-06 07:42:06 +0000 | [diff] [blame] | 432 | } |