move the asm string analysis code out of codegen into common

code where Sema can get to it.  No functionality change.

llvm-svn: 66596
This commit is contained in:
Chris Lattner 2009-03-10 23:21:44 +00:00
parent dab7b9355f
commit 35b5836147
3 changed files with 182 additions and 116 deletions

View File

@ -24,7 +24,6 @@
#include "llvm/Bitcode/SerializationFwd.h"
#include "clang/AST/ASTContext.h"
#include <string>
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<AsmStringPiece> &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]; }

View File

@ -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<AsmStringPiece> &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
//===----------------------------------------------------------------------===//

View File

@ -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<AsmStmt::AsmStringPiece, 4> 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;