| 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 |  | 
|  | 16 | #include "ARM.h" | 
|  | 17 | #include "ARMInstrInfo.h" | 
|  | 18 | #include "llvm/Constants.h" | 
|  | 19 | #include "llvm/DerivedTypes.h" | 
|  | 20 | #include "llvm/Module.h" | 
|  | 21 | #include "llvm/Assembly/Writer.h" | 
|  | 22 | #include "llvm/CodeGen/AsmPrinter.h" | 
|  | 23 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | 24 | #include "llvm/CodeGen/MachineConstantPool.h" | 
|  | 25 | #include "llvm/CodeGen/MachineInstr.h" | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 26 | #include "llvm/Target/TargetAsmInfo.h" | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 27 | #include "llvm/Target/TargetData.h" | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 28 | #include "llvm/Target/TargetMachine.h" | 
|  | 29 | #include "llvm/Support/Mangler.h" | 
|  | 30 | #include "llvm/ADT/Statistic.h" | 
|  | 31 | #include "llvm/ADT/StringExtras.h" | 
|  | 32 | #include "llvm/Support/CommandLine.h" | 
|  | 33 | #include "llvm/Support/MathExtras.h" | 
|  | 34 | #include <cctype> | 
|  | 35 | #include <iostream> | 
|  | 36 | using namespace llvm; | 
|  | 37 |  | 
|  | 38 | namespace { | 
|  | 39 | Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); | 
|  | 40 |  | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 41 | struct VISIBILITY_HIDDEN ARMAsmPrinter : public AsmPrinter { | 
| Jim Laskey | a0f3d17 | 2006-09-07 22:06:40 +0000 | [diff] [blame] | 42 | ARMAsmPrinter(std::ostream &O, TargetMachine &TM, const TargetAsmInfo *T) | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 43 | : AsmPrinter(O, TM, T) { | 
|  | 44 | } | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 45 |  | 
|  | 46 | /// We name each basic block in a Function with a unique number, so | 
|  | 47 | /// that we can consistently refer to them later. This is cleared | 
|  | 48 | /// at the beginning of each call to runOnMachineFunction(). | 
|  | 49 | /// | 
|  | 50 | typedef std::map<const Value *, unsigned> ValueMapTy; | 
|  | 51 | ValueMapTy NumberForBB; | 
|  | 52 |  | 
|  | 53 | virtual const char *getPassName() const { | 
|  | 54 | return "ARM Assembly Printer"; | 
|  | 55 | } | 
|  | 56 |  | 
| Rafael Espindola | f3a335c | 2006-08-17 17:09:40 +0000 | [diff] [blame] | 57 | void printMemRegImm(const MachineInstr *MI, int opNum, | 
|  | 58 | const char *Modifier = NULL) { | 
|  | 59 | const MachineOperand &MO1 = MI->getOperand(opNum); | 
|  | 60 | const MachineOperand &MO2 = MI->getOperand(opNum + 1); | 
| Rafael Espindola | 1ed3af1 | 2006-08-01 18:53:10 +0000 | [diff] [blame] | 61 | assert(MO1.isImmediate()); | 
| Rafael Espindola | f3a335c | 2006-08-17 17:09:40 +0000 | [diff] [blame] | 62 | bool arith = false; | 
|  | 63 | if (Modifier != NULL) { | 
|  | 64 | assert(strcmp(Modifier, "arith") == 0); | 
|  | 65 | arith = true; | 
|  | 66 | } | 
| Rafael Espindola | 1ed3af1 | 2006-08-01 18:53:10 +0000 | [diff] [blame] | 67 |  | 
|  | 68 | if (MO2.isConstantPoolIndex()) { | 
| Rafael Espindola | f3a335c | 2006-08-17 17:09:40 +0000 | [diff] [blame] | 69 | printOperand(MI, opNum + 1); | 
| Rafael Espindola | 1ed3af1 | 2006-08-01 18:53:10 +0000 | [diff] [blame] | 70 | } else if (MO2.isRegister()) { | 
| Rafael Espindola | f3a335c | 2006-08-17 17:09:40 +0000 | [diff] [blame] | 71 | if(!arith) | 
|  | 72 | O << '['; | 
|  | 73 | printOperand(MI, opNum + 1); | 
| Rafael Espindola | 1ed3af1 | 2006-08-01 18:53:10 +0000 | [diff] [blame] | 74 | O << ", "; | 
| Rafael Espindola | f3a335c | 2006-08-17 17:09:40 +0000 | [diff] [blame] | 75 | printOperand(MI, opNum); | 
|  | 76 | if(!arith) | 
|  | 77 | O << ']'; | 
| Rafael Espindola | 1ed3af1 | 2006-08-01 18:53:10 +0000 | [diff] [blame] | 78 | } else { | 
|  | 79 | assert(0 && "Invalid Operand Type"); | 
|  | 80 | } | 
| Rafael Espindola | a4e6435 | 2006-07-11 11:36:48 +0000 | [diff] [blame] | 81 | } | 
|  | 82 |  | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 83 | void printOperand(const MachineInstr *MI, int opNum); | 
|  | 84 | void printMemOperand(const MachineInstr *MI, int opNum, | 
|  | 85 | const char *Modifier = 0); | 
|  | 86 | void printCCOperand(const MachineInstr *MI, int opNum); | 
|  | 87 |  | 
|  | 88 | bool printInstruction(const MachineInstr *MI);  // autogenerated. | 
|  | 89 | bool runOnMachineFunction(MachineFunction &F); | 
|  | 90 | bool doInitialization(Module &M); | 
|  | 91 | bool doFinalization(Module &M); | 
|  | 92 | }; | 
|  | 93 | } // end of anonymous namespace | 
|  | 94 |  | 
|  | 95 | #include "ARMGenAsmWriter.inc" | 
|  | 96 |  | 
|  | 97 | /// createARMCodePrinterPass - Returns a pass that prints the ARM | 
|  | 98 | /// assembly code for a MachineFunction to the given output stream, | 
|  | 99 | /// using the given target machine description.  This should work | 
|  | 100 | /// regardless of whether the function is in SSA form. | 
|  | 101 | /// | 
|  | 102 | FunctionPass *llvm::createARMCodePrinterPass(std::ostream &o, | 
|  | 103 | TargetMachine &tm) { | 
| Jim Laskey | a0f3d17 | 2006-09-07 22:06:40 +0000 | [diff] [blame] | 104 | return new ARMAsmPrinter(o, tm, tm.getTargetAsmInfo()); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 105 | } | 
|  | 106 |  | 
|  | 107 | /// runOnMachineFunction - This uses the printMachineInstruction() | 
|  | 108 | /// method to print assembly for each instruction. | 
|  | 109 | /// | 
|  | 110 | bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 111 | SetupMachineFunction(MF); | 
|  | 112 | O << "\n\n"; | 
|  | 113 |  | 
|  | 114 | // Print out constants referenced by the function | 
|  | 115 | EmitConstantPool(MF.getConstantPool()); | 
|  | 116 |  | 
|  | 117 | // Print out jump tables referenced by the function | 
|  | 118 | EmitJumpTableInfo(MF.getJumpTableInfo()); | 
|  | 119 |  | 
|  | 120 | // Print out labels for the function. | 
|  | 121 | const Function *F = MF.getFunction(); | 
|  | 122 | switch (F->getLinkage()) { | 
|  | 123 | default: assert(0 && "Unknown linkage type!"); | 
|  | 124 | case Function::InternalLinkage: | 
|  | 125 | SwitchToTextSection("\t.text", F); | 
|  | 126 | break; | 
|  | 127 | case Function::ExternalLinkage: | 
|  | 128 | SwitchToTextSection("\t.text", F); | 
|  | 129 | O << "\t.globl\t" << CurrentFnName << "\n"; | 
|  | 130 | break; | 
|  | 131 | case Function::WeakLinkage: | 
|  | 132 | case Function::LinkOnceLinkage: | 
|  | 133 | assert(0 && "Not implemented"); | 
|  | 134 | break; | 
|  | 135 | } | 
| Rafael Espindola | a1334cd | 2006-05-26 10:56:17 +0000 | [diff] [blame] | 136 | EmitAlignment(2, F); | 
| Rafael Espindola | 4b442b5 | 2006-05-23 02:48:20 +0000 | [diff] [blame] | 137 | O << CurrentFnName << ":\n"; | 
|  | 138 |  | 
|  | 139 | // Print out code for the function. | 
|  | 140 | for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); | 
|  | 141 | I != E; ++I) { | 
|  | 142 | // Print a label for the basic block. | 
|  | 143 | if (I != MF.begin()) { | 
|  | 144 | printBasicBlockLabel(I, true); | 
|  | 145 | O << '\n'; | 
|  | 146 | } | 
|  | 147 | for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); | 
|  | 148 | II != E; ++II) { | 
|  | 149 | // Print the assembly for the instruction. | 
|  | 150 | O << "\t"; | 
|  | 151 | printInstruction(II); | 
|  | 152 | } | 
|  | 153 | } | 
|  | 154 |  | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 155 | return false; | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | void ARMAsmPrinter::printOperand(const MachineInstr *MI, int opNum) { | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 159 | const MachineOperand &MO = MI->getOperand (opNum); | 
|  | 160 | const MRegisterInfo &RI = *TM.getRegisterInfo(); | 
|  | 161 | switch (MO.getType()) { | 
|  | 162 | case MachineOperand::MO_Register: | 
|  | 163 | if (MRegisterInfo::isPhysicalRegister(MO.getReg())) | 
|  | 164 | O << LowercaseString (RI.get(MO.getReg()).Name); | 
|  | 165 | else | 
|  | 166 | assert(0 && "not implemented"); | 
|  | 167 | break; | 
|  | 168 | case MachineOperand::MO_Immediate: | 
|  | 169 | O << "#" << (int)MO.getImmedValue(); | 
|  | 170 | break; | 
|  | 171 | case MachineOperand::MO_MachineBasicBlock: | 
| Rafael Espindola | 687bc49 | 2006-08-24 13:45:55 +0000 | [diff] [blame] | 172 | printBasicBlockLabel(MO.getMachineBasicBlock()); | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 173 | return; | 
| Rafael Espindola | 84b19be | 2006-07-16 01:02:57 +0000 | [diff] [blame] | 174 | case MachineOperand::MO_GlobalAddress: { | 
|  | 175 | GlobalValue *GV = MO.getGlobal(); | 
|  | 176 | std::string Name = Mang->getValueName(GV); | 
|  | 177 | O << Name; | 
|  | 178 | } | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 179 | break; | 
|  | 180 | case MachineOperand::MO_ExternalSymbol: | 
|  | 181 | assert(0 && "not implemented"); | 
|  | 182 | abort(); | 
|  | 183 | break; | 
|  | 184 | case MachineOperand::MO_ConstantPoolIndex: | 
| Jim Laskey | 563321a | 2006-09-06 18:34:40 +0000 | [diff] [blame] | 185 | O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() | 
| Rafael Espindola | 06c1e7e | 2006-08-01 12:58:43 +0000 | [diff] [blame] | 186 | << '_' << MO.getConstantPoolIndex(); | 
| Rafael Espindola | 2f99b6b | 2006-05-25 12:57:06 +0000 | [diff] [blame] | 187 | break; | 
|  | 188 | default: | 
|  | 189 | O << "<unknown operand type>"; abort (); break; | 
|  | 190 | } | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 191 | } | 
|  | 192 |  | 
|  | 193 | void ARMAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, | 
|  | 194 | const char *Modifier) { | 
|  | 195 | assert(0 && "not implemented"); | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | void ARMAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum) { | 
| Rafael Espindola | 6f602de | 2006-08-24 16:13:15 +0000 | [diff] [blame] | 199 | int CC = (int)MI->getOperand(opNum).getImmedValue(); | 
|  | 200 | O << ARMCondCodeToString((ARMCC::CondCodes)CC); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 201 | } | 
|  | 202 |  | 
|  | 203 | bool ARMAsmPrinter::doInitialization(Module &M) { | 
| Rafael Espindola | ff59d22 | 2006-09-11 12:49:38 +0000 | [diff] [blame^] | 204 | AsmPrinter::doInitialization(M); | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 205 | return false; // success | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | bool ARMAsmPrinter::doFinalization(Module &M) { | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 209 | const TargetData *TD = TM.getTargetData(); | 
|  | 210 |  | 
|  | 211 | for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); | 
|  | 212 | I != E; ++I) { | 
|  | 213 | if (!I->hasInitializer())   // External global require no code | 
|  | 214 | continue; | 
|  | 215 |  | 
|  | 216 | if (EmitSpecialLLVMGlobal(I)) | 
|  | 217 | continue; | 
|  | 218 |  | 
|  | 219 | O << "\n\n"; | 
|  | 220 | std::string name = Mang->getValueName(I); | 
|  | 221 | Constant *C = I->getInitializer(); | 
|  | 222 | unsigned Size = TD->getTypeSize(C->getType()); | 
|  | 223 | unsigned Align = TD->getTypeAlignment(C->getType()); | 
|  | 224 |  | 
| Rafael Espindola | 6d581e8 | 2006-07-31 20:38:13 +0000 | [diff] [blame] | 225 | switch (I->getLinkage()) { | 
|  | 226 | default: | 
|  | 227 | assert(0 && "Unknown linkage type!"); | 
|  | 228 | break; | 
|  | 229 | case GlobalValue::ExternalLinkage: | 
|  | 230 | O << "\t.globl " << name << "\n"; | 
|  | 231 | break; | 
|  | 232 | case GlobalValue::InternalLinkage: | 
|  | 233 | break; | 
|  | 234 | } | 
| Rafael Espindola | b01c4bb | 2006-07-27 11:38:51 +0000 | [diff] [blame] | 235 |  | 
|  | 236 | assert (!C->isNullValue()); | 
|  | 237 | SwitchToDataSection(".data", I); | 
|  | 238 |  | 
|  | 239 | EmitAlignment(Align, I); | 
|  | 240 | O << "\t.type " << name << ", %object\n"; | 
|  | 241 | O << "\t.size " << name << ", " << Size << "\n"; | 
|  | 242 | O << name << ":\n"; | 
|  | 243 | EmitGlobalConstant(C); | 
|  | 244 | } | 
| Rafael Espindola | 7bc59bc | 2006-05-14 22:18:28 +0000 | [diff] [blame] | 245 | AsmPrinter::doFinalization(M); | 
|  | 246 | return false; // success | 
|  | 247 | } |