From: Chris Lattner Date: Tue, 10 Mar 2009 23:21:44 +0000 (+0000) Subject: move the asm string analysis code out of codegen into common X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=458cd9c8a79b25b87dcea43c9d97a4c59f194799;p=clang move the asm string analysis code out of codegen into common code where Sema can get to it. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66596 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index cb4159d61e..513c5d9556 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -24,7 +24,6 @@ #include "llvm/Bitcode/SerializationFwd.h" #include "clang/AST/ASTContext.h" #include - using llvm::dyn_cast_or_null; namespace clang { @@ -923,6 +922,61 @@ public: bool isVolatile() const { return IsVolatile; } bool isSimple() const { return IsSimple; } + //===--- Asm String Analysis ---===// + + const StringLiteral *getAsmString() const { return AsmStr; } + StringLiteral *getAsmString() { return AsmStr; } + + /// AsmStringPiece - this is part of a decomposed asm string specification + /// (for use with the AnalyzeAsmString function below). An asm string is + /// considered to be a concatenation of these parts. + class AsmStringPiece { + public: + enum Kind { + String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%". + Operand // Operand reference, with optional modifier %c4. + }; + private: + Kind MyKind; + std::string Str; + unsigned OperandNo; + public: + AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} + AsmStringPiece(unsigned OpNo, char Modifier) + : MyKind(Operand), Str(), OperandNo(OpNo) { + Str += Modifier; + } + + bool isString() const { return MyKind == String; } + bool isOperand() const { return MyKind == Operand; } + + const std::string &getString() const { + assert(isString()); + return Str; + } + + unsigned getOperandNo() const { + assert(isOperand()); + return OperandNo; + } + + /// getModifier - Get the modifier for this operand, if present. This + /// returns '\0' if there was no modifier. + char getModifier() const { + assert(isOperand()); + return Str[0]; + } + }; + + /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing + /// it into pieces. If the asm string is erroneous, emit errors and return + /// true, otherwise return false. This handles canonicalization and + /// translation of strings from GCC syntax to LLVM IR syntax, and handles + //// flattening of named references like %[foo] to Operand AsmStringPiece's. + bool AnalyzeAsmString(llvm::SmallVectorImpl &Pieces, + ASTContext &C) const; + + //===--- Output operands ---===// unsigned getNumOutputs() const { return NumOutputs; } @@ -992,9 +1046,6 @@ public: - const StringLiteral *getAsmString() const { return AsmStr; } - StringLiteral *getAsmString() { return AsmStr; } - unsigned getNumClobbers() const { return Clobbers.size(); } StringLiteral *getClobber(unsigned i) { return Clobbers[i]; } const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index b7feda9b8f..5335deba33 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -179,6 +179,118 @@ int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { } +/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing +/// it into pieces. If the asm string is erroneous, emit errors and return +/// true, otherwise return false. +bool AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl &Pieces, + ASTContext &C) const { + const char *StrStart = getAsmString()->getStrData(); + const char *StrEnd = StrStart + getAsmString()->getByteLength(); + + // "Simple" inline asms have no constraints or operands, just convert the asm + // string to escape $'s. + if (isSimple()) { + std::string Result; + for (; StrStart != StrEnd; ++StrStart) { + switch (*StrStart) { + case '$': + Result += "$$"; + break; + default: + Result += *StrStart; + break; + } + } + Pieces.push_back(AsmStringPiece(Result)); + return false; + } + + // CurStringPiece - The current string that we are building up as we scan the + // asm string. + std::string CurStringPiece; + + while (1) { + // Done with the string? + if (StrStart == StrEnd) { + if (!CurStringPiece.empty()) + Pieces.push_back(AsmStringPiece(CurStringPiece)); + return false; + } + + char CurChar = *StrStart++; + if (CurChar == '$') { + CurStringPiece += "$$"; + continue; + } else if (CurChar != '%') { + CurStringPiece += CurChar; + continue; + } + + // Escaped "%" character in asm string. + // FIXME: This should be caught during Sema. + assert(StrStart != StrEnd && "Trailing '%' in asm string."); + + char EscapedChar = *StrStart++; + if (EscapedChar == '%') { // %% -> % + // Escaped percentage sign. + CurStringPiece += '%'; + continue; + } + + if (EscapedChar == '=') { // %= -> Generate an unique ID. + CurStringPiece += "${:uid}"; + continue; + } + + // Otherwise, we have an operand. If we have accumulated a string so far, + // add it to the Pieces list. + if (!CurStringPiece.empty()) { + Pieces.push_back(AsmStringPiece(CurStringPiece)); + CurStringPiece.clear(); + } + + // Handle %x4 and %x[foo] by capturing x as the modifier character. + char Modifier = '\0'; + if (isalpha(EscapedChar)) { + Modifier = EscapedChar; + EscapedChar = *StrStart++; + } + + if (isdigit(EscapedChar)) { + // %n - Assembler operand n + char *End; + unsigned long N = strtoul(StrStart-1, &End, 10); + assert(End != StrStart-1 && "We know that EscapedChar is a digit!"); + StrStart = End; + + // FIXME: This should be caught during Sema. + //unsigned NumOperands = S.getNumOutputs() + S.getNumInputs(); + //assert(N < NumOperands && "Operand number out of range!"); + + Pieces.push_back(AsmStringPiece(N, Modifier)); + continue; + } + + // Handle %[foo], a symbolic operand reference. + if (EscapedChar == '[') { + const char *NameEnd = (const char*)memchr(StrStart, ']', StrEnd-StrStart); + // FIXME: Should be caught by sema. + // FIXME: Does sema catch multiple operands with the same name? + assert(NameEnd != 0 && "Could not parse symbolic name"); + std::string SymbolicName(StrStart, NameEnd); + StrStart = NameEnd+1; + + int N = getNamedOperand(SymbolicName); + assert(N != -1 && "FIXME: Catch in Sema."); + Pieces.push_back(AsmStringPiece(N, Modifier)); + continue; + } + + assert(0 && "FIXME: Reject"); + return true; + } +} + //===----------------------------------------------------------------------===// // Constructors //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 1ada5ba419..26eb039d53 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -680,112 +680,6 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { CaseRangeBlock = SavedCRBlock; } -/// ConvertAsmString - Convert the GNU-style asm string to the LLVM-style asm -/// string. -static std::string ConvertAsmString(const AsmStmt& S, bool &Failed) { - Failed = false; - - const char *StrStart = S.getAsmString()->getStrData(); - const char *StrEnd = StrStart + S.getAsmString()->getByteLength(); - - // "Simple" inline asms have no constraints or operands, just convert the asm - // string to escape $'s. - if (S.isSimple()) { - std::string Result; - for (; StrStart != StrEnd; ++StrStart) { - switch (*StrStart) { - case '$': - Result += "$$"; - break; - default: - Result += *StrStart; - break; - } - } - return Result; - } - - std::string Result; - - while (1) { - // Done with the string? - if (StrStart == StrEnd) - return Result; - - char CurChar = *StrStart++; - if (CurChar == '$') { - Result += "$$"; - continue; - } else if (CurChar != '%') { - Result += CurChar; - continue; - } - - // Escaped "%" character in asm string. - // FIXME: This should be caught during Sema. - assert(StrStart != StrEnd && "Trailing '%' in asm string."); - - char EscapedChar = *StrStart++; - if (EscapedChar == '%') { // %% -> % - // Escaped percentage sign. - Result += '%'; - continue; - } - - if (EscapedChar == '=') { // %= -> Generate an unique ID. - Result += "${:uid}"; - continue; - } - - // Handle %x4 and %x[foo] by capturing x as the modifier character. - char Modifier = '\0'; - if (isalpha(EscapedChar)) { - Modifier = EscapedChar; - EscapedChar = *StrStart++; - } - - if (isdigit(EscapedChar)) { - // %n - Assembler operand n - char *End; - unsigned long N = strtoul(StrStart-1, &End, 10); - assert(End != StrStart-1 && "We know that EscapedChar is a digit!"); - StrStart = End; - - // FIXME: This should be caught during Sema. - //unsigned NumOperands = S.getNumOutputs() + S.getNumInputs(); - //assert(N < NumOperands && "Operand number out of range!"); - - if (Modifier == '\0') - Result += '$' + llvm::utostr(N); - else - Result += "${" + llvm::utostr(N) + ':' + Modifier + '}'; - continue; - } - - // Handle %[foo], a symbolic operand reference. - if (EscapedChar == '[') { - const char *NameEnd = (const char*)memchr(StrStart, ']', StrEnd-StrStart); - // FIXME: Should be caught by sema. - // FIXME: Does sema catch multiple operands with the same name? - assert(NameEnd != 0 && "Could not parse symbolic name"); - std::string SymbolicName(StrStart, NameEnd); - StrStart = NameEnd+1; - - int N = S.getNamedOperand(SymbolicName); - assert(N != -1 && "FIXME: Catch in Sema."); - - if (Modifier == '\0') - Result += '$' + llvm::utostr(N); - else - Result += "${" + llvm::utostr(N) + ':' + Modifier + '}'; - continue; - } - - Failed = true; - return ""; - } -} - static std::string SimplifyConstraint(const char* Constraint, TargetInfo &Target, const std::string *OutputNamesBegin = 0, @@ -859,12 +753,21 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, } void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { - bool Failed; - std::string AsmString = ConvertAsmString(S, Failed); - - if (Failed) { - ErrorUnsupported(&S, "asm string"); - return; + // Analyze the asm string to decompose it into its pieces. We know that Sema + // has already done this, so it is guaranteed to be successful. + llvm::SmallVector Pieces; + S.AnalyzeAsmString(Pieces, getContext()); + + // Assemble the pieces into the final asm string. + std::string AsmString; + for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { + if (Pieces[i].isString()) + AsmString += Pieces[i].getString(); + else if (Pieces[i].getModifier() == '\0') + AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo()); + else + AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' + + Pieces[i].getModifier() + '}'; } std::string Constraints;