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