[ms-inline asm] Rework the front-end to use the API introduced in r165946.

-The front-end now builds a single assembly string and feeds it to the
 AsmParser.  The front-end iterates on a per statement basis by calling the
 ParseStatement() function.  Please note, the calling of ParseStatement() and
 and any notion of MCAsmParsedOperands will be sunk into the MC layer in the
 near future.  I plan to expose more basic APIs such as getClobbers, etc.

-The enumeration of the AsmString expressions have been reworked to use SMLocs
 rather than assembly Pieces, which were being parsed in the front-end.

-The test case, t8(), was modified due to r129223.  I'll have to find a way to
 work around things such as these.

Sorry for the large commit, but breaking this in multiple smaller commits proved
too irritating.

llvm-svn: 165957
This commit is contained in:
Chad Rosier 2012-10-15 19:56:10 +00:00
parent aee00b5e72
commit 4a0054f383
2 changed files with 173 additions and 211 deletions

View File

@ -331,34 +331,11 @@ static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
return Asm;
}
// Break the AsmString into pieces (i.e., mnemonic and operands).
static void buildMSAsmPieces(StringRef Asm, std::vector<StringRef> &Pieces) {
std::pair<StringRef,StringRef> Split = Asm.split(' ');
// Mnemonic
Pieces.push_back(Split.first);
Asm = Split.second;
// Operands
while (!Asm.empty()) {
Split = Asm.split(", ");
Pieces.push_back(Split.first);
Asm = Split.second;
}
}
static void buildMSAsmPieces(std::vector<std::string> &AsmStrings,
std::vector<std::vector<StringRef> > &Pieces) {
for (unsigned i = 0, e = AsmStrings.size(); i != e; ++i)
buildMSAsmPieces(AsmStrings[i], Pieces[i]);
}
// Build the individual assembly instruction(s) and place them in the AsmStrings
// vector. These strings are fed to the AsmParser. Returns true on error.
static bool buildMSAsmStrings(Sema &SemaRef,
SourceLocation AsmLoc,
ArrayRef<Token> AsmToks,
std::vector<std::string> &AsmStrings) {
// Build the inline assembly string. Returns true on error.
static bool buildMSAsmString(Sema &SemaRef,
SourceLocation AsmLoc,
ArrayRef<Token> AsmToks,
std::string &AsmString) {
assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
SmallString<512> Asm;
@ -366,18 +343,17 @@ static bool buildMSAsmStrings(Sema &SemaRef,
bool isNewAsm = ((i == 0) ||
AsmToks[i].isAtStartOfLine() ||
AsmToks[i].is(tok::kw_asm));
if (isNewAsm) {
if (i) {
AsmStrings.push_back(Asm.str());
Asm.clear();
}
if (i != 0)
Asm += "\n\t";
if (AsmToks[i].is(tok::kw_asm)) {
i++; // Skip __asm
if (i == e) {
SemaRef.Diag(AsmLoc, diag::err_asm_empty);
return true;
}
}
}
@ -387,47 +363,59 @@ static bool buildMSAsmStrings(Sema &SemaRef,
StringRef Spelling = getSpelling(SemaRef, AsmToks[i]);
Asm += Spelling;
}
AsmStrings.push_back(Asm.str());
AsmString = Asm.str();
return false;
}
#define DEF_SIMPLE_MSASM(STR) \
MSAsmStmt *NS = \
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, \
/*IsVolatile*/ true, AsmToks, Inputs, Outputs, \
InputExprs, OutputExprs, STR, Constraints, \
Clobbers, EndLoc);
namespace {
enum AsmOpRewriteKind {
AOK_Imm,
AOK_Input,
AOK_Output
};
struct AsmOpRewrite {
AsmOpRewriteKind Kind;
llvm::SMLoc Loc;
unsigned Len;
public:
AsmOpRewrite(AsmOpRewriteKind kind, llvm::SMLoc loc, unsigned len)
: Kind(kind), Loc(loc), Len(len) { }
};
}
StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
ArrayRef<Token> AsmToks,SourceLocation EndLoc) {
SmallVector<StringRef, 4> Constraints;
std::vector<std::string> InputConstraints;
std::vector<std::string> OutputConstraints;
SmallVector<StringRef, 4> Clobbers;
std::set<std::string> ClobberRegs;
// FIXME: Use a struct to hold the various expression information.
SmallVector<IdentifierInfo*, 4> Inputs;
SmallVector<IdentifierInfo*, 4> Outputs;
SmallVector<Expr*, 4> InputExprs;
SmallVector<Expr*, 4> OutputExprs;
SmallVector<std::string, 4> InputExprNames;
SmallVector<std::string, 4> OutputExprNames;
SmallVector<unsigned, 4> InputExprStrIdx;
SmallVector<unsigned, 4> OutputExprStrIdx;
SmallVector<StringRef, 4> Constraints;
SmallVector<std::string, 4> InputConstraints;
SmallVector<std::string, 4> OutputConstraints;
SmallVector<StringRef, 4> Clobbers;
std::set<std::string> ClobberRegs;
SmallVector<struct AsmOpRewrite, 4> AsmStrRewrites;
// Empty asm statements don't need to instantiate the AsmParser, etc.
StringRef EmptyAsmStr;
if (AsmToks.empty()) { DEF_SIMPLE_MSASM(EmptyAsmStr); return Owned(NS); }
if (AsmToks.empty()) {
StringRef EmptyAsmStr;
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
/*IsVolatile*/ true, AsmToks, Inputs, Outputs,
InputExprs, OutputExprs, EmptyAsmStr, Constraints,
Clobbers, EndLoc);
return Owned(NS);
}
std::vector<std::string> AsmStrings;
if (buildMSAsmStrings(*this, AsmLoc, AsmToks, AsmStrings))
std::string AsmString;
if (buildMSAsmString(*this, AsmLoc, AsmToks, AsmString))
return StmtError();
std::vector<std::vector<StringRef> > Pieces(AsmStrings.size());
buildMSAsmPieces(AsmStrings, Pieces);
// Get the target specific parser.
std::string Error;
const std::string &TT = Context.getTargetInfo().getTriple().getTriple();
@ -439,113 +427,111 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
OwningPtr<llvm::MCSubtargetInfo>
STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
for (unsigned StrIdx = 0, e = AsmStrings.size(); StrIdx != e; ++StrIdx) {
llvm::SourceMgr SrcMgr;
llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
llvm::MemoryBuffer *Buffer =
llvm::MemoryBuffer::getMemBuffer(AsmStrings[StrIdx], "<inline asm>");
llvm::SourceMgr SrcMgr;
llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
llvm::MemoryBuffer *Buffer =
llvm::MemoryBuffer::getMemBuffer(AsmString, "<inline asm>");
// Tell SrcMgr about this buffer, which is what the parser will pick up.
SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
// Tell SrcMgr about this buffer, which is what the parser will pick up.
SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc());
OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
OwningPtr<llvm::MCAsmParser>
Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
OwningPtr<llvm::MCTargetAsmParser>
TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
// Change to the Intel dialect.
Parser->setAssemblerDialect(1);
Parser->setTargetParser(*TargetParser.get());
OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
OwningPtr<llvm::MCAsmParser>
Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
OwningPtr<llvm::MCTargetAsmParser>
TargetParser(TheTarget->createMCAsmParser(*STI, *Parser));
Parser->setParsingInlineAsm(true);
// Prime the lexer.
Parser->Lex();
// Get the instruction descriptor.
const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
llvm::MCInstPrinter *IP =
TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
// Parse the opcode.
StringRef IDVal;
Parser->ParseIdentifier(IDVal);
// Change to the Intel dialect.
Parser->setAssemblerDialect(1);
Parser->setTargetParser(*TargetParser.get());
Parser->setParsingInlineAsm(true);
// Canonicalize the opcode to lower case.
SmallString<128> OpcodeStr;
for (unsigned i = 0, e = IDVal.size(); i != e; ++i)
OpcodeStr.push_back(tolower(IDVal[i]));
// FIXME: Convert to a StmtError.
assert(TargetParser->mnemonicIsValid(OpcodeStr) && "Invalid mnemonic!");
// Prime the lexer.
Parser->Lex();
// Parse the operands.
llvm::SMLoc IDLoc;
SmallVector<llvm::MCParsedAsmOperand*, 8> Operands;
bool HadError = TargetParser->ParseInstruction(OpcodeStr.str(), IDLoc,
Operands);
// If we had an error parsing the operands, fail gracefully.
if (HadError) { DEF_SIMPLE_MSASM(EmptyAsmStr); return Owned(NS); }
// While we have input, parse each statement.
unsigned InputIdx = 0;
unsigned OutputIdx = 0;
while (Parser->getLexer().isNot(llvm::AsmToken::Eof)) {
if (Parser->ParseStatement()) {
// FIXME: The AsmParser should report errors, but we could potentially be
// more verbose here.
break;
}
// Match the MCInstr.
unsigned Opcode;
unsigned ErrorInfo;
HadError = TargetParser->MatchAndEmitInstruction(IDLoc, Opcode, Operands,
*Str.get(), ErrorInfo,
/*MatchingInlineAsm*/ true);
// If we had an error parsing the operands, fail gracefully.
if (HadError) { DEF_SIMPLE_MSASM(EmptyAsmStr); return Owned(NS); }
if (Parser->isInstruction()) {
const llvm::MCInstrDesc &Desc = MII->get(Parser->getOpcode());
// Get the instruction descriptor.
const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
const llvm::MCInstrDesc &Desc = MII->get(Opcode);
llvm::MCInstPrinter *IP =
TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
// Build the list of clobbers, outputs and inputs.
for (unsigned i = 1, e = Parser->getNumParsedOperands(); i != e; ++i) {
llvm::MCParsedAsmOperand &Operand = Parser->getParsedOperand(i);
// Build the list of clobbers, outputs and inputs.
unsigned NumDefs = Desc.getNumDefs();
for (unsigned i = 1, e = Operands.size(); i != e; ++i) {
// Skip immediates.
if (Operands[i]->isImm())
continue;
// Register.
if (Operands[i]->isReg()) {
// Clobber.
if (NumDefs && (Operands[i]->getMCOperandNum() < NumDefs)) {
std::string Reg;
llvm::raw_string_ostream OS(Reg);
IP->printRegName(OS, Operands[i]->getReg());
StringRef Clobber(OS.str());
if (!Context.getTargetInfo().isValidClobber(Clobber))
return StmtError(
Diag(AsmLoc, diag::err_asm_unknown_register_name) << Clobber);
ClobberRegs.insert(Reg);
// Immediate.
if (Operand.isImm()) {
AsmStrRewrites.push_back(AsmOpRewrite(AOK_Imm,
Operand.getStartLoc(),
Operand.getNameLen()));
continue;
}
continue;
}
// Expr/Input or Output.
StringRef Name = Pieces[StrIdx][i];
if (IdentifierInfo *II = &Context.Idents.get(Name)) {
CXXScopeSpec SS;
UnqualifiedId Id;
SourceLocation Loc;
Id.setIdentifier(II, AsmLoc);
ExprResult Result = ActOnIdExpression(getCurScope(), SS, Loc, Id,
false, false);
if (!Result.isInvalid()) {
bool isMemDef = (i == 1) && Desc.mayStore();
if (isMemDef) {
Outputs.push_back(II);
OutputExprs.push_back(Result.take());
OutputExprNames.push_back(Name.str());
OutputExprStrIdx.push_back(StrIdx);
std::string Constraint = "=" + Operands[i]->getConstraint().str();
OutputConstraints.push_back(Constraint);
} else {
Inputs.push_back(II);
InputExprs.push_back(Result.take());
InputExprNames.push_back(Name.str());
InputExprStrIdx.push_back(StrIdx);
InputConstraints.push_back(Operands[i]->getConstraint());
// Register operand.
if (Operand.isReg()) {
unsigned NumDefs = Desc.getNumDefs();
// Clobber.
if (NumDefs && Operand.getMCOperandNum() < NumDefs) {
std::string Reg;
llvm::raw_string_ostream OS(Reg);
IP->printRegName(OS, Operand.getReg());
StringRef Clobber(OS.str());
if (!Context.getTargetInfo().isValidClobber(Clobber))
return StmtError(
Diag(AsmLoc, diag::err_asm_unknown_register_name) << Clobber);
ClobberRegs.insert(Reg);
}
continue;
}
// Expr/Input or Output.
StringRef Name = Operand.getName();
if (IdentifierInfo *II = &Context.Idents.get(Name)) {
CXXScopeSpec SS;
UnqualifiedId Id;
SourceLocation Loc;
Id.setIdentifier(II, AsmLoc);
ExprResult Result = ActOnIdExpression(getCurScope(), SS, Loc, Id,
false, false);
if (!Result.isInvalid()) {
bool isOutput = (i == 1) && Desc.mayStore();
if (isOutput) {
std::string Constraint = "=";
++InputIdx;
Outputs.push_back(II);
OutputExprs.push_back(Result.take());
Constraint += Operand.getConstraint().str();
OutputConstraints.push_back(Constraint);
AsmStrRewrites.push_back(AsmOpRewrite(AOK_Output,
Operand.getStartLoc(),
Operand.getNameLen()));
} else {
Inputs.push_back(II);
InputExprs.push_back(Result.take());
InputConstraints.push_back(Operand.getConstraint().str());
AsmStrRewrites.push_back(AsmOpRewrite(AOK_Input,
Operand.getStartLoc(),
Operand.getNameLen()));
}
}
}
}
Parser->freeParsedOperands();
}
}
for (std::set<std::string>::iterator I = ClobberRegs.begin(),
@ -554,75 +540,51 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
// Merge the output and input constraints. Output constraints are expected
// first.
for (std::vector<std::string>::iterator I = OutputConstraints.begin(),
for (SmallVectorImpl<std::string>::iterator I = OutputConstraints.begin(),
E = OutputConstraints.end(); I != E; ++I)
Constraints.push_back(*I);
for (std::vector<std::string>::iterator I = InputConstraints.begin(),
for (SmallVectorImpl<std::string>::iterator I = InputConstraints.begin(),
E = InputConstraints.end(); I != E; ++I)
Constraints.push_back(*I);
// Enumerate the AsmString expressions.
unsigned OpNum = 0;
for (unsigned i = 0, e = OutputExprNames.size(); i != e; ++i, ++OpNum) {
unsigned StrIdx = OutputExprStrIdx[i];
// Iterate over the assembly instruction pieces, skipping the mnemonic.
for (unsigned j = 1, f = Pieces[StrIdx].size(); j != f; ++j) {
// If the operand and the expression name match, then rewrite the operand.
if (OutputExprNames[i] == Pieces[StrIdx][j]) {
SmallString<32> Res;
llvm::raw_svector_ostream OS(Res);
OS << '$' << OpNum;
OutputExprNames[i] = OS.str();
Pieces[StrIdx][j] = OutputExprNames[i];
break;
}
}
}
for (unsigned i = 0, e = InputExprNames.size(); i != e; ++i, ++OpNum) {
unsigned StrIdx = InputExprStrIdx[i];
// Iterate over the assembly instruction pieces, skipping the mnemonic.
for (unsigned j = 1, f = Pieces[StrIdx].size(); j != f; ++j) {
// If the operand and the expression name match, then rewrite the operand.
if (InputExprNames[i] == Pieces[StrIdx][j]) {
SmallString<32> Res;
llvm::raw_svector_ostream OS(Res);
OS << '$' << OpNum;
InputExprNames[i] = OS.str();
Pieces[StrIdx][j] = InputExprNames[i];
break;
}
// Build the IR assembly string.
std::string AsmStringIR;
llvm::raw_string_ostream OS(AsmStringIR);
const char *Start = AsmString.c_str();
for (SmallVectorImpl<struct AsmOpRewrite>::iterator I = AsmStrRewrites.begin(),
E = AsmStrRewrites.end(); I != E; ++I) {
const char *Loc = (*I).Loc.getPointer();
// Emit everything up to the immediate/expression.
OS << StringRef(Start, Loc - Start);
// Rewrite expressions in $N notation.
switch ((*I).Kind) {
case AOK_Imm:
OS << Twine("$$") + StringRef(Loc, (*I).Len);
break;
case AOK_Input:
OS << '$';
OS << InputIdx++;
break;
case AOK_Output:
OS << '$';
OS << OutputIdx++;
break;
}
// Skip the original expression.
Start = Loc + (*I).Len;
}
// Emit the remainder of the asm string.
const char *AsmEnd = AsmString.c_str() + AsmString.size();
if (Start != AsmEnd)
OS << StringRef(Start, AsmEnd - Start);
// Emit the IR assembly string.
std::string AsmString;
for (unsigned i = 0, e = Pieces.size(); i != e; ++i) {
// Skip empty asm stmts.
if (Pieces[i].empty()) continue;
if (i > 0)
AsmString += "\n\t";
// Emit the mnemonic.
AsmString += Pieces[i][0];
if (Pieces[i].size() > 1)
AsmString += ' ';
// Emit the operands adding $$ to constants.
for (unsigned j = 1, f = Pieces[i].size(); j != f; ++j) {
if (j > 1) AsmString += ", ";
unsigned Val;
if (!Pieces[i][j].getAsInteger(0, Val))
AsmString += "$$";
AsmString += Pieces[i][j];
}
}
bool IsSimple = Inputs.size() != 0 || Outputs.size() != 0;
AsmString = OS.str();
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ false,
/*IsVolatile*/ true, AsmToks, Inputs, Outputs,
InputExprs, OutputExprs, AsmString, Constraints,
Clobbers, EndLoc);

View File

@ -59,12 +59,12 @@ void t7() {
}
int t8() {
__asm int 3 ; } comments for single-line asm
__asm int 4 ; } comments for single-line asm
__asm {}
__asm int 4
return 10;
// CHECK: t8
// CHECK: call void asm sideeffect inteldialect "int $$3", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"() nounwind
// CHECK: ret i32 10