forked from OSchip/llvm-project
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:
parent
dab7b9355f
commit
35b5836147
|
@ -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]; }
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue