AsmPrinterInlineAsm.cpp revision 7fb59c6cad5a7e3ae621e0fedcbc67fea3ea13fe
1//===-- AsmPrinterInlineAsm.cpp - AsmPrinter Inline Asm Handling ----------===// 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 implements the inline assembler pieces of the AsmPrinter class. 11// 12//===----------------------------------------------------------------------===// 13 14#define DEBUG_TYPE "asm-printer" 15#include "llvm/CodeGen/AsmPrinter.h" 16#include "llvm/InlineAsm.h" 17#include "llvm/CodeGen/MachineBasicBlock.h" 18#include "llvm/MC/MCAsmInfo.h" 19#include "llvm/MC/MCStreamer.h" 20#include "llvm/MC/MCSymbol.h" 21#include "llvm/ADT/SmallString.h" 22#include "llvm/ADT/Twine.h" 23#include "llvm/Support/ErrorHandling.h" 24#include "llvm/Support/raw_ostream.h" 25using namespace llvm; 26 27/// EmitInlineAsm - Emit a blob of inline asm to the output streamer. 28void AsmPrinter::EmitInlineAsm(StringRef Str) const { 29 assert(!Str.empty() && "Can't emit empty inline asm block"); 30 31 // If the output streamer is actually a .s file, just emit the blob textually. 32 // This is useful in case the asm parser doesn't handle something but the 33 // system assembler does. 34 if (OutStreamer.hasRawTextSupport()) { 35 OutStreamer.EmitRawText(Str); 36 return; 37 } 38 39 errs() << "Inline asm not supported by this streamer!\n"; 40} 41 42 43/// EmitInlineAsm - This method formats and emits the specified machine 44/// instruction that is an inline asm. 45void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { 46 assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); 47 48 unsigned NumOperands = MI->getNumOperands(); 49 50 // Count the number of register definitions to find the asm string. 51 unsigned NumDefs = 0; 52 for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); 53 ++NumDefs) 54 assert(NumDefs != NumOperands-1 && "No asm string?"); 55 56 assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); 57 58 // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. 59 const char *AsmStr = MI->getOperand(NumDefs).getSymbolName(); 60 61 // If this asmstr is empty, just print the #APP/#NOAPP markers. 62 // These are useful to see where empty asm's wound up. 63 if (AsmStr[0] == 0) { 64 // Don't emit the comments if writing to a .o file. 65 if (!OutStreamer.hasRawTextSupport()) return; 66 67 OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ 68 MAI->getInlineAsmStart()); 69 OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ 70 MAI->getInlineAsmEnd()); 71 return; 72 } 73 74 // Emit the #APP start marker. This has to happen even if verbose-asm isn't 75 // enabled, so we use EmitRawText. 76 if (OutStreamer.hasRawTextSupport()) 77 OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ 78 MAI->getInlineAsmStart()); 79 80 // Emit the inline asm to a temporary string so we can emit it through 81 // EmitInlineAsm. 82 SmallString<256> StringData; 83 raw_svector_ostream OS(StringData); 84 85 OS << '\t'; 86 87 // The variant of the current asmprinter. 88 int AsmPrinterVariant = MAI->getAssemblerDialect(); 89 90 int CurVariant = -1; // The number of the {.|.|.} region we are in. 91 const char *LastEmitted = AsmStr; // One past the last character emitted. 92 93 while (*LastEmitted) { 94 switch (*LastEmitted) { 95 default: { 96 // Not a special case, emit the string section literally. 97 const char *LiteralEnd = LastEmitted+1; 98 while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' && 99 *LiteralEnd != '}' && *LiteralEnd != '$' && *LiteralEnd != '\n') 100 ++LiteralEnd; 101 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) 102 OS.write(LastEmitted, LiteralEnd-LastEmitted); 103 LastEmitted = LiteralEnd; 104 break; 105 } 106 case '\n': 107 ++LastEmitted; // Consume newline character. 108 OS << '\n'; // Indent code with newline. 109 break; 110 case '$': { 111 ++LastEmitted; // Consume '$' character. 112 bool Done = true; 113 114 // Handle escapes. 115 switch (*LastEmitted) { 116 default: Done = false; break; 117 case '$': // $$ -> $ 118 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) 119 OS << '$'; 120 ++LastEmitted; // Consume second '$' character. 121 break; 122 case '(': // $( -> same as GCC's { character. 123 ++LastEmitted; // Consume '(' character. 124 if (CurVariant != -1) { 125 llvm_report_error("Nested variants found in inline asm string: '" 126 + std::string(AsmStr) + "'"); 127 } 128 CurVariant = 0; // We're in the first variant now. 129 break; 130 case '|': 131 ++LastEmitted; // consume '|' character. 132 if (CurVariant == -1) 133 OS << '|'; // this is gcc's behavior for | outside a variant 134 else 135 ++CurVariant; // We're in the next variant. 136 break; 137 case ')': // $) -> same as GCC's } char. 138 ++LastEmitted; // consume ')' character. 139 if (CurVariant == -1) 140 OS << '}'; // this is gcc's behavior for } outside a variant 141 else 142 CurVariant = -1; 143 break; 144 } 145 if (Done) break; 146 147 bool HasCurlyBraces = false; 148 if (*LastEmitted == '{') { // ${variable} 149 ++LastEmitted; // Consume '{' character. 150 HasCurlyBraces = true; 151 } 152 153 // If we have ${:foo}, then this is not a real operand reference, it is a 154 // "magic" string reference, just like in .td files. Arrange to call 155 // PrintSpecial. 156 if (HasCurlyBraces && *LastEmitted == ':') { 157 ++LastEmitted; 158 const char *StrStart = LastEmitted; 159 const char *StrEnd = strchr(StrStart, '}'); 160 if (StrEnd == 0) 161 llvm_report_error(Twine("Unterminated ${:foo} operand in inline asm" 162 " string: '") + Twine(AsmStr) + "'"); 163 164 std::string Val(StrStart, StrEnd); 165 PrintSpecial(MI, OS, Val.c_str()); 166 LastEmitted = StrEnd+1; 167 break; 168 } 169 170 const char *IDStart = LastEmitted; 171 const char *IDEnd = IDStart; 172 while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; 173 174 unsigned Val; 175 if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) 176 llvm_report_error("Bad $ operand number in inline asm string: '" 177 + std::string(AsmStr) + "'"); 178 LastEmitted = IDEnd; 179 180 char Modifier[2] = { 0, 0 }; 181 182 if (HasCurlyBraces) { 183 // If we have curly braces, check for a modifier character. This 184 // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm. 185 if (*LastEmitted == ':') { 186 ++LastEmitted; // Consume ':' character. 187 if (*LastEmitted == 0) 188 llvm_report_error("Bad ${:} expression in inline asm string: '" + 189 std::string(AsmStr) + "'"); 190 191 Modifier[0] = *LastEmitted; 192 ++LastEmitted; // Consume modifier character. 193 } 194 195 if (*LastEmitted != '}') 196 llvm_report_error("Bad ${} expression in inline asm string: '" 197 + std::string(AsmStr) + "'"); 198 ++LastEmitted; // Consume '}' character. 199 } 200 201 if (Val >= NumOperands-1) 202 llvm_report_error("Invalid $ operand number in inline asm string: '" 203 + std::string(AsmStr) + "'"); 204 205 // Okay, we finally have a value number. Ask the target to print this 206 // operand! 207 if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { 208 unsigned OpNo = 1; 209 210 bool Error = false; 211 212 // Scan to find the machine operand number for the operand. 213 for (; Val; --Val) { 214 if (OpNo >= MI->getNumOperands()) break; 215 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 216 OpNo += InlineAsm::getNumOperandRegisters(OpFlags) + 1; 217 } 218 219 if (OpNo >= MI->getNumOperands()) { 220 Error = true; 221 } else { 222 unsigned OpFlags = MI->getOperand(OpNo).getImm(); 223 ++OpNo; // Skip over the ID number. 224 225 if (Modifier[0] == 'l') // labels are target independent 226 // FIXME: What if the operand isn't an MBB, report error? 227 OS << *MI->getOperand(OpNo).getMBB()->getSymbol(); 228 else { 229 AsmPrinter *AP = const_cast<AsmPrinter*>(this); 230 if ((OpFlags & 7) == 4) { 231 Error = AP->PrintAsmMemoryOperand(MI, OpNo, AsmPrinterVariant, 232 Modifier[0] ? Modifier : 0, 233 OS); 234 } else { 235 Error = AP->PrintAsmOperand(MI, OpNo, AsmPrinterVariant, 236 Modifier[0] ? Modifier : 0, OS); 237 } 238 } 239 } 240 if (Error) { 241 std::string msg; 242 raw_string_ostream Msg(msg); 243 Msg << "Invalid operand found in inline asm: '" << AsmStr << "'\n"; 244 MI->print(Msg); 245 llvm_report_error(Msg.str()); 246 } 247 } 248 break; 249 } 250 } 251 } 252 OS << "\n"; 253 254 EmitInlineAsm(OS.str()); 255 256 // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't 257 // enabled, so we use EmitRawText. 258 if (OutStreamer.hasRawTextSupport()) 259 OutStreamer.EmitRawText(Twine("\t")+MAI->getCommentString()+ 260 MAI->getInlineAsmEnd()); 261} 262 263 264/// PrintSpecial - Print information related to the specified machine instr 265/// that is independent of the operand, and may be independent of the instr 266/// itself. This can be useful for portably encoding the comment character 267/// or other bits of target-specific knowledge into the asmstrings. The 268/// syntax used is ${:comment}. Targets can override this to add support 269/// for their own strange codes. 270void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, 271 const char *Code) const { 272 if (!strcmp(Code, "private")) { 273 OS << MAI->getPrivateGlobalPrefix(); 274 } else if (!strcmp(Code, "comment")) { 275 OS << MAI->getCommentString(); 276 } else if (!strcmp(Code, "uid")) { 277 // Comparing the address of MI isn't sufficient, because machineinstrs may 278 // be allocated to the same address across functions. 279 280 // If this is a new LastFn instruction, bump the counter. 281 if (LastMI != MI || LastFn != getFunctionNumber()) { 282 ++Counter; 283 LastMI = MI; 284 LastFn = getFunctionNumber(); 285 } 286 OS << Counter; 287 } else { 288 std::string msg; 289 raw_string_ostream Msg(msg); 290 Msg << "Unknown special formatter '" << Code 291 << "' for machine instr: " << *MI; 292 llvm_report_error(Msg.str()); 293 } 294} 295 296/// PrintAsmOperand - Print the specified operand of MI, an INLINEASM 297/// instruction, using the specified assembler variant. Targets should 298/// override this to format as appropriate. 299bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 300 unsigned AsmVariant, const char *ExtraCode, 301 raw_ostream &O) { 302 // Target doesn't support this yet! 303 return true; 304} 305 306bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 307 unsigned AsmVariant, 308 const char *ExtraCode, raw_ostream &O) { 309 // Target doesn't support this yet! 310 return true; 311} 312 313