1*0fca6ea1SDimitry Andric //===- AsmWriterInst.h - Classes encapsulating a printable inst -----------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // These classes implement a parser for assembly strings. 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #include "AsmWriterInst.h" 14*0fca6ea1SDimitry Andric #include "CodeGenInstruction.h" 15*0fca6ea1SDimitry Andric #include "llvm/ADT/StringExtras.h" 16*0fca6ea1SDimitry Andric #include "llvm/TableGen/Error.h" 17*0fca6ea1SDimitry Andric #include "llvm/TableGen/Record.h" 18*0fca6ea1SDimitry Andric 19*0fca6ea1SDimitry Andric using namespace llvm; 20*0fca6ea1SDimitry Andric 21*0fca6ea1SDimitry Andric static bool isIdentChar(char C) { return isAlnum(C) || C == '_'; } 22*0fca6ea1SDimitry Andric 23*0fca6ea1SDimitry Andric std::string AsmWriterOperand::getCode(bool PassSubtarget) const { 24*0fca6ea1SDimitry Andric if (OperandType == isLiteralTextOperand) { 25*0fca6ea1SDimitry Andric if (Str.size() == 1) 26*0fca6ea1SDimitry Andric return "O << '" + Str + "';"; 27*0fca6ea1SDimitry Andric return "O << \"" + Str + "\";"; 28*0fca6ea1SDimitry Andric } 29*0fca6ea1SDimitry Andric 30*0fca6ea1SDimitry Andric if (OperandType == isLiteralStatementOperand) 31*0fca6ea1SDimitry Andric return Str; 32*0fca6ea1SDimitry Andric 33*0fca6ea1SDimitry Andric std::string Result = Str + "(MI"; 34*0fca6ea1SDimitry Andric if (PCRel) 35*0fca6ea1SDimitry Andric Result += ", Address"; 36*0fca6ea1SDimitry Andric if (MIOpNo != ~0U) 37*0fca6ea1SDimitry Andric Result += ", " + utostr(MIOpNo); 38*0fca6ea1SDimitry Andric if (PassSubtarget) 39*0fca6ea1SDimitry Andric Result += ", STI"; 40*0fca6ea1SDimitry Andric Result += ", O"; 41*0fca6ea1SDimitry Andric if (!MiModifier.empty()) 42*0fca6ea1SDimitry Andric Result += ", \"" + MiModifier + '"'; 43*0fca6ea1SDimitry Andric return Result + ");"; 44*0fca6ea1SDimitry Andric } 45*0fca6ea1SDimitry Andric 46*0fca6ea1SDimitry Andric /// ParseAsmString - Parse the specified Instruction's AsmString into this 47*0fca6ea1SDimitry Andric /// AsmWriterInst. 48*0fca6ea1SDimitry Andric /// 49*0fca6ea1SDimitry Andric AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned CGIIndex, 50*0fca6ea1SDimitry Andric unsigned Variant) 51*0fca6ea1SDimitry Andric : CGI(&CGI), CGIIndex(CGIIndex) { 52*0fca6ea1SDimitry Andric 53*0fca6ea1SDimitry Andric // NOTE: Any extensions to this code need to be mirrored in the 54*0fca6ea1SDimitry Andric // AsmPrinter::printInlineAsm code that executes as compile time (assuming 55*0fca6ea1SDimitry Andric // that inline asm strings should also get the new feature)! 56*0fca6ea1SDimitry Andric std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant); 57*0fca6ea1SDimitry Andric std::string::size_type LastEmitted = 0; 58*0fca6ea1SDimitry Andric while (LastEmitted != AsmString.size()) { 59*0fca6ea1SDimitry Andric std::string::size_type DollarPos = 60*0fca6ea1SDimitry Andric AsmString.find_first_of("$\\", LastEmitted); 61*0fca6ea1SDimitry Andric if (DollarPos == std::string::npos) 62*0fca6ea1SDimitry Andric DollarPos = AsmString.size(); 63*0fca6ea1SDimitry Andric 64*0fca6ea1SDimitry Andric // Emit a constant string fragment. 65*0fca6ea1SDimitry Andric if (DollarPos != LastEmitted) { 66*0fca6ea1SDimitry Andric for (; LastEmitted != DollarPos; ++LastEmitted) 67*0fca6ea1SDimitry Andric switch (AsmString[LastEmitted]) { 68*0fca6ea1SDimitry Andric case '\n': 69*0fca6ea1SDimitry Andric AddLiteralString("\\n"); 70*0fca6ea1SDimitry Andric break; 71*0fca6ea1SDimitry Andric case '\t': 72*0fca6ea1SDimitry Andric AddLiteralString("\\t"); 73*0fca6ea1SDimitry Andric break; 74*0fca6ea1SDimitry Andric case '"': 75*0fca6ea1SDimitry Andric AddLiteralString("\\\""); 76*0fca6ea1SDimitry Andric break; 77*0fca6ea1SDimitry Andric case '\\': 78*0fca6ea1SDimitry Andric AddLiteralString("\\\\"); 79*0fca6ea1SDimitry Andric break; 80*0fca6ea1SDimitry Andric default: 81*0fca6ea1SDimitry Andric AddLiteralString(std::string(1, AsmString[LastEmitted])); 82*0fca6ea1SDimitry Andric break; 83*0fca6ea1SDimitry Andric } 84*0fca6ea1SDimitry Andric } else if (AsmString[DollarPos] == '\\') { 85*0fca6ea1SDimitry Andric if (DollarPos + 1 != AsmString.size()) { 86*0fca6ea1SDimitry Andric if (AsmString[DollarPos + 1] == 'n') { 87*0fca6ea1SDimitry Andric AddLiteralString("\\n"); 88*0fca6ea1SDimitry Andric } else if (AsmString[DollarPos + 1] == 't') { 89*0fca6ea1SDimitry Andric AddLiteralString("\\t"); 90*0fca6ea1SDimitry Andric } else if (std::string("${|}\\").find(AsmString[DollarPos + 1]) != 91*0fca6ea1SDimitry Andric std::string::npos) { 92*0fca6ea1SDimitry Andric AddLiteralString(std::string(1, AsmString[DollarPos + 1])); 93*0fca6ea1SDimitry Andric } else { 94*0fca6ea1SDimitry Andric PrintFatalError( 95*0fca6ea1SDimitry Andric CGI.TheDef->getLoc(), 96*0fca6ea1SDimitry Andric "Non-supported escaped character found in instruction '" + 97*0fca6ea1SDimitry Andric CGI.TheDef->getName() + "'!"); 98*0fca6ea1SDimitry Andric } 99*0fca6ea1SDimitry Andric LastEmitted = DollarPos + 2; 100*0fca6ea1SDimitry Andric continue; 101*0fca6ea1SDimitry Andric } 102*0fca6ea1SDimitry Andric } else if (DollarPos + 1 != AsmString.size() && 103*0fca6ea1SDimitry Andric AsmString[DollarPos + 1] == '$') { 104*0fca6ea1SDimitry Andric AddLiteralString("$"); // "$$" -> $ 105*0fca6ea1SDimitry Andric LastEmitted = DollarPos + 2; 106*0fca6ea1SDimitry Andric } else { 107*0fca6ea1SDimitry Andric // Get the name of the variable. 108*0fca6ea1SDimitry Andric std::string::size_type VarEnd = DollarPos + 1; 109*0fca6ea1SDimitry Andric 110*0fca6ea1SDimitry Andric // handle ${foo}bar as $foo by detecting whether the character following 111*0fca6ea1SDimitry Andric // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos 112*0fca6ea1SDimitry Andric // so the variable name does not contain the leading curly brace. 113*0fca6ea1SDimitry Andric bool hasCurlyBraces = false; 114*0fca6ea1SDimitry Andric if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) { 115*0fca6ea1SDimitry Andric hasCurlyBraces = true; 116*0fca6ea1SDimitry Andric ++DollarPos; 117*0fca6ea1SDimitry Andric ++VarEnd; 118*0fca6ea1SDimitry Andric } 119*0fca6ea1SDimitry Andric 120*0fca6ea1SDimitry Andric while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 121*0fca6ea1SDimitry Andric ++VarEnd; 122*0fca6ea1SDimitry Andric StringRef VarName(AsmString.data() + DollarPos + 1, 123*0fca6ea1SDimitry Andric VarEnd - DollarPos - 1); 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed 126*0fca6ea1SDimitry Andric // into printOperand. Also support ${:feature}, which is passed into 127*0fca6ea1SDimitry Andric // PrintSpecial. 128*0fca6ea1SDimitry Andric std::string Modifier; 129*0fca6ea1SDimitry Andric 130*0fca6ea1SDimitry Andric // In order to avoid starting the next string at the terminating curly 131*0fca6ea1SDimitry Andric // brace, advance the end position past it if we found an opening curly 132*0fca6ea1SDimitry Andric // brace. 133*0fca6ea1SDimitry Andric if (hasCurlyBraces) { 134*0fca6ea1SDimitry Andric if (VarEnd >= AsmString.size()) 135*0fca6ea1SDimitry Andric PrintFatalError( 136*0fca6ea1SDimitry Andric CGI.TheDef->getLoc(), 137*0fca6ea1SDimitry Andric "Reached end of string before terminating curly brace in '" + 138*0fca6ea1SDimitry Andric CGI.TheDef->getName() + "'"); 139*0fca6ea1SDimitry Andric 140*0fca6ea1SDimitry Andric // Look for a modifier string. 141*0fca6ea1SDimitry Andric if (AsmString[VarEnd] == ':') { 142*0fca6ea1SDimitry Andric ++VarEnd; 143*0fca6ea1SDimitry Andric if (VarEnd >= AsmString.size()) 144*0fca6ea1SDimitry Andric PrintFatalError( 145*0fca6ea1SDimitry Andric CGI.TheDef->getLoc(), 146*0fca6ea1SDimitry Andric "Reached end of string before terminating curly brace in '" + 147*0fca6ea1SDimitry Andric CGI.TheDef->getName() + "'"); 148*0fca6ea1SDimitry Andric 149*0fca6ea1SDimitry Andric std::string::size_type ModifierStart = VarEnd; 150*0fca6ea1SDimitry Andric while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd])) 151*0fca6ea1SDimitry Andric ++VarEnd; 152*0fca6ea1SDimitry Andric Modifier = AsmString.substr(ModifierStart, VarEnd - ModifierStart); 153*0fca6ea1SDimitry Andric if (Modifier.empty()) 154*0fca6ea1SDimitry Andric PrintFatalError(CGI.TheDef->getLoc(), 155*0fca6ea1SDimitry Andric "Bad operand modifier name in '" + 156*0fca6ea1SDimitry Andric CGI.TheDef->getName() + "'"); 157*0fca6ea1SDimitry Andric } 158*0fca6ea1SDimitry Andric 159*0fca6ea1SDimitry Andric if (AsmString[VarEnd] != '}') 160*0fca6ea1SDimitry Andric PrintFatalError( 161*0fca6ea1SDimitry Andric CGI.TheDef->getLoc(), 162*0fca6ea1SDimitry Andric "Variable name beginning with '{' did not end with '}' in '" + 163*0fca6ea1SDimitry Andric CGI.TheDef->getName() + "'"); 164*0fca6ea1SDimitry Andric ++VarEnd; 165*0fca6ea1SDimitry Andric } 166*0fca6ea1SDimitry Andric if (VarName.empty() && Modifier.empty()) 167*0fca6ea1SDimitry Andric PrintFatalError(CGI.TheDef->getLoc(), 168*0fca6ea1SDimitry Andric "Stray '$' in '" + CGI.TheDef->getName() + 169*0fca6ea1SDimitry Andric "' asm string, maybe you want $$?"); 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric if (VarName.empty()) { 172*0fca6ea1SDimitry Andric // Just a modifier, pass this into PrintSpecial. 173*0fca6ea1SDimitry Andric Operands.emplace_back("PrintSpecial", ~0U, Modifier); 174*0fca6ea1SDimitry Andric } else { 175*0fca6ea1SDimitry Andric // Otherwise, normal operand. 176*0fca6ea1SDimitry Andric unsigned OpNo = CGI.Operands.getOperandNamed(VarName); 177*0fca6ea1SDimitry Andric CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; 178*0fca6ea1SDimitry Andric 179*0fca6ea1SDimitry Andric unsigned MIOp = OpInfo.MIOperandNo; 180*0fca6ea1SDimitry Andric Operands.emplace_back(OpInfo.PrinterMethodName, MIOp, Modifier, 181*0fca6ea1SDimitry Andric AsmWriterOperand::isMachineInstrOperand, 182*0fca6ea1SDimitry Andric OpInfo.OperandType == "MCOI::OPERAND_PCREL"); 183*0fca6ea1SDimitry Andric } 184*0fca6ea1SDimitry Andric LastEmitted = VarEnd; 185*0fca6ea1SDimitry Andric } 186*0fca6ea1SDimitry Andric } 187*0fca6ea1SDimitry Andric 188*0fca6ea1SDimitry Andric Operands.emplace_back("return;", AsmWriterOperand::isLiteralStatementOperand); 189*0fca6ea1SDimitry Andric } 190*0fca6ea1SDimitry Andric 191*0fca6ea1SDimitry Andric /// MatchesAllButOneOp - If this instruction is exactly identical to the 192*0fca6ea1SDimitry Andric /// specified instruction except for one differing operand, return the differing 193*0fca6ea1SDimitry Andric /// operand number. If more than one operand mismatches, return ~1, otherwise 194*0fca6ea1SDimitry Andric /// if the instructions are identical return ~0. 195*0fca6ea1SDimitry Andric unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other) const { 196*0fca6ea1SDimitry Andric if (Operands.size() != Other.Operands.size()) 197*0fca6ea1SDimitry Andric return ~1; 198*0fca6ea1SDimitry Andric 199*0fca6ea1SDimitry Andric unsigned MismatchOperand = ~0U; 200*0fca6ea1SDimitry Andric for (unsigned i = 0, e = Operands.size(); i != e; ++i) { 201*0fca6ea1SDimitry Andric if (Operands[i] != Other.Operands[i]) { 202*0fca6ea1SDimitry Andric if (MismatchOperand != ~0U) // Already have one mismatch? 203*0fca6ea1SDimitry Andric return ~1U; 204*0fca6ea1SDimitry Andric MismatchOperand = i; 205*0fca6ea1SDimitry Andric } 206*0fca6ea1SDimitry Andric } 207*0fca6ea1SDimitry Andric return MismatchOperand; 208*0fca6ea1SDimitry Andric } 209