1203954Srdivacky//===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===// 2203954Srdivacky// 3203954Srdivacky// The LLVM Compiler Infrastructure 4203954Srdivacky// 5203954Srdivacky// This file is distributed under the University of Illinois Open Source 6203954Srdivacky// License. See LICENSE.TXT for details. 7203954Srdivacky// 8203954Srdivacky//===----------------------------------------------------------------------===// 9203954Srdivacky// 10203954Srdivacky// These classes implement a parser for assembly strings. 11203954Srdivacky// 12203954Srdivacky//===----------------------------------------------------------------------===// 13203954Srdivacky 14203954Srdivacky#include "AsmWriterInst.h" 15203954Srdivacky#include "CodeGenTarget.h" 16203954Srdivacky#include "llvm/ADT/StringExtras.h" 17243830Sdim#include "llvm/TableGen/Error.h" 18226633Sdim#include "llvm/TableGen/Record.h" 19203954Srdivacky 20203954Srdivackyusing namespace llvm; 21203954Srdivacky 22203954Srdivackystatic bool isIdentChar(char C) { 23203954Srdivacky return (C >= 'a' && C <= 'z') || 24203954Srdivacky (C >= 'A' && C <= 'Z') || 25203954Srdivacky (C >= '0' && C <= '9') || 26203954Srdivacky C == '_'; 27203954Srdivacky} 28203954Srdivacky 29203954Srdivackystd::string AsmWriterOperand::getCode() const { 30203954Srdivacky if (OperandType == isLiteralTextOperand) { 31203954Srdivacky if (Str.size() == 1) 32203954Srdivacky return "O << '" + Str + "'; "; 33203954Srdivacky return "O << \"" + Str + "\"; "; 34203954Srdivacky } 35263508Sdim 36203954Srdivacky if (OperandType == isLiteralStatementOperand) 37203954Srdivacky return Str; 38263508Sdim 39203954Srdivacky std::string Result = Str + "(MI"; 40203954Srdivacky if (MIOpNo != ~0U) 41203954Srdivacky Result += ", " + utostr(MIOpNo); 42206274Srdivacky Result += ", O"; 43203954Srdivacky if (!MiModifier.empty()) 44203954Srdivacky Result += ", \"" + MiModifier + '"'; 45203954Srdivacky return Result + "); "; 46203954Srdivacky} 47203954Srdivacky 48203954Srdivacky/// ParseAsmString - Parse the specified Instruction's AsmString into this 49203954Srdivacky/// AsmWriterInst. 50203954Srdivacky/// 51203954SrdivackyAsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, 52203954Srdivacky unsigned Variant, 53203954Srdivacky int FirstOperandColumn, 54203954Srdivacky int OperandSpacing) { 55203954Srdivacky this->CGI = &CGI; 56263508Sdim 57203954Srdivacky // This is the number of tabs we've seen if we're doing columnar layout. 58203954Srdivacky unsigned CurColumn = 0; 59263508Sdim 60263508Sdim 61263508Sdim // NOTE: Any extensions to this code need to be mirrored in the 62203954Srdivacky // AsmPrinter::printInlineAsm code that executes as compile time (assuming 63203954Srdivacky // that inline asm strings should also get the new feature)! 64218893Sdim std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant); 65203954Srdivacky std::string::size_type LastEmitted = 0; 66203954Srdivacky while (LastEmitted != AsmString.size()) { 67203954Srdivacky std::string::size_type DollarPos = 68218893Sdim AsmString.find_first_of("$\\", LastEmitted); 69203954Srdivacky if (DollarPos == std::string::npos) DollarPos = AsmString.size(); 70263508Sdim 71203954Srdivacky // Emit a constant string fragment. 72203954Srdivacky if (DollarPos != LastEmitted) { 73218893Sdim for (; LastEmitted != DollarPos; ++LastEmitted) 74218893Sdim switch (AsmString[LastEmitted]) { 75218893Sdim case '\n': 76218893Sdim AddLiteralString("\\n"); 77218893Sdim break; 78218893Sdim case '\t': 79218893Sdim // If the asm writer is not using a columnar layout, \t is not 80218893Sdim // magic. 81218893Sdim if (FirstOperandColumn == -1 || OperandSpacing == -1) { 82218893Sdim AddLiteralString("\\t"); 83218893Sdim } else { 84218893Sdim // We recognize a tab as an operand delimeter. 85263508Sdim unsigned DestColumn = FirstOperandColumn + 86218893Sdim CurColumn++ * OperandSpacing; 87218893Sdim Operands.push_back( 88218893Sdim AsmWriterOperand( 89218893Sdim "O.PadToColumn(" + 90218893Sdim utostr(DestColumn) + ");\n", 91218893Sdim AsmWriterOperand::isLiteralStatementOperand)); 92218893Sdim } 93218893Sdim break; 94218893Sdim case '"': 95218893Sdim AddLiteralString("\\\""); 96218893Sdim break; 97218893Sdim case '\\': 98218893Sdim AddLiteralString("\\\\"); 99218893Sdim break; 100218893Sdim default: 101218893Sdim AddLiteralString(std::string(1, AsmString[LastEmitted])); 102218893Sdim break; 103218893Sdim } 104203954Srdivacky } else if (AsmString[DollarPos] == '\\') { 105218893Sdim if (DollarPos+1 != AsmString.size()) { 106203954Srdivacky if (AsmString[DollarPos+1] == 'n') { 107203954Srdivacky AddLiteralString("\\n"); 108203954Srdivacky } else if (AsmString[DollarPos+1] == 't') { 109203954Srdivacky // If the asm writer is not using a columnar layout, \t is not 110203954Srdivacky // magic. 111203954Srdivacky if (FirstOperandColumn == -1 || OperandSpacing == -1) { 112203954Srdivacky AddLiteralString("\\t"); 113203954Srdivacky break; 114203954Srdivacky } 115263508Sdim 116203954Srdivacky // We recognize a tab as an operand delimeter. 117263508Sdim unsigned DestColumn = FirstOperandColumn + 118203954Srdivacky CurColumn++ * OperandSpacing; 119203954Srdivacky Operands.push_back( 120203954Srdivacky AsmWriterOperand("O.PadToColumn(" + utostr(DestColumn) + ");\n", 121203954Srdivacky AsmWriterOperand::isLiteralStatementOperand)); 122203954Srdivacky break; 123263508Sdim } else if (std::string("${|}\\").find(AsmString[DollarPos+1]) 124203954Srdivacky != std::string::npos) { 125203954Srdivacky AddLiteralString(std::string(1, AsmString[DollarPos+1])); 126203954Srdivacky } else { 127243830Sdim PrintFatalError("Non-supported escaped character found in instruction '" + 128243830Sdim CGI.TheDef->getName() + "'!"); 129203954Srdivacky } 130203954Srdivacky LastEmitted = DollarPos+2; 131203954Srdivacky continue; 132203954Srdivacky } 133203954Srdivacky } else if (DollarPos+1 != AsmString.size() && 134203954Srdivacky AsmString[DollarPos+1] == '$') { 135218893Sdim AddLiteralString("$"); // "$$" -> $ 136203954Srdivacky LastEmitted = DollarPos+2; 137203954Srdivacky } else { 138203954Srdivacky // Get the name of the variable. 139203954Srdivacky std::string::size_type VarEnd = DollarPos+1; 140263508Sdim 141203954Srdivacky // handle ${foo}bar as $foo by detecting whether the character following 142203954Srdivacky // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos 143203954Srdivacky // so the variable name does not contain the leading curly brace. 144203954Srdivacky bool hasCurlyBraces = false; 145203954Srdivacky if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { 146203954Srdivacky hasCurlyBraces = true; 147203954Srdivacky ++DollarPos; 148203954Srdivacky ++VarEnd; 149203954Srdivacky } 150263508Sdim 151203954Srdivacky while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 152203954Srdivacky ++VarEnd; 153203954Srdivacky std::string VarName(AsmString.begin()+DollarPos+1, 154203954Srdivacky AsmString.begin()+VarEnd); 155263508Sdim 156203954Srdivacky // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed 157203954Srdivacky // into printOperand. Also support ${:feature}, which is passed into 158203954Srdivacky // PrintSpecial. 159203954Srdivacky std::string Modifier; 160263508Sdim 161203954Srdivacky // In order to avoid starting the next string at the terminating curly 162203954Srdivacky // brace, advance the end position past it if we found an opening curly 163203954Srdivacky // brace. 164203954Srdivacky if (hasCurlyBraces) { 165203954Srdivacky if (VarEnd >= AsmString.size()) 166243830Sdim PrintFatalError("Reached end of string before terminating curly brace in '" 167243830Sdim + CGI.TheDef->getName() + "'"); 168263508Sdim 169203954Srdivacky // Look for a modifier string. 170203954Srdivacky if (AsmString[VarEnd] == ':') { 171203954Srdivacky ++VarEnd; 172203954Srdivacky if (VarEnd >= AsmString.size()) 173243830Sdim PrintFatalError("Reached end of string before terminating curly brace in '" 174243830Sdim + CGI.TheDef->getName() + "'"); 175263508Sdim 176203954Srdivacky unsigned ModifierStart = VarEnd; 177203954Srdivacky while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 178203954Srdivacky ++VarEnd; 179203954Srdivacky Modifier = std::string(AsmString.begin()+ModifierStart, 180203954Srdivacky AsmString.begin()+VarEnd); 181203954Srdivacky if (Modifier.empty()) 182243830Sdim PrintFatalError("Bad operand modifier name in '"+ CGI.TheDef->getName() + "'"); 183203954Srdivacky } 184263508Sdim 185203954Srdivacky if (AsmString[VarEnd] != '}') 186243830Sdim PrintFatalError("Variable name beginning with '{' did not end with '}' in '" 187243830Sdim + CGI.TheDef->getName() + "'"); 188203954Srdivacky ++VarEnd; 189203954Srdivacky } 190203954Srdivacky if (VarName.empty() && Modifier.empty()) 191243830Sdim PrintFatalError("Stray '$' in '" + CGI.TheDef->getName() + 192243830Sdim "' asm string, maybe you want $$?"); 193263508Sdim 194203954Srdivacky if (VarName.empty()) { 195203954Srdivacky // Just a modifier, pass this into PrintSpecial. 196263508Sdim Operands.push_back(AsmWriterOperand("PrintSpecial", 197263508Sdim ~0U, 198263508Sdim ~0U, 199203954Srdivacky Modifier)); 200203954Srdivacky } else { 201203954Srdivacky // Otherwise, normal operand. 202218893Sdim unsigned OpNo = CGI.Operands.getOperandNamed(VarName); 203218893Sdim CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; 204263508Sdim 205218893Sdim unsigned MIOp = OpInfo.MIOperandNo; 206263508Sdim Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, 207218893Sdim OpNo, MIOp, Modifier)); 208203954Srdivacky } 209203954Srdivacky LastEmitted = VarEnd; 210203954Srdivacky } 211203954Srdivacky } 212263508Sdim 213203954Srdivacky Operands.push_back(AsmWriterOperand("return;", 214203954Srdivacky AsmWriterOperand::isLiteralStatementOperand)); 215203954Srdivacky} 216203954Srdivacky 217203954Srdivacky/// MatchesAllButOneOp - If this instruction is exactly identical to the 218203954Srdivacky/// specified instruction except for one differing operand, return the differing 219203954Srdivacky/// operand number. If more than one operand mismatches, return ~1, otherwise 220203954Srdivacky/// if the instructions are identical return ~0. 221203954Srdivackyunsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{ 222203954Srdivacky if (Operands.size() != Other.Operands.size()) return ~1; 223263508Sdim 224203954Srdivacky unsigned MismatchOperand = ~0U; 225203954Srdivacky for (unsigned i = 0, e = Operands.size(); i != e; ++i) { 226203954Srdivacky if (Operands[i] != Other.Operands[i]) { 227203954Srdivacky if (MismatchOperand != ~0U) // Already have one mismatch? 228203954Srdivacky return ~1U; 229263508Sdim MismatchOperand = i; 230203954Srdivacky } 231203954Srdivacky } 232203954Srdivacky return MismatchOperand; 233203954Srdivacky} 234