1 //===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // 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 SPARC assembly language. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #define DEBUG_TYPE "asm-printer" 16 #include "Sparc.h" 17 #include "SparcInstrInfo.h" 18 #include "SparcTargetMachine.h" 19 #include "MCTargetDesc/SparcBaseInfo.h" 20 #include "llvm/ADT/SmallString.h" 21 #include "llvm/CodeGen/AsmPrinter.h" 22 #include "llvm/CodeGen/MachineInstr.h" 23 #include "llvm/MC/MCAsmInfo.h" 24 #include "llvm/MC/MCStreamer.h" 25 #include "llvm/MC/MCSymbol.h" 26 #include "llvm/Support/TargetRegistry.h" 27 #include "llvm/Support/raw_ostream.h" 28 #include "llvm/Target/Mangler.h" 29 using namespace llvm; 30 31 namespace { 32 class SparcAsmPrinter : public AsmPrinter { 33 public: 34 explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) 35 : AsmPrinter(TM, Streamer) {} 36 37 virtual const char *getPassName() const { 38 return "Sparc Assembly Printer"; 39 } 40 41 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); 42 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS, 43 const char *Modifier = 0); 44 void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); 45 46 virtual void EmitInstruction(const MachineInstr *MI) { 47 SmallString<128> Str; 48 raw_svector_ostream OS(Str); 49 printInstruction(MI, OS); 50 OutStreamer.EmitRawText(OS.str()); 51 } 52 void printInstruction(const MachineInstr *MI, raw_ostream &OS);// autogen'd. 53 static const char *getRegisterName(unsigned RegNo); 54 55 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 56 unsigned AsmVariant, const char *ExtraCode, 57 raw_ostream &O); 58 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 59 unsigned AsmVariant, const char *ExtraCode, 60 raw_ostream &O); 61 62 bool printGetPCX(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS); 63 64 virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) 65 const; 66 67 virtual MachineLocation getDebugValueLocation(const MachineInstr *MI) const; 68 }; 69 } // end of anonymous namespace 70 71 #include "SparcGenAsmWriter.inc" 72 73 void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, 74 raw_ostream &O) { 75 const MachineOperand &MO = MI->getOperand (opNum); 76 unsigned TF = MO.getTargetFlags(); 77 #ifndef NDEBUG 78 // Verify the target flags. 79 if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) { 80 if (MI->getOpcode() == SP::CALL) 81 assert(TF == SPII::MO_NO_FLAG && 82 "Cannot handle target flags on call address"); 83 else if (MI->getOpcode() == SP::SETHIi) 84 assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH) && 85 "Invalid target flags for address operand on sethi"); 86 else 87 assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 || 88 TF == SPII::MO_HM) && 89 "Invalid target flags for small address operand"); 90 } 91 #endif 92 93 bool CloseParen = true; 94 switch (TF) { 95 default: 96 llvm_unreachable("Unknown target flags on operand"); 97 case SPII::MO_NO_FLAG: 98 CloseParen = false; 99 break; 100 case SPII::MO_LO: O << "%lo("; break; 101 case SPII::MO_HI: O << "%hi("; break; 102 case SPII::MO_H44: O << "%h44("; break; 103 case SPII::MO_M44: O << "%m44("; break; 104 case SPII::MO_L44: O << "%l44("; break; 105 case SPII::MO_HH: O << "%hh("; break; 106 case SPII::MO_HM: O << "%hm("; break; 107 } 108 109 switch (MO.getType()) { 110 case MachineOperand::MO_Register: 111 O << "%" << StringRef(getRegisterName(MO.getReg())).lower(); 112 break; 113 114 case MachineOperand::MO_Immediate: 115 O << (int)MO.getImm(); 116 break; 117 case MachineOperand::MO_MachineBasicBlock: 118 O << *MO.getMBB()->getSymbol(); 119 return; 120 case MachineOperand::MO_GlobalAddress: 121 O << *Mang->getSymbol(MO.getGlobal()); 122 break; 123 case MachineOperand::MO_BlockAddress: 124 O << GetBlockAddressSymbol(MO.getBlockAddress())->getName(); 125 break; 126 case MachineOperand::MO_ExternalSymbol: 127 O << MO.getSymbolName(); 128 break; 129 case MachineOperand::MO_ConstantPoolIndex: 130 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" 131 << MO.getIndex(); 132 break; 133 default: 134 llvm_unreachable("<unknown operand type>"); 135 } 136 if (CloseParen) O << ")"; 137 } 138 139 void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, 140 raw_ostream &O, const char *Modifier) { 141 printOperand(MI, opNum, O); 142 143 // If this is an ADD operand, emit it like normal operands. 144 if (Modifier && !strcmp(Modifier, "arith")) { 145 O << ", "; 146 printOperand(MI, opNum+1, O); 147 return; 148 } 149 150 if (MI->getOperand(opNum+1).isReg() && 151 MI->getOperand(opNum+1).getReg() == SP::G0) 152 return; // don't print "+%g0" 153 if (MI->getOperand(opNum+1).isImm() && 154 MI->getOperand(opNum+1).getImm() == 0) 155 return; // don't print "+0" 156 157 O << "+"; 158 printOperand(MI, opNum+1, O); 159 } 160 161 bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum, 162 raw_ostream &O) { 163 std::string operand = ""; 164 const MachineOperand &MO = MI->getOperand(opNum); 165 switch (MO.getType()) { 166 default: llvm_unreachable("Operand is not a register"); 167 case MachineOperand::MO_Register: 168 assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && 169 "Operand is not a physical register "); 170 assert(MO.getReg() != SP::O7 && 171 "%o7 is assigned as destination for getpcx!"); 172 operand = "%" + StringRef(getRegisterName(MO.getReg())).lower(); 173 break; 174 } 175 176 unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber(); 177 unsigned bbNum = MI->getParent()->getNumber(); 178 179 O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n"; 180 O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ; 181 182 O << "\t sethi\t" 183 << "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum 184 << ")), " << operand << '\n' ; 185 186 O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ; 187 O << "\tor\t" << operand 188 << ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum 189 << ")), " << operand << '\n'; 190 O << "\tadd\t" << operand << ", %o7, " << operand << '\n'; 191 192 return true; 193 } 194 195 void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum, 196 raw_ostream &O) { 197 int CC = (int)MI->getOperand(opNum).getImm(); 198 O << SPARCCondCodeToString((SPCC::CondCodes)CC); 199 } 200 201 /// PrintAsmOperand - Print out an operand for an inline asm expression. 202 /// 203 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 204 unsigned AsmVariant, 205 const char *ExtraCode, 206 raw_ostream &O) { 207 if (ExtraCode && ExtraCode[0]) { 208 if (ExtraCode[1] != 0) return true; // Unknown modifier. 209 210 switch (ExtraCode[0]) { 211 default: 212 // See if this is a generic print operand 213 return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); 214 case 'r': 215 break; 216 } 217 } 218 219 printOperand(MI, OpNo, O); 220 221 return false; 222 } 223 224 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 225 unsigned OpNo, unsigned AsmVariant, 226 const char *ExtraCode, 227 raw_ostream &O) { 228 if (ExtraCode && ExtraCode[0]) 229 return true; // Unknown modifier 230 231 O << '['; 232 printMemOperand(MI, OpNo, O); 233 O << ']'; 234 235 return false; 236 } 237 238 /// isBlockOnlyReachableByFallthough - Return true if the basic block has 239 /// exactly one predecessor and the control transfer mechanism between 240 /// the predecessor and this block is a fall-through. 241 /// 242 /// This overrides AsmPrinter's implementation to handle delay slots. 243 bool SparcAsmPrinter:: 244 isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { 245 // If this is a landing pad, it isn't a fall through. If it has no preds, 246 // then nothing falls through to it. 247 if (MBB->isLandingPad() || MBB->pred_empty()) 248 return false; 249 250 // If there isn't exactly one predecessor, it can't be a fall through. 251 MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; 252 ++PI2; 253 if (PI2 != MBB->pred_end()) 254 return false; 255 256 // The predecessor has to be immediately before this block. 257 const MachineBasicBlock *Pred = *PI; 258 259 if (!Pred->isLayoutSuccessor(MBB)) 260 return false; 261 262 // Check if the last terminator is an unconditional branch. 263 MachineBasicBlock::const_iterator I = Pred->end(); 264 while (I != Pred->begin() && !(--I)->isTerminator()) 265 ; // Noop 266 return I == Pred->end() || !I->isBarrier(); 267 } 268 269 MachineLocation SparcAsmPrinter:: 270 getDebugValueLocation(const MachineInstr *MI) const { 271 assert(MI->getNumOperands() == 4 && "Invalid number of operands!"); 272 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm() && 273 "Unexpected MachineOperand types"); 274 return MachineLocation(MI->getOperand(0).getReg(), 275 MI->getOperand(1).getImm()); 276 } 277 278 // Force static initialization. 279 extern "C" void LLVMInitializeSparcAsmPrinter() { 280 RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget); 281 RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target); 282 } 283