-static bool isIdentChar(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9') ||
- C == '_';
-}
-
-namespace {
- struct AsmWriterOperand {
- enum { isLiteralTextOperand, isMachineInstrOperand } OperandType;
-
- /// Str - For isLiteralTextOperand, this IS the literal text. For
- /// isMachineInstrOperand, this is the PrinterMethodName for the operand.
- std::string Str;
-
- /// MiOpNo - For isMachineInstrOperand, this is the operand number of the
- /// machine instruction.
- unsigned MIOpNo;
-
- /// MiModifier - For isMachineInstrOperand, this is the modifier string for
- /// an operand, specified with syntax like ${opname:modifier}.
- std::string MiModifier;
-
- AsmWriterOperand(const std::string &LitStr)
- : OperandType(isLiteralTextOperand), Str(LitStr) {}
-
- AsmWriterOperand(const std::string &Printer, unsigned OpNo,
- const std::string &Modifier)
- : OperandType(isMachineInstrOperand), Str(Printer), MIOpNo(OpNo),
- MiModifier(Modifier) {}
-
- bool operator!=(const AsmWriterOperand &Other) const {
- if (OperandType != Other.OperandType || Str != Other.Str) return true;
- if (OperandType == isMachineInstrOperand)
- return MIOpNo != Other.MIOpNo || MiModifier != Other.MiModifier;
- return false;
- }
- bool operator==(const AsmWriterOperand &Other) const {
- return !operator!=(Other);
- }
-
- /// getCode - Return the code that prints this operand.
- std::string getCode() const;
- };
-}
-
-namespace llvm {
- struct AsmWriterInst {
- std::vector<AsmWriterOperand> Operands;
- const CodeGenInstruction *CGI;
-
- AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant);
-
- /// MatchesAllButOneOp - If this instruction is exactly identical to the
- /// specified instruction except for one differing operand, return the
- /// differing operand number. Otherwise return ~0.
- unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const;
-
- private:
- void AddLiteralString(const std::string &Str) {
- // If the last operand was already a literal text string, append this to
- // it, otherwise add a new operand.
- if (!Operands.empty() &&
- Operands.back().OperandType == AsmWriterOperand::isLiteralTextOperand)
- Operands.back().Str.append(Str);
- else
- Operands.push_back(AsmWriterOperand(Str));
- }
- };
-}
-
-
-std::string AsmWriterOperand::getCode() const {
- if (OperandType == isLiteralTextOperand)
- return "O << \"" + Str + "\"; ";
-
- std::string Result = Str + "(MI, " + utostr(MIOpNo);
- if (!MiModifier.empty())
- Result += ", \"" + MiModifier + '"';
- return Result + "); ";
-}
-
-
-/// ParseAsmString - Parse the specified Instruction's AsmString into this
-/// AsmWriterInst.
-///
-AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant) {
- this->CGI = &CGI;
- unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #.
-
- // NOTE: Any extensions to this code need to be mirrored in the
- // AsmPrinter::printInlineAsm code that executes as compile time (assuming
- // that inline asm strings should also get the new feature)!
- const std::string &AsmString = CGI.AsmString;
- std::string::size_type LastEmitted = 0;
- while (LastEmitted != AsmString.size()) {
- std::string::size_type DollarPos =
- AsmString.find_first_of("${|}", LastEmitted);
- if (DollarPos == std::string::npos) DollarPos = AsmString.size();
-
- // Emit a constant string fragment.
- if (DollarPos != LastEmitted) {
- // TODO: this should eventually handle escaping.
- if (CurVariant == Variant || CurVariant == ~0U)
- AddLiteralString(std::string(AsmString.begin()+LastEmitted,
- AsmString.begin()+DollarPos));
- LastEmitted = DollarPos;
- } else if (AsmString[DollarPos] == '{') {
- if (CurVariant != ~0U)
- throw "Nested variants found for instruction '" +
- CGI.TheDef->getName() + "'!";
- LastEmitted = DollarPos+1;
- CurVariant = 0; // We are now inside of the variant!
- } else if (AsmString[DollarPos] == '|') {
- if (CurVariant == ~0U)
- throw "'|' character found outside of a variant in instruction '"
- + CGI.TheDef->getName() + "'!";
- ++CurVariant;
- ++LastEmitted;
- } else if (AsmString[DollarPos] == '}') {
- if (CurVariant == ~0U)
- throw "'}' character found outside of a variant in instruction '"
- + CGI.TheDef->getName() + "'!";
- ++LastEmitted;
- CurVariant = ~0U;
- } else if (DollarPos+1 != AsmString.size() &&
- AsmString[DollarPos+1] == '$') {
- if (CurVariant == Variant || CurVariant == ~0U)
- AddLiteralString("$"); // "$$" -> $
- LastEmitted = DollarPos+2;
- } else {
- // Get the name of the variable.
- std::string::size_type VarEnd = DollarPos+1;
-
- // handle ${foo}bar as $foo by detecting whether the character following
- // the dollar sign is a curly brace. If so, advance VarEnd and DollarPos
- // so the variable name does not contain the leading curly brace.
- bool hasCurlyBraces = false;
- if (VarEnd < AsmString.size() && '{' == AsmString[VarEnd]) {
- hasCurlyBraces = true;
- ++DollarPos;
- ++VarEnd;
- }
-
- while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
- ++VarEnd;
- std::string VarName(AsmString.begin()+DollarPos+1,
- AsmString.begin()+VarEnd);
-
- // Modifier - Support ${foo:modifier} syntax, where "modifier" is passed
- // into printOperand.
- std::string Modifier;
-
- // In order to avoid starting the next string at the terminating curly
- // brace, advance the end position past it if we found an opening curly
- // brace.
- if (hasCurlyBraces) {
- if (VarEnd >= AsmString.size())
- throw "Reached end of string before terminating curly brace in '"
- + CGI.TheDef->getName() + "'";
-
- // Look for a modifier string.
- if (AsmString[VarEnd] == ':') {
- ++VarEnd;
- if (VarEnd >= AsmString.size())
- throw "Reached end of string before terminating curly brace in '"
- + CGI.TheDef->getName() + "'";
-
- unsigned ModifierStart = VarEnd;
- while (VarEnd < AsmString.size() && isIdentChar(AsmString[VarEnd]))
- ++VarEnd;
- Modifier = std::string(AsmString.begin()+ModifierStart,
- AsmString.begin()+VarEnd);
- if (Modifier.empty())
- throw "Bad operand modifier name in '"+ CGI.TheDef->getName() + "'";
- }
-
- if (AsmString[VarEnd] != '}')
- throw "Variable name beginning with '{' did not end with '}' in '"
- + CGI.TheDef->getName() + "'";
- ++VarEnd;
- }
- if (VarName.empty())
- throw "Stray '$' in '" + CGI.TheDef->getName() +
- "' asm string, maybe you want $$?";
-
- unsigned OpNo = CGI.getOperandNamed(VarName);
- CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo];
-
- // If this is a two-address instruction and we are not accessing the
- // 0th operand, remove an operand.
- unsigned MIOp = OpInfo.MIOperandNo;
- if (CGI.isTwoAddress && MIOp != 0) {
- if (MIOp == 1)
- throw "Should refer to operand #0 instead of #1 for two-address"
- " instruction '" + CGI.TheDef->getName() + "'!";
- --MIOp;
- }
-
- if (CurVariant == Variant || CurVariant == ~0U)
- Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, MIOp,
- Modifier));
- LastEmitted = VarEnd;
- }
- }
-
- AddLiteralString("\\n");
-}
-
-/// MatchesAllButOneOp - If this instruction is exactly identical to the
-/// specified instruction except for one differing operand, return the differing
-/// operand number. If more than one operand mismatches, return ~1, otherwise
-/// if the instructions are identical return ~0.
-unsigned AsmWriterInst::MatchesAllButOneOp(const AsmWriterInst &Other)const{
- if (Operands.size() != Other.Operands.size()) return ~1;
-
- unsigned MismatchOperand = ~0U;
- for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
- if (Operands[i] != Other.Operands[i])
- if (MismatchOperand != ~0U) // Already have one mismatch?
- return ~1U;
- else
- MismatchOperand = i;
- }
- return MismatchOperand;
-}
-