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