aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorChad Rosier <mcrosier@apple.com>2012-10-15 19:56:10 +0000
committerChad Rosier <mcrosier@apple.com>2012-10-15 19:56:10 +0000
commitd9b56edcf42232c5331f9ad79aae83ba31e852df (patch)
tree6e3f63a4f15c343d3e5b7d2b8c039824e6e8c83a /lib/Sema
parent6553c686cb419b22b4c79d05a422fb1e96f6e122 (diff)
[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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165957 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaStmtAsm.cpp396
1 files changed, 179 insertions, 217 deletions
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 017cdb90f6..339ff7a953 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -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>");
-
- // 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());
+ 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());
+
+ 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();
-
- // Parse the opcode.
- StringRef IDVal;
- Parser->ParseIdentifier(IDVal);
-
- // 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!");
-
- // 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); }
-
- // 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); }
-
- // 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.
- 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);
+ // Get the instruction descriptor.
+ const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
+ llvm::MCInstPrinter *IP =
+ TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
+
+ // Change to the Intel dialect.
+ Parser->setAssemblerDialect(1);
+ Parser->setTargetParser(*TargetParser.get());
+ Parser->setParsingInlineAsm(true);
+
+ // Prime the lexer.
+ Parser->Lex();
+
+ // 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;
+ }
+
+ if (Parser->isInstruction()) {
+ const llvm::MCInstrDesc &Desc = MII->get(Parser->getOpcode());
+
+ // Build the list of clobbers, outputs and inputs.
+ for (unsigned i = 1, e = Parser->getNumParsedOperands(); i != e; ++i) {
+ llvm::MCParsedAsmOperand &Operand = Parser->getParsedOperand(i);
+
+ // 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;
}
- }
-
- // 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];
- }
+ // 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);
- 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);