| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 1 | //===-- ARMAsmPrinter.cpp - ARM LLVM assembly writer ----------------------===// | 
 | 2 | // | 
 | 3 | //                     The LLVM Compiler Infrastructure | 
 | 4 | // | 
 | 5 | // This file was developed by the "Instituto Nokia de Tecnologia" and | 
 | 6 | // is distributed under the University of Illinois Open Source | 
 | 7 | // License. See LICENSE.TXT for details. | 
 | 8 | // | 
 | 9 | //===----------------------------------------------------------------------===// | 
 | 10 | // | 
 | 11 | // This file contains a printer that converts from our internal representation | 
 | 12 | // of machine-dependent LLVM code to GAS-format ARM assembly language. | 
 | 13 | // | 
 | 14 | //===----------------------------------------------------------------------===// | 
 | 15 |  | 
| Chris Lattner | 95b2c7d | 2006-12-19 22:59:26 +0000 | [diff] [blame] | 16 | #define DEBUG_TYPE "asm-printer" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 17 | #include "ARM.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 18 | #include "ARMTargetMachine.h" | 
 | 19 | #include "ARMAddressingModes.h" | 
 | 20 | #include "ARMConstantPoolValue.h" | 
 | 21 | #include "ARMMachineFunctionInfo.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 22 | #include "llvm/Constants.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 23 | #include "llvm/Module.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 24 | #include "llvm/CodeGen/AsmPrinter.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 25 | #include "llvm/CodeGen/DwarfWriter.h" | 
| Jim Laskey | 44c3b9f | 2007-01-26 21:22:28 +0000 | [diff] [blame] | 26 | #include "llvm/CodeGen/MachineModuleInfo.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 27 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 28 | #include "llvm/CodeGen/MachineJumpTableInfo.h" | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 29 | #include "llvm/Target/TargetAsmInfo.h" | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 30 | #include "llvm/Target/TargetData.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 31 | #include "llvm/Target/TargetMachine.h" | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 32 | #include "llvm/Target/TargetOptions.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 33 | #include "llvm/ADT/Statistic.h" | 
 | 34 | #include "llvm/ADT/StringExtras.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 35 | #include "llvm/Support/Compiler.h" | 
 | 36 | #include "llvm/Support/Mangler.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 37 | #include "llvm/Support/MathExtras.h" | 
 | 38 | #include <cctype> | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 39 | #include <iostream> | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 40 | using namespace llvm; | 
 | 41 |  | 
| Chris Lattner | 95b2c7d | 2006-12-19 22:59:26 +0000 | [diff] [blame] | 42 | STATISTIC(EmittedInsts, "Number of machine instrs printed"); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 43 |  | 
| Chris Lattner | 95b2c7d | 2006-12-19 22:59:26 +0000 | [diff] [blame] | 44 | namespace { | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 45 |   struct VISIBILITY_HIDDEN ARMAsmPrinter : public AsmPrinter { | 
| Jim Laskey | a0f3d17 | 2006-09-07 22:06:40 +0000 | [diff] [blame] | 46 |     ARMAsmPrinter(std::ostream &O, TargetMachine &TM, const TargetAsmInfo *T) | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 47 |       : AsmPrinter(O, TM, T), DW(O, this, T), AFI(NULL), InCPMode(false) { | 
 | 48 |       Subtarget = &TM.getSubtarget<ARMSubtarget>(); | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 49 |     } | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 50 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 51 |     DwarfWriter DW; | 
 | 52 |  | 
 | 53 |     /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can | 
 | 54 |     /// make the right decision when printing asm code for different targets. | 
 | 55 |     const ARMSubtarget *Subtarget; | 
 | 56 |  | 
 | 57 |     /// AFI - Keep a pointer to ARMFunctionInfo for the current | 
 | 58 |     /// MachineFunction | 
 | 59 |     ARMFunctionInfo *AFI; | 
 | 60 |  | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 61 |     /// We name each basic block in a Function with a unique number, so | 
 | 62 |     /// that we can consistently refer to them later. This is cleared | 
 | 63 |     /// at the beginning of each call to runOnMachineFunction(). | 
 | 64 |     /// | 
 | 65 |     typedef std::map<const Value *, unsigned> ValueMapTy; | 
 | 66 |     ValueMapTy NumberForBB; | 
 | 67 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 68 |     /// Keeps the set of GlobalValues that require non-lazy-pointers for | 
 | 69 |     /// indirect access. | 
 | 70 |     std::set<std::string> GVNonLazyPtrs; | 
 | 71 |  | 
 | 72 |     /// Keeps the set of external function GlobalAddresses that the asm | 
 | 73 |     /// printer should generate stubs for. | 
 | 74 |     std::set<std::string> FnStubs; | 
 | 75 |  | 
 | 76 |     /// True if asm printer is printing a series of CONSTPOOL_ENTRY. | 
 | 77 |     bool InCPMode; | 
 | 78 |      | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 79 |     virtual const char *getPassName() const { | 
 | 80 |       return "ARM Assembly Printer"; | 
 | 81 |     } | 
 | 82 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 83 |     void printOperand(const MachineInstr *MI, int opNum, | 
 | 84 |                       const char *Modifier = 0); | 
 | 85 |     void printSOImmOperand(const MachineInstr *MI, int opNum); | 
 | 86 |     void printSORegOperand(const MachineInstr *MI, int opNum); | 
 | 87 |     void printAddrMode2Operand(const MachineInstr *MI, int OpNo); | 
 | 88 |     void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNo); | 
 | 89 |     void printAddrMode3Operand(const MachineInstr *MI, int OpNo); | 
 | 90 |     void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNo); | 
 | 91 |     void printAddrMode4Operand(const MachineInstr *MI, int OpNo, | 
 | 92 |                                const char *Modifier = 0); | 
 | 93 |     void printAddrMode5Operand(const MachineInstr *MI, int OpNo, | 
 | 94 |                                const char *Modifier = 0); | 
 | 95 |     void printAddrModePCOperand(const MachineInstr *MI, int OpNo, | 
 | 96 |                                 const char *Modifier = 0); | 
 | 97 |     void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNo); | 
 | 98 |     void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNo, | 
 | 99 |                                       unsigned Scale); | 
| Evan Cheng | c38f2bc | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 100 |     void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNo); | 
 | 101 |     void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNo); | 
 | 102 |     void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNo); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 103 |     void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNo); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 104 |     void printCCOperand(const MachineInstr *MI, int opNum); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 105 |     void printPCLabel(const MachineInstr *MI, int opNum); | 
 | 106 |     void printRegisterList(const MachineInstr *MI, int opNum); | 
 | 107 |     void printCPInstOperand(const MachineInstr *MI, int opNum, | 
 | 108 |                             const char *Modifier); | 
 | 109 |     void printJTBlockOperand(const MachineInstr *MI, int opNum); | 
 | 110 |  | 
 | 111 |     virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | 
 | 112 |                                  unsigned AsmVariant, const char *ExtraCode); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 113 |  | 
 | 114 |     bool printInstruction(const MachineInstr *MI);  // autogenerated. | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 115 |     void printMachineInstruction(const MachineInstr *MI); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 116 |     bool runOnMachineFunction(MachineFunction &F); | 
 | 117 |     bool doInitialization(Module &M); | 
 | 118 |     bool doFinalization(Module &M); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 119 |  | 
 | 120 |     virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { | 
 | 121 |       printDataDirective(MCPV->getType()); | 
 | 122 |  | 
 | 123 |       ARMConstantPoolValue *ACPV = (ARMConstantPoolValue*)MCPV; | 
| Lauro Ramos Venancio | 1a92d94 | 2007-01-26 19:51:32 +0000 | [diff] [blame] | 124 |       GlobalValue *GV = ACPV->getGV(); | 
| Evan Cheng | c60e76d | 2007-01-30 20:37:08 +0000 | [diff] [blame] | 125 |       std::string Name = GV ? Mang->getValueName(GV) : TAI->getGlobalPrefix(); | 
 | 126 |       if (!GV) | 
 | 127 |         Name += ACPV->getSymbol(); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 128 |       if (ACPV->isNonLazyPointer()) { | 
 | 129 |         GVNonLazyPtrs.insert(Name); | 
 | 130 |         O << TAI->getPrivateGlobalPrefix() << Name << "$non_lazy_ptr"; | 
| Evan Cheng | c60e76d | 2007-01-30 20:37:08 +0000 | [diff] [blame] | 131 |       } else if (ACPV->isStub()) { | 
 | 132 |         FnStubs.insert(Name); | 
 | 133 |         O << TAI->getPrivateGlobalPrefix() << Name << "$stub"; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 134 |       } else | 
 | 135 |         O << Name; | 
 | 136 |       if (ACPV->getPCAdjustment() != 0) | 
 | 137 |         O << "-(" << TAI->getPrivateGlobalPrefix() << "PC" | 
 | 138 |           << utostr(ACPV->getLabelId()) | 
 | 139 |           << "+" << (unsigned)ACPV->getPCAdjustment() << ")"; | 
 | 140 |       O << "\n"; | 
| Lauro Ramos Venancio | 1a92d94 | 2007-01-26 19:51:32 +0000 | [diff] [blame] | 141 |  | 
 | 142 |       // If the constant pool value is a extern weak symbol, remember to emit | 
 | 143 |       // the weak reference. | 
| Evan Cheng | c60e76d | 2007-01-30 20:37:08 +0000 | [diff] [blame] | 144 |       if (GV && GV->hasExternalWeakLinkage()) | 
| Lauro Ramos Venancio | 1a92d94 | 2007-01-26 19:51:32 +0000 | [diff] [blame] | 145 |         ExtWeakSymbols.insert(GV); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 146 |     } | 
 | 147 |      | 
 | 148 |     void getAnalysisUsage(AnalysisUsage &AU) const { | 
 | 149 |       AU.setPreservesAll(); | 
| Jim Laskey | 44c3b9f | 2007-01-26 21:22:28 +0000 | [diff] [blame] | 150 |       AU.addRequired<MachineModuleInfo>(); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 151 |     } | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 152 |   }; | 
 | 153 | } // end of anonymous namespace | 
 | 154 |  | 
 | 155 | #include "ARMGenAsmWriter.inc" | 
 | 156 |  | 
 | 157 | /// createARMCodePrinterPass - Returns a pass that prints the ARM | 
 | 158 | /// assembly code for a MachineFunction to the given output stream, | 
 | 159 | /// using the given target machine description.  This should work | 
 | 160 | /// regardless of whether the function is in SSA form. | 
 | 161 | /// | 
 | 162 | FunctionPass *llvm::createARMCodePrinterPass(std::ostream &o, | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 163 |                                              ARMTargetMachine &tm) { | 
| Jim Laskey | a0f3d17 | 2006-09-07 22:06:40 +0000 | [diff] [blame] | 164 |   return new ARMAsmPrinter(o, tm, tm.getTargetAsmInfo()); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 165 | } | 
 | 166 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 167 | /// runOnMachineFunction - This uses the printInstruction() | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 168 | /// method to print assembly for each instruction. | 
 | 169 | /// | 
 | 170 | bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 171 |   AFI = MF.getInfo<ARMFunctionInfo>(); | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 172 |  | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 173 |   if (Subtarget->isTargetDarwin()) { | 
| Jim Laskey | 44c3b9f | 2007-01-26 21:22:28 +0000 | [diff] [blame] | 174 |     DW.SetModuleInfo(&getAnalysis<MachineModuleInfo>()); | 
| Chris Lattner | 1a199de | 2006-12-21 22:59:58 +0000 | [diff] [blame] | 175 |   } | 
 | 176 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 177 |   SetupMachineFunction(MF); | 
 | 178 |   O << "\n"; | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 179 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 180 |   // NOTE: we don't print out constant pools here, they are handled as | 
 | 181 |   // instructions. | 
 | 182 |  | 
 | 183 |   O << "\n"; | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 184 |   // Print out labels for the function. | 
 | 185 |   const Function *F = MF.getFunction(); | 
 | 186 |   switch (F->getLinkage()) { | 
 | 187 |   default: assert(0 && "Unknown linkage type!"); | 
 | 188 |   case Function::InternalLinkage: | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 189 |     SwitchToTextSection("\t.text", F); | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 190 |     break; | 
 | 191 |   case Function::ExternalLinkage: | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 192 |     SwitchToTextSection("\t.text", F); | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 193 |     O << "\t.globl\t" << CurrentFnName << "\n"; | 
 | 194 |     break; | 
 | 195 |   case Function::WeakLinkage: | 
 | 196 |   case Function::LinkOnceLinkage: | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 197 |     if (Subtarget->isTargetDarwin()) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 198 |       SwitchToTextSection( | 
 | 199 |                 ".section __TEXT,__textcoal_nt,coalesced,pure_instructions", F); | 
 | 200 |       O << "\t.globl\t" << CurrentFnName << "\n"; | 
 | 201 |       O << "\t.weak_definition\t" << CurrentFnName << "\n"; | 
 | 202 |     } else { | 
 | 203 |       O << TAI->getWeakRefDirective() << CurrentFnName << "\n"; | 
 | 204 |     } | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 205 |     break; | 
 | 206 |   } | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 207 |  | 
 | 208 |   if (AFI->isThumbFunction()) { | 
 | 209 |     EmitAlignment(1, F); | 
 | 210 |     O << "\t.code\t16\n"; | 
 | 211 |     O << "\t.thumb_func\t" << CurrentFnName << "\n"; | 
 | 212 |     InCPMode = false; | 
 | 213 |   } else | 
 | 214 |     EmitAlignment(2, F); | 
 | 215 |  | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 216 |   O << CurrentFnName << ":\n"; | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 217 |   if (Subtarget->isTargetDarwin()) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 218 |     // Emit pre-function debug information. | 
 | 219 |     DW.BeginFunction(&MF); | 
 | 220 |   } | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 221 |  | 
 | 222 |   // Print out code for the function. | 
 | 223 |   for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); | 
 | 224 |        I != E; ++I) { | 
 | 225 |     // Print a label for the basic block. | 
 | 226 |     if (I != MF.begin()) { | 
 | 227 |       printBasicBlockLabel(I, true); | 
 | 228 |       O << '\n'; | 
 | 229 |     } | 
 | 230 |     for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); | 
 | 231 |          II != E; ++II) { | 
 | 232 |       // Print the assembly for the instruction. | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 233 |       printMachineInstruction(II); | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 234 |     } | 
 | 235 |   } | 
 | 236 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 237 |   if (TAI->hasDotTypeDotSizeDirective()) | 
 | 238 |     O << "\t.size " << CurrentFnName << ", .-" << CurrentFnName << "\n"; | 
 | 239 |  | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 240 |   if (Subtarget->isTargetDarwin()) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 241 |     // Emit post-function debug information. | 
 | 242 |     DW.EndFunction(); | 
 | 243 |   } | 
 | 244 |  | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 245 |   return false; | 
 | 246 | } | 
 | 247 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 248 | void ARMAsmPrinter::printOperand(const MachineInstr *MI, int opNum, | 
 | 249 |                                  const char *Modifier) { | 
 | 250 |   const MachineOperand &MO = MI->getOperand(opNum); | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 251 |   switch (MO.getType()) { | 
 | 252 |   case MachineOperand::MO_Register: | 
 | 253 |     if (MRegisterInfo::isPhysicalRegister(MO.getReg())) | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 254 |       O << TM.getRegisterInfo()->get(MO.getReg()).Name; | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 255 |     else | 
 | 256 |       assert(0 && "not implemented"); | 
 | 257 |     break; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 258 |   case MachineOperand::MO_Immediate: { | 
 | 259 |     if (!Modifier || strcmp(Modifier, "no_hash") != 0) | 
 | 260 |       O << "#"; | 
 | 261 |  | 
 | 262 |     O << (int)MO.getImmedValue(); | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 263 |     break; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 264 |   } | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 265 |   case MachineOperand::MO_MachineBasicBlock: | 
| Rafael Espindola | 687bc49 | 2006-08-24 13:45:55 +0000 | [diff] [blame] | 266 |     printBasicBlockLabel(MO.getMachineBasicBlock()); | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 267 |     return; | 
| Rafael Espindola | 84b19be | 2006-07-16 01:02:57 +0000 | [diff] [blame] | 268 |   case MachineOperand::MO_GlobalAddress: { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 269 |     bool isCallOp = Modifier && !strcmp(Modifier, "call"); | 
| Rafael Espindola | 84b19be | 2006-07-16 01:02:57 +0000 | [diff] [blame] | 270 |     GlobalValue *GV = MO.getGlobal(); | 
 | 271 |     std::string Name = Mang->getValueName(GV); | 
| Reid Spencer | 5cbf985 | 2007-01-30 20:08:39 +0000 | [diff] [blame] | 272 |     bool isExt = (GV->isDeclaration() || GV->hasWeakLinkage() || | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 273 |                   GV->hasLinkOnceLinkage()); | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 274 |     if (isExt && isCallOp && Subtarget->isTargetDarwin() && | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 275 |         TM.getRelocationModel() != Reloc::Static) { | 
 | 276 |       O << TAI->getPrivateGlobalPrefix() << Name << "$stub"; | 
 | 277 |       FnStubs.insert(Name); | 
 | 278 |     } else | 
 | 279 |       O << Name; | 
 | 280 |  | 
 | 281 |     if (GV->hasExternalWeakLinkage()) | 
| Rafael Espindola | 15404d0 | 2006-12-18 03:37:18 +0000 | [diff] [blame] | 282 |       ExtWeakSymbols.insert(GV); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 283 |     break; | 
| Rafael Espindola | 84b19be | 2006-07-16 01:02:57 +0000 | [diff] [blame] | 284 |   } | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 285 |   case MachineOperand::MO_ExternalSymbol: { | 
 | 286 |     bool isCallOp = Modifier && !strcmp(Modifier, "call"); | 
 | 287 |     std::string Name(TAI->getGlobalPrefix()); | 
 | 288 |     Name += MO.getSymbolName(); | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 289 |     if (isCallOp && Subtarget->isTargetDarwin() && | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 290 |         TM.getRelocationModel() != Reloc::Static) { | 
 | 291 |       O << TAI->getPrivateGlobalPrefix() << Name << "$stub"; | 
 | 292 |       FnStubs.insert(Name); | 
 | 293 |     } else | 
 | 294 |       O << Name; | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 295 |     break; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 296 |   } | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 297 |   case MachineOperand::MO_ConstantPoolIndex: | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 298 |     O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() | 
| Rafael Espindola | 06c1e7e | 2006-08-01 12:58:43 +0000 | [diff] [blame] | 299 |       << '_' << MO.getConstantPoolIndex(); | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 300 |     break; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 301 |   case MachineOperand::MO_JumpTableIndex: | 
 | 302 |     O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() | 
 | 303 |       << '_' << MO.getJumpTableIndex(); | 
 | 304 |     break; | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 305 |   default: | 
 | 306 |     O << "<unknown operand type>"; abort (); break; | 
 | 307 |   } | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 308 | } | 
 | 309 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 310 | /// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit | 
 | 311 | /// immediate in bits 0-7. | 
 | 312 | void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum) { | 
 | 313 |   const MachineOperand &MO = MI->getOperand(OpNum); | 
 | 314 |   assert(MO.isImmediate() && (MO.getImmedValue() < (1 << 12)) && | 
 | 315 |          "Not a valid so_imm value!"); | 
 | 316 |   unsigned Imm = ARM_AM::getSOImmValImm(MO.getImmedValue()); | 
 | 317 |   unsigned Rot = ARM_AM::getSOImmValRot(MO.getImmedValue()); | 
 | 318 |    | 
 | 319 |   // Print low-level immediate formation info, per | 
 | 320 |   // A5.1.3: "Data-processing operands - Immediate". | 
 | 321 |   if (Rot) { | 
 | 322 |     O << "#" << Imm << ", " << Rot; | 
 | 323 |     // Pretty printed version. | 
 | 324 |     O << ' ' << TAI->getCommentString() << ' ' << (int)ARM_AM::rotr32(Imm, Rot); | 
 | 325 |   } else { | 
 | 326 |     O << "#" << Imm; | 
 | 327 |   } | 
 | 328 | } | 
 | 329 |  | 
 | 330 | // so_reg is a 4-operand unit corresponding to register forms of the A5.1 | 
 | 331 | // "Addressing Mode 1 - Data-processing operands" forms.  This includes: | 
 | 332 | //    REG 0   0    - e.g. R5 | 
 | 333 | //    REG REG 0,SH_OPC     - e.g. R5, ROR R3 | 
 | 334 | //    REG 0   IMM,SH_OPC  - e.g. R5, LSL #3 | 
 | 335 | void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op) { | 
 | 336 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 337 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 338 |   const MachineOperand &MO3 = MI->getOperand(Op+2); | 
 | 339 |  | 
 | 340 |   assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); | 
 | 341 |   O << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 342 |  | 
 | 343 |   // Print the shift opc. | 
 | 344 |   O << ", " | 
 | 345 |     << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImmedValue())) | 
 | 346 |     << " "; | 
 | 347 |  | 
 | 348 |   if (MO2.getReg()) { | 
 | 349 |     assert(MRegisterInfo::isPhysicalRegister(MO2.getReg())); | 
 | 350 |     O << TM.getRegisterInfo()->get(MO2.getReg()).Name; | 
 | 351 |     assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); | 
 | 352 |   } else { | 
 | 353 |     O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); | 
 | 354 |   } | 
 | 355 | } | 
 | 356 |  | 
 | 357 | void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op) { | 
 | 358 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 359 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 360 |   const MachineOperand &MO3 = MI->getOperand(Op+2); | 
 | 361 |  | 
 | 362 |   if (!MO1.isRegister()) {   // FIXME: This is for CP entries, but isn't right. | 
 | 363 |     printOperand(MI, Op); | 
 | 364 |     return; | 
 | 365 |   } | 
 | 366 |  | 
 | 367 |   O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 368 |  | 
 | 369 |   if (!MO2.getReg()) { | 
 | 370 |     if (ARM_AM::getAM2Offset(MO3.getImm()))  // Don't print +0. | 
 | 371 |       O << ", #" | 
 | 372 |         << (char)ARM_AM::getAM2Op(MO3.getImm()) | 
 | 373 |         << ARM_AM::getAM2Offset(MO3.getImm()); | 
 | 374 |     O << "]"; | 
 | 375 |     return; | 
 | 376 |   } | 
 | 377 |  | 
 | 378 |   O << ", " | 
 | 379 |     << (char)ARM_AM::getAM2Op(MO3.getImm()) | 
 | 380 |     << TM.getRegisterInfo()->get(MO2.getReg()).Name; | 
 | 381 |    | 
 | 382 |   if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) | 
 | 383 |     O << ", " | 
 | 384 |       << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImmedValue())) | 
 | 385 |       << " #" << ShImm; | 
 | 386 |   O << "]"; | 
 | 387 | } | 
 | 388 |  | 
 | 389 | void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op){ | 
 | 390 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 391 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 392 |  | 
 | 393 |   if (!MO1.getReg()) { | 
 | 394 |     if (ARM_AM::getAM2Offset(MO2.getImm()))  // Don't print +0. | 
 | 395 |       O << "#" | 
 | 396 |         << (char)ARM_AM::getAM2Op(MO2.getImm()) | 
 | 397 |         << ARM_AM::getAM2Offset(MO2.getImm()); | 
 | 398 |     return; | 
 | 399 |   } | 
 | 400 |  | 
 | 401 |   O << (char)ARM_AM::getAM2Op(MO2.getImm()) | 
 | 402 |     << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 403 |    | 
 | 404 |   if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) | 
 | 405 |     O << ", " | 
 | 406 |       << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImmedValue())) | 
 | 407 |       << " #" << ShImm; | 
 | 408 | } | 
 | 409 |  | 
 | 410 | void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op) { | 
 | 411 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 412 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 413 |   const MachineOperand &MO3 = MI->getOperand(Op+2); | 
 | 414 |    | 
 | 415 |   assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); | 
 | 416 |   O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 417 |  | 
 | 418 |   if (MO2.getReg()) { | 
 | 419 |     O << ", " | 
 | 420 |       << (char)ARM_AM::getAM3Op(MO3.getImm()) | 
 | 421 |       << TM.getRegisterInfo()->get(MO2.getReg()).Name | 
 | 422 |       << "]"; | 
 | 423 |     return; | 
 | 424 |   } | 
 | 425 |    | 
 | 426 |   if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) | 
 | 427 |     O << ", #" | 
 | 428 |       << (char)ARM_AM::getAM3Op(MO3.getImm()) | 
 | 429 |       << ImmOffs; | 
 | 430 |   O << "]"; | 
 | 431 | } | 
 | 432 |  | 
 | 433 | void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op){ | 
 | 434 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 435 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 436 |  | 
 | 437 |   if (MO1.getReg()) { | 
 | 438 |     O << (char)ARM_AM::getAM3Op(MO2.getImm()) | 
 | 439 |       << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 440 |     return; | 
 | 441 |   } | 
 | 442 |  | 
 | 443 |   unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); | 
 | 444 |   O << "#" | 
 | 445 |   << (char)ARM_AM::getAM3Op(MO2.getImm()) | 
 | 446 |     << ImmOffs; | 
 | 447 | } | 
 | 448 |    | 
 | 449 | void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op, | 
 | 450 |                                           const char *Modifier) { | 
 | 451 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 452 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 453 |   ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); | 
 | 454 |   if (Modifier && strcmp(Modifier, "submode") == 0) { | 
 | 455 |     if (MO1.getReg() == ARM::SP) { | 
 | 456 |       bool isLDM = (MI->getOpcode() == ARM::LDM || | 
 | 457 |                     MI->getOpcode() == ARM::LDM_RET); | 
 | 458 |       O << ARM_AM::getAMSubModeAltStr(Mode, isLDM); | 
 | 459 |     } else | 
 | 460 |       O << ARM_AM::getAMSubModeStr(Mode); | 
 | 461 |   } else { | 
 | 462 |     printOperand(MI, Op); | 
 | 463 |     if (ARM_AM::getAM4WBFlag(MO2.getImm())) | 
 | 464 |       O << "!"; | 
 | 465 |   } | 
 | 466 | } | 
 | 467 |  | 
 | 468 | void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op, | 
 | 469 |                                           const char *Modifier) { | 
 | 470 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 471 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 472 |  | 
 | 473 |   if (!MO1.isRegister()) {   // FIXME: This is for CP entries, but isn't right. | 
 | 474 |     printOperand(MI, Op); | 
 | 475 |     return; | 
 | 476 |   } | 
 | 477 |    | 
 | 478 |   assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); | 
 | 479 |  | 
 | 480 |   if (Modifier && strcmp(Modifier, "submode") == 0) { | 
 | 481 |     ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm()); | 
 | 482 |     if (MO1.getReg() == ARM::SP) { | 
 | 483 |       bool isFLDM = (MI->getOpcode() == ARM::FLDMD || | 
 | 484 |                      MI->getOpcode() == ARM::FLDMS); | 
 | 485 |       O << ARM_AM::getAMSubModeAltStr(Mode, isFLDM); | 
 | 486 |     } else | 
 | 487 |       O << ARM_AM::getAMSubModeStr(Mode); | 
 | 488 |     return; | 
 | 489 |   } else if (Modifier && strcmp(Modifier, "base") == 0) { | 
 | 490 |     // Used for FSTM{D|S} and LSTM{D|S} operations. | 
 | 491 |     O << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 492 |     if (ARM_AM::getAM5WBFlag(MO2.getImm())) | 
 | 493 |       O << "!"; | 
 | 494 |     return; | 
 | 495 |   } | 
 | 496 |    | 
 | 497 |   O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 498 |    | 
 | 499 |   if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { | 
 | 500 |     O << ", #" | 
 | 501 |       << (char)ARM_AM::getAM5Op(MO2.getImm()) | 
 | 502 |       << ImmOffs*4; | 
 | 503 |   } | 
 | 504 |   O << "]"; | 
 | 505 | } | 
 | 506 |  | 
 | 507 | void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, | 
 | 508 |                                            const char *Modifier) { | 
 | 509 |   if (Modifier && strcmp(Modifier, "label") == 0) { | 
 | 510 |     printPCLabel(MI, Op+1); | 
 | 511 |     return; | 
 | 512 |   } | 
 | 513 |  | 
 | 514 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 515 |   assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); | 
 | 516 |   O << "[pc, +" << TM.getRegisterInfo()->get(MO1.getReg()).Name << "]"; | 
 | 517 | } | 
 | 518 |  | 
 | 519 | void | 
 | 520 | ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op) { | 
 | 521 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 522 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 523 |   O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 524 |   O << ", " << TM.getRegisterInfo()->get(MO2.getReg()).Name << "]"; | 
 | 525 | } | 
 | 526 |  | 
 | 527 | void | 
 | 528 | ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op, | 
 | 529 |                                             unsigned Scale) { | 
 | 530 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
| Evan Cheng | cea117d | 2007-01-30 02:35:32 +0000 | [diff] [blame] | 531 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 532 |   const MachineOperand &MO3 = MI->getOperand(Op+2); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 533 |  | 
 | 534 |   if (!MO1.isRegister()) {   // FIXME: This is for CP entries, but isn't right. | 
 | 535 |     printOperand(MI, Op); | 
 | 536 |     return; | 
 | 537 |   } | 
 | 538 |  | 
 | 539 |   O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
| Evan Cheng | cea117d | 2007-01-30 02:35:32 +0000 | [diff] [blame] | 540 |   if (MO3.getReg()) | 
 | 541 |     O << ", " << TM.getRegisterInfo()->get(MO3.getReg()).Name; | 
 | 542 |   else if (unsigned ImmOffs = MO2.getImm()) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 543 |     O << ", #" << ImmOffs; | 
 | 544 |     if (Scale > 1) | 
 | 545 |       O << " * " << Scale; | 
 | 546 |   } | 
 | 547 |   O << "]"; | 
 | 548 | } | 
 | 549 |  | 
 | 550 | void | 
| Evan Cheng | c38f2bc | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 551 | ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op) { | 
| Evan Cheng | cea117d | 2007-01-30 02:35:32 +0000 | [diff] [blame] | 552 |   printThumbAddrModeRI5Operand(MI, Op, 1); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 553 | } | 
 | 554 | void | 
| Evan Cheng | c38f2bc | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 555 | ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op) { | 
| Evan Cheng | cea117d | 2007-01-30 02:35:32 +0000 | [diff] [blame] | 556 |   printThumbAddrModeRI5Operand(MI, Op, 2); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 557 | } | 
 | 558 | void | 
| Evan Cheng | c38f2bc | 2007-01-23 22:59:13 +0000 | [diff] [blame] | 559 | ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op) { | 
| Evan Cheng | cea117d | 2007-01-30 02:35:32 +0000 | [diff] [blame] | 560 |   printThumbAddrModeRI5Operand(MI, Op, 4); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 561 | } | 
 | 562 |  | 
 | 563 | void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op) { | 
 | 564 |   const MachineOperand &MO1 = MI->getOperand(Op); | 
 | 565 |   const MachineOperand &MO2 = MI->getOperand(Op+1); | 
 | 566 |   O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; | 
 | 567 |   if (unsigned ImmOffs = MO2.getImm()) | 
 | 568 |     O << ", #" << ImmOffs << " * 4"; | 
 | 569 |   O << "]"; | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 570 | } | 
 | 571 |  | 
 | 572 | void ARMAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) { | 
| Rafael Espindola | 6f602de | 2006-08-24 16:13:15 +0000 | [diff] [blame] | 573 |   int CC = (int)MI->getOperand(opNum).getImmedValue(); | 
 | 574 |   O << ARMCondCodeToString((ARMCC::CondCodes)CC); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 575 | } | 
 | 576 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 577 | void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int opNum) { | 
 | 578 |   int Id = (int)MI->getOperand(opNum).getImmedValue(); | 
 | 579 |   O << TAI->getPrivateGlobalPrefix() << "PC" << Id; | 
 | 580 | } | 
 | 581 |  | 
 | 582 | void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int opNum) { | 
 | 583 |   O << "{"; | 
 | 584 |   for (unsigned i = opNum, e = MI->getNumOperands(); i != e; ++i) { | 
 | 585 |     printOperand(MI, i); | 
 | 586 |     if (i != e-1) O << ", "; | 
 | 587 |   } | 
 | 588 |   O << "}"; | 
 | 589 | } | 
 | 590 |  | 
 | 591 | void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNo, | 
 | 592 |                                        const char *Modifier) { | 
 | 593 |   assert(Modifier && "This operand only works with a modifier!"); | 
 | 594 |   // There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the | 
 | 595 |   // data itself. | 
 | 596 |   if (!strcmp(Modifier, "label")) { | 
 | 597 |     unsigned ID = MI->getOperand(OpNo).getImm(); | 
 | 598 |     O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() | 
 | 599 |       << '_' << ID << ":\n"; | 
 | 600 |   } else { | 
 | 601 |     assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE"); | 
 | 602 |     unsigned CPI = MI->getOperand(OpNo).getConstantPoolIndex(); | 
 | 603 |  | 
 | 604 |     const MachineConstantPoolEntry &MCPE =  // Chasing pointers is fun? | 
 | 605 |       MI->getParent()->getParent()->getConstantPool()->getConstants()[CPI]; | 
 | 606 |      | 
 | 607 |     if (MCPE.isMachineConstantPoolEntry()) | 
 | 608 |       EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); | 
 | 609 |     else | 
 | 610 |       EmitGlobalConstant(MCPE.Val.ConstVal); | 
 | 611 |   } | 
 | 612 | } | 
 | 613 |  | 
 | 614 | void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNo) { | 
 | 615 |   const MachineOperand &MO1 = MI->getOperand(OpNo); | 
 | 616 |   const MachineOperand &MO2 = MI->getOperand(OpNo+1); // Unique Id | 
 | 617 |   unsigned JTI = MO1.getJumpTableIndex(); | 
 | 618 |   O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() | 
 | 619 |     << '_' << JTI << '_' << MO2.getImmedValue() << ":\n"; | 
 | 620 |  | 
 | 621 |   const char *JTEntryDirective = TAI->getJumpTableDirective(); | 
 | 622 |   if (!JTEntryDirective) | 
 | 623 |     JTEntryDirective = TAI->getData32bitsDirective(); | 
 | 624 |  | 
 | 625 |   const MachineFunction *MF = MI->getParent()->getParent(); | 
 | 626 |   MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); | 
 | 627 |   const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); | 
 | 628 |   const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; | 
 | 629 |   bool UseSet= TAI->getSetDirective() && TM.getRelocationModel() == Reloc::PIC_; | 
 | 630 |   std::set<MachineBasicBlock*> JTSets; | 
 | 631 |   for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { | 
 | 632 |     MachineBasicBlock *MBB = JTBBs[i]; | 
 | 633 |     if (UseSet && JTSets.insert(MBB).second) | 
 | 634 |       printSetLabel(JTI, MO2.getImmedValue(), MBB); | 
 | 635 |  | 
 | 636 |     O << JTEntryDirective << ' '; | 
 | 637 |     if (UseSet) | 
 | 638 |       O << TAI->getPrivateGlobalPrefix() << getFunctionNumber() | 
 | 639 |         << '_' << JTI << '_' << MO2.getImmedValue() | 
 | 640 |         << "_set_" << MBB->getNumber(); | 
 | 641 |     else if (TM.getRelocationModel() == Reloc::PIC_) { | 
 | 642 |       printBasicBlockLabel(MBB, false, false); | 
 | 643 |       // If the arch uses custom Jump Table directives, don't calc relative to JT | 
 | 644 |       if (!TAI->getJumpTableDirective())  | 
 | 645 |         O << '-' << TAI->getPrivateGlobalPrefix() << "JTI" | 
 | 646 |           << getFunctionNumber() << '_' << JTI << '_' << MO2.getImmedValue(); | 
 | 647 |     } else | 
 | 648 |       printBasicBlockLabel(MBB, false, false); | 
| Evan Cheng | d85ac4d | 2007-01-27 02:29:45 +0000 | [diff] [blame] | 649 |     if (i != e-1) | 
 | 650 |       O << '\n'; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 651 |   } | 
 | 652 | } | 
 | 653 |  | 
 | 654 |  | 
 | 655 | bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | 
 | 656 |                                     unsigned AsmVariant, const char *ExtraCode){ | 
 | 657 |   // Does this asm operand have a single letter operand modifier? | 
 | 658 |   if (ExtraCode && ExtraCode[0]) { | 
 | 659 |     if (ExtraCode[1] != 0) return true; // Unknown modifier. | 
 | 660 |      | 
 | 661 |     switch (ExtraCode[0]) { | 
 | 662 |     default: return true;  // Unknown modifier. | 
 | 663 |     case 'Q': | 
 | 664 |       if (TM.getTargetData()->isLittleEndian()) | 
 | 665 |         break; | 
 | 666 |       // Fallthrough | 
 | 667 |     case 'R': | 
 | 668 |       if (TM.getTargetData()->isBigEndian()) | 
 | 669 |         break; | 
 | 670 |       // Fallthrough | 
 | 671 |     case 'H': // Write second word of DI / DF reference.   | 
 | 672 |       // Verify that this operand has two consecutive registers. | 
 | 673 |       if (!MI->getOperand(OpNo).isRegister() || | 
 | 674 |           OpNo+1 == MI->getNumOperands() || | 
 | 675 |           !MI->getOperand(OpNo+1).isRegister()) | 
 | 676 |         return true; | 
 | 677 |       ++OpNo;   // Return the high-part. | 
 | 678 |     } | 
 | 679 |   } | 
 | 680 |    | 
 | 681 |   printOperand(MI, OpNo); | 
 | 682 |   return false; | 
 | 683 | } | 
 | 684 |  | 
 | 685 | void ARMAsmPrinter::printMachineInstruction(const MachineInstr *MI) { | 
 | 686 |   ++EmittedInsts; | 
 | 687 |  | 
| Evan Cheng | c60e76d | 2007-01-30 20:37:08 +0000 | [diff] [blame] | 688 |   int Opc = MI->getOpcode(); | 
 | 689 |   switch (Opc) { | 
 | 690 |   case ARM::CONSTPOOL_ENTRY: | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 691 |     if (!InCPMode && AFI->isThumbFunction()) { | 
 | 692 |       EmitAlignment(2); | 
 | 693 |       InCPMode = true; | 
 | 694 |     } | 
| Evan Cheng | c60e76d | 2007-01-30 20:37:08 +0000 | [diff] [blame] | 695 |     break; | 
 | 696 |   default: { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 697 |     if (InCPMode && AFI->isThumbFunction()) { | 
 | 698 |       EmitAlignment(1); | 
 | 699 |       InCPMode = false; | 
 | 700 |     } | 
| Evan Cheng | c60e76d | 2007-01-30 20:37:08 +0000 | [diff] [blame] | 701 |     switch (Opc) { | 
 | 702 |     case ARM::PICADD: | 
 | 703 |     case ARM::PICLD: | 
 | 704 |     case ARM::tPICADD: | 
 | 705 |       break; | 
 | 706 |     default: | 
 | 707 |       O << "\t"; | 
 | 708 |       break; | 
 | 709 |     } | 
 | 710 |   }} | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 711 |  | 
 | 712 |   // Call the autogenerated instruction printer routines. | 
 | 713 |   printInstruction(MI); | 
 | 714 | } | 
 | 715 |  | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 716 | bool ARMAsmPrinter::doInitialization(Module &M) { | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 717 |   if (Subtarget->isTargetDarwin()) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 718 |     // Emit initial debug information. | 
 | 719 |     DW.BeginModule(&M); | 
 | 720 |   } | 
 | 721 |    | 
 | 722 |   return AsmPrinter::doInitialization(M); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 723 | } | 
 | 724 |  | 
 | 725 | bool ARMAsmPrinter::doFinalization(Module &M) { | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 726 |   const TargetData *TD = TM.getTargetData(); | 
 | 727 |  | 
 | 728 |   for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); | 
 | 729 |        I != E; ++I) { | 
 | 730 |     if (!I->hasInitializer())   // External global require no code | 
 | 731 |       continue; | 
 | 732 |  | 
| Evan Cheng | b267ca1 | 2007-01-30 08:04:53 +0000 | [diff] [blame] | 733 |     if (EmitSpecialLLVMGlobal(I)) { | 
 | 734 |       if (Subtarget->isTargetDarwin() && | 
 | 735 |           TM.getRelocationModel() == Reloc::Static) { | 
 | 736 |         if (I->getName() == "llvm.global_ctors") | 
 | 737 |           O << ".reference .constructors_used\n"; | 
 | 738 |         else if (I->getName() == "llvm.global_dtors") | 
 | 739 |           O << ".reference .destructors_used\n"; | 
 | 740 |       } | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 741 |       continue; | 
| Evan Cheng | b267ca1 | 2007-01-30 08:04:53 +0000 | [diff] [blame] | 742 |     } | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 743 |  | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 744 |     std::string name = Mang->getValueName(I); | 
 | 745 |     Constant *C = I->getInitializer(); | 
 | 746 |     unsigned Size = TD->getTypeSize(C->getType()); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 747 |     unsigned Align = TD->getPreferredAlignmentLog(I); | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 748 |  | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 749 |     if (I->hasHiddenVisibility()) | 
 | 750 |       if (const char *Directive = TAI->getHiddenDirective()) | 
 | 751 |         O << Directive << name << "\n"; | 
 | 752 |     if (Subtarget->isTargetELF()) | 
| Lauro Ramos Venancio | b1cc052 | 2007-01-25 20:11:04 +0000 | [diff] [blame] | 753 |       O << "\t.type " << name << ",%object\n"; | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 754 |      | 
 | 755 |     if (C->isNullValue()) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 756 |       if (I->hasExternalLinkage()) { | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 757 |         if (const char *Directive = TAI->getZeroFillDirective()) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 758 |           O << "\t.globl\t" << name << "\n"; | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 759 |           O << Directive << "__DATA__, __common, " << name << ", " | 
 | 760 |             << Size << ", " << Align << "\n"; | 
 | 761 |           continue; | 
 | 762 |         } | 
 | 763 |       } | 
 | 764 |  | 
 | 765 |       if (!I->hasSection() && | 
 | 766 |           (I->hasInternalLinkage() || I->hasWeakLinkage() || | 
 | 767 |            I->hasLinkOnceLinkage())) { | 
 | 768 |         if (Size == 0) Size = 1;   // .comm Foo, 0 is undefined, avoid it. | 
 | 769 |         if (!NoZerosInBSS && TAI->getBSSSection()) | 
 | 770 |           SwitchToDataSection(TAI->getBSSSection(), I); | 
 | 771 |         else | 
 | 772 |           SwitchToDataSection(TAI->getDataSection(), I); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 773 |         if (TAI->getLCOMMDirective() != NULL) { | 
 | 774 |           if (I->hasInternalLinkage()) { | 
 | 775 |             O << TAI->getLCOMMDirective() << name << "," << Size; | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 776 |             if (Subtarget->isTargetDarwin()) | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 777 |               O << "," << Align; | 
 | 778 |           } else | 
 | 779 |             O << TAI->getCOMMDirective()  << name << "," << Size; | 
 | 780 |         } else { | 
 | 781 |           if (I->hasInternalLinkage()) | 
 | 782 |             O << "\t.local\t" << name << "\n"; | 
 | 783 |           O << TAI->getCOMMDirective()  << name << "," << Size; | 
 | 784 |           if (TAI->getCOMMDirectiveTakesAlignment()) | 
 | 785 |             O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align); | 
 | 786 |         } | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 787 |         O << "\t\t" << TAI->getCommentString() << " " << I->getName() << "\n"; | 
 | 788 |         continue; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 789 |       } | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 790 |     } | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 791 |  | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 792 |     switch (I->getLinkage()) { | 
 | 793 |     case GlobalValue::LinkOnceLinkage: | 
 | 794 |     case GlobalValue::WeakLinkage: | 
 | 795 |       if (Subtarget->isTargetDarwin()) { | 
 | 796 |         O << "\t.globl " << name << "\n" | 
 | 797 |           << "\t.weak_definition " << name << "\n"; | 
 | 798 |         SwitchToDataSection("\t.section __DATA,__const_coal,coalesced", I); | 
 | 799 |       } else { | 
 | 800 |         std::string SectionName("\t.section\t.llvm.linkonce.d." + | 
 | 801 |                                 name + | 
 | 802 |                                 ",\"aw\",%progbits"); | 
 | 803 |         SwitchToDataSection(SectionName.c_str(), I); | 
 | 804 |         O << "\t.weak " << name << "\n"; | 
 | 805 |       } | 
 | 806 |       break; | 
 | 807 |     case GlobalValue::AppendingLinkage: | 
 | 808 |       // FIXME: appending linkage variables should go into a section of | 
 | 809 |       // their name or something.  For now, just emit them as external. | 
 | 810 |     case GlobalValue::ExternalLinkage: | 
 | 811 |       O << "\t.globl " << name << "\n"; | 
 | 812 |       // FALL THROUGH | 
 | 813 |     case GlobalValue::InternalLinkage: { | 
 | 814 |       if (I->isConstant()) { | 
 | 815 |         const ConstantArray *CVA = dyn_cast<ConstantArray>(C); | 
 | 816 |         if (TAI->getCStringSection() && CVA && CVA->isCString()) { | 
 | 817 |           SwitchToDataSection(TAI->getCStringSection(), I); | 
 | 818 |           break; | 
 | 819 |         } | 
 | 820 |       } | 
 | 821 |       // FIXME: special handling for ".ctors" & ".dtors" sections | 
 | 822 |       if (I->hasSection() && | 
 | 823 |           (I->getSection() == ".ctors" || | 
 | 824 |            I->getSection() == ".dtors")) { | 
 | 825 |         assert(!Subtarget->isTargetDarwin()); | 
 | 826 |         std::string SectionName = ".section " + I->getSection(); | 
 | 827 |         SectionName += ",\"aw\",%progbits"; | 
 | 828 |         SwitchToDataSection(SectionName.c_str()); | 
 | 829 |       } else { | 
 | 830 |         if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection()) | 
 | 831 |           SwitchToDataSection(TAI->getBSSSection(), I); | 
 | 832 |         else | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 833 |           SwitchToDataSection(TAI->getDataSection(), I); | 
| Rafael Espindola | b97809c | 2006-10-19 13:30:40 +0000 | [diff] [blame] | 834 |       } | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 835 |  | 
 | 836 |       break; | 
 | 837 |     } | 
 | 838 |     default: | 
 | 839 |       assert(0 && "Unknown linkage type!"); | 
 | 840 |       break; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 841 |     } | 
| Rafael Espindola | b97809c | 2006-10-19 13:30:40 +0000 | [diff] [blame] | 842 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 843 |     EmitAlignment(Align, I); | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 844 |     O << name << ":\t\t\t\t" << TAI->getCommentString() << " " << I->getName() | 
 | 845 |       << "\n"; | 
 | 846 |     if (TAI->hasDotTypeDotSizeDirective()) | 
| Rafael Espindola | b97809c | 2006-10-19 13:30:40 +0000 | [diff] [blame] | 847 |       O << "\t.size " << name << ", " << Size << "\n"; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 848 |     // If the initializer is a extern weak symbol, remember to emit the weak | 
 | 849 |     // reference! | 
 | 850 |     if (const GlobalValue *GV = dyn_cast<GlobalValue>(C)) | 
 | 851 |       if (GV->hasExternalWeakLinkage()) | 
 | 852 |       ExtWeakSymbols.insert(GV); | 
 | 853 |  | 
 | 854 |     EmitGlobalConstant(C); | 
 | 855 |     O << '\n'; | 
 | 856 |   } | 
 | 857 |  | 
| Evan Cheng | 5be54b0 | 2007-01-19 19:25:36 +0000 | [diff] [blame] | 858 |   if (Subtarget->isTargetDarwin()) { | 
 | 859 |     SwitchToDataSection(""); | 
 | 860 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 861 |     // Output stubs for dynamically-linked functions | 
 | 862 |     unsigned j = 1; | 
 | 863 |     for (std::set<std::string>::iterator i = FnStubs.begin(), e = FnStubs.end(); | 
 | 864 |          i != e; ++i, ++j) { | 
 | 865 |       if (TM.getRelocationModel() == Reloc::PIC_) | 
 | 866 |         SwitchToTextSection(".section __TEXT,__picsymbolstub4,symbol_stubs," | 
 | 867 |                             "none,16", 0); | 
 | 868 |       else | 
 | 869 |         SwitchToTextSection(".section __TEXT,__symbol_stub4,symbol_stubs," | 
 | 870 |                             "none,12", 0); | 
 | 871 |  | 
 | 872 |       EmitAlignment(2); | 
 | 873 |       O << "\t.code\t32\n"; | 
 | 874 |  | 
 | 875 |       O << "L" << *i << "$stub:\n"; | 
 | 876 |       O << "\t.indirect_symbol " << *i << "\n"; | 
 | 877 |       O << "\tldr ip, L" << *i << "$slp\n"; | 
 | 878 |       if (TM.getRelocationModel() == Reloc::PIC_) { | 
 | 879 |         O << "L" << *i << "$scv:\n"; | 
 | 880 |         O << "\tadd ip, pc, ip\n"; | 
 | 881 |       } | 
 | 882 |       O << "\tldr pc, [ip, #0]\n"; | 
 | 883 |       O << "L" << *i << "$slp:\n"; | 
 | 884 |       if (TM.getRelocationModel() == Reloc::PIC_) | 
 | 885 |         O << "\t.long\tL" << *i << "$lazy_ptr-(L" << *i << "$scv+8)\n"; | 
 | 886 |       else | 
 | 887 |         O << "\t.long\tL" << *i << "$lazy_ptr\n"; | 
 | 888 |       SwitchToDataSection(".lazy_symbol_pointer", 0); | 
 | 889 |       O << "L" << *i << "$lazy_ptr:\n"; | 
 | 890 |       O << "\t.indirect_symbol " << *i << "\n"; | 
 | 891 |       O << "\t.long\tdyld_stub_binding_helper\n"; | 
 | 892 |     } | 
 | 893 |     O << "\n"; | 
 | 894 |  | 
 | 895 |     // Output non-lazy-pointers for external and common global variables. | 
 | 896 |     if (GVNonLazyPtrs.begin() != GVNonLazyPtrs.end()) | 
 | 897 |       SwitchToDataSection(".non_lazy_symbol_pointer", 0); | 
 | 898 |     for (std::set<std::string>::iterator i = GVNonLazyPtrs.begin(), | 
 | 899 |            e = GVNonLazyPtrs.end(); i != e; ++i) { | 
 | 900 |       O << "L" << *i << "$non_lazy_ptr:\n"; | 
 | 901 |       O << "\t.indirect_symbol " << *i << "\n"; | 
 | 902 |       O << "\t.long\t0\n"; | 
 | 903 |     } | 
 | 904 |  | 
 | 905 |     // Emit initial debug information. | 
 | 906 |     DW.EndModule(); | 
 | 907 |  | 
 | 908 |     // Funny Darwin hack: This flag tells the linker that no global symbols | 
 | 909 |     // contain code that falls through to other global symbols (e.g. the obvious | 
 | 910 |     // implementation of multiple entry points).  If this doesn't occur, the | 
 | 911 |     // linker can safely perform dead code stripping.  Since LLVM never | 
 | 912 |     // generates code that does this, it is always safe to set. | 
 | 913 |     O << "\t.subsections_via_symbols\n"; | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 914 |   } | 
| Rafael Espindola | b97809c | 2006-10-19 13:30:40 +0000 | [diff] [blame] | 915 |  | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 916 |   AsmPrinter::doFinalization(M); | 
 | 917 |   return false; // success | 
 | 918 | } |