summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/MC/MCParser/MCAsmParser.h36
-rw-r--r--lib/MC/MCParser/AsmParser.cpp219
2 files changed, 221 insertions, 34 deletions
diff --git a/include/llvm/MC/MCParser/MCAsmParser.h b/include/llvm/MC/MCParser/MCAsmParser.h
index 52948f749d6..ea20c15fe18 100644
--- a/include/llvm/MC/MCParser/MCAsmParser.h
+++ b/include/llvm/MC/MCParser/MCAsmParser.h
@@ -20,6 +20,8 @@ class MCAsmLexer;
class MCAsmParserExtension;
class MCContext;
class MCExpr;
+class MCInstPrinter;
+class MCInstrInfo;
class MCParsedAsmOperand;
class MCStreamer;
class MCTargetAsmParser;
@@ -29,6 +31,13 @@ class SourceMgr;
class StringRef;
class Twine;
+/// MCAsmParserSemaCallback - Generic Sema callback for assembly parser.
+class MCAsmParserSemaCallback {
+public:
+ virtual void *LookupInlineAsmIdentifier(StringRef Name, void *Loc,
+ void **IdentifierInfoPtr) = 0;
+};
+
/// MCAsmParser - Generic assembler parser interface, for use by target specific
/// assembly parsers.
class MCAsmParser {
@@ -77,25 +86,20 @@ public:
virtual void setParsingInlineAsm(bool V) = 0;
virtual bool isParsingInlineAsm() = 0;
+ /// ParseMSInlineAsm - Parse ms-style inline assembly.
+ virtual bool ParseMSInlineAsm(void *AsmLoc, std::string &AsmString,
+ unsigned &NumOutputs, unsigned &NumInputs,
+ SmallVectorImpl<void *> &Names,
+ SmallVectorImpl<std::string> &Constraints,
+ SmallVectorImpl<void *> &Exprs,
+ SmallVectorImpl<std::string> &Clobbers,
+ const MCInstrInfo *MII,
+ const MCInstPrinter *IP,
+ MCAsmParserSemaCallback &SI) = 0;
+
/// ParseStatement - Parse the next statement.
virtual bool ParseStatement() = 0;
- /// getNumParsedOperands - Returns the number of MCAsmParsedOperands from the
- /// previously parsed statement.
- virtual unsigned getNumParsedOperands() = 0;
-
- /// getParsedOperand - Get a MCAsmParsedOperand.
- virtual MCParsedAsmOperand &getParsedOperand(unsigned OpNum) = 0;
-
- /// freeParsedOperands - Free the MCAsmParsedOperands.
- virtual void freeParsedOperands() = 0;
-
- /// isInstruction - Was the previously parsed statement an instruction?
- virtual bool isInstruction() = 0;
-
- /// getOpcode - Get the opcode from the previously parsed instruction.
- virtual unsigned getOpcode() = 0;
-
/// Warning - Emit a warning at the location \p L, with the message \p Msg.
///
/// \return The return value is true, if warnings are fatal.
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index a5d06663176..78a877baa0b 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -19,6 +19,8 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCParser/AsmCond.h"
#include "llvm/MC/MCParser/AsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
@@ -35,6 +37,8 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include <cctype>
+#include <set>
+#include <string>
#include <vector>
using namespace llvm;
@@ -139,7 +143,8 @@ private:
/// ParsedOperands - The parsed operands from the last parsed statement.
SmallVector<MCParsedAsmOperand*, 8> ParsedOperands;
- /// Opcode - The opcode from the last parsed instruction.
+ /// Opcode - The opcode from the last parsed instruction. This is MS-style
+ /// inline asm specific.
unsigned Opcode;
public:
@@ -180,21 +185,18 @@ public:
virtual const AsmToken &Lex();
- bool ParseStatement();
void setParsingInlineAsm(bool V) { ParsingInlineAsm = V; }
bool isParsingInlineAsm() { return ParsingInlineAsm; }
- unsigned getNumParsedOperands() { return ParsedOperands.size(); }
- MCParsedAsmOperand &getParsedOperand(unsigned OpNum) {
- assert (ParsedOperands.size() > OpNum);
- return *ParsedOperands[OpNum];
- }
- void freeParsedOperands() {
- for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i)
- delete ParsedOperands[i];
- ParsedOperands.clear();
- }
- bool isInstruction() { return Opcode != (unsigned)~0x0; }
- unsigned getOpcode() { return Opcode; }
+
+ bool ParseMSInlineAsm(void *AsmLoc, std::string &AsmString,
+ unsigned &NumOutputs, unsigned &NumInputs,
+ SmallVectorImpl<void *> &Names,
+ SmallVectorImpl<std::string> &Constraints,
+ SmallVectorImpl<void *> &Exprs,
+ SmallVectorImpl<std::string> &Clobbers,
+ const MCInstrInfo *MII,
+ const MCInstPrinter *IP,
+ MCAsmParserSemaCallback &SI);
bool ParseExpression(const MCExpr *&Res);
virtual bool ParseExpression(const MCExpr *&Res, SMLoc &EndLoc);
@@ -206,6 +208,7 @@ public:
private:
void CheckForValidSection();
+ bool ParseStatement();
void EatToEndOfLine();
bool ParseCppHashLineFilenameComment(const SMLoc &L);
@@ -311,6 +314,10 @@ private:
bool ParseDirectiveIrp(SMLoc DirectiveLoc); // ".irp"
bool ParseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc"
bool ParseDirectiveEndr(SMLoc DirectiveLoc); // ".endr"
+
+ // MS-style inline assembly parsing.
+ bool isInstruction() { return Opcode != (unsigned)~0x0; }
+ unsigned getOpcode() { return Opcode; }
};
/// \brief Generic implementations of directive handling, etc. which is shared
@@ -1378,10 +1385,13 @@ bool AsmParser::ParseStatement() {
ParsingInlineAsm);
}
- // Free any parsed operands. If parsing ms-style inline assembly it is the
- // responsibility of the caller (i.e., clang) to free the parsed operands.
- if (!ParsingInlineAsm)
- freeParsedOperands();
+ // Free any parsed operands. If parsing ms-style inline assembly the operands
+ // will be freed by the ParseMSInlineAsm() function.
+ if (!ParsingInlineAsm) {
+ for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i)
+ delete ParsedOperands[i];
+ ParsedOperands.clear();
+ }
// Don't skip the rest of the line, the instruction parser is responsible for
// that.
@@ -3562,6 +3572,179 @@ bool AsmParser::ParseDirectiveEndr(SMLoc DirectiveLoc) {
return false;
}
+namespace {
+enum AsmOpRewriteKind {
+ AOK_Imm,
+ AOK_Input,
+ AOK_Output
+};
+
+struct AsmOpRewrite {
+ AsmOpRewriteKind Kind;
+ SMLoc Loc;
+ unsigned Len;
+
+public:
+ AsmOpRewrite(AsmOpRewriteKind kind, SMLoc loc, unsigned len)
+ : Kind(kind), Loc(loc), Len(len) { }
+};
+}
+
+bool AsmParser::ParseMSInlineAsm(void *AsmLoc, std::string &AsmString,
+ unsigned &NumOutputs, unsigned &NumInputs,
+ SmallVectorImpl<void *> &Names,
+ SmallVectorImpl<std::string> &Constraints,
+ SmallVectorImpl<void *> &Exprs,
+ SmallVectorImpl<std::string> &Clobbers,
+ const MCInstrInfo *MII,
+ const MCInstPrinter *IP,
+ MCAsmParserSemaCallback &SI) {
+ SmallVector<void*, 4> Inputs;
+ SmallVector<void*, 4> Outputs;
+ SmallVector<std::string, 4> InputConstraints;
+ SmallVector<std::string, 4> OutputConstraints;
+ SmallVector<void*, 4> InputExprs;
+ SmallVector<void*, 4> OutputExprs;
+ std::set<std::string> ClobberRegs;
+
+ SmallVector<struct AsmOpRewrite, 4> AsmStrRewrites;
+
+ // Prime the lexer.
+ Lex();
+
+ // While we have input, parse each statement.
+ unsigned InputIdx = 0;
+ unsigned OutputIdx = 0;
+ while (getLexer().isNot(AsmToken::Eof)) {
+ if (ParseStatement()) return true;
+
+ if (isInstruction()) {
+ const MCInstrDesc &Desc = MII->get(getOpcode());
+
+ // Build the list of clobbers, outputs and inputs.
+ for (unsigned i = 1, e = ParsedOperands.size(); i != e; ++i) {
+ MCParsedAsmOperand *Operand = ParsedOperands[i];
+
+ // Immediate.
+ if (Operand->isImm()) {
+ AsmStrRewrites.push_back(AsmOpRewrite(AOK_Imm,
+ Operand->getStartLoc(),
+ Operand->getNameLen()));
+ continue;
+ }
+
+ // Register operand.
+ if (Operand->isReg()) {
+ unsigned NumDefs = Desc.getNumDefs();
+ // Clobber.
+ if (NumDefs && Operand->getMCOperandNum() < NumDefs) {
+ std::string Reg;
+ raw_string_ostream OS(Reg);
+ IP->printRegName(OS, Operand->getReg());
+ ClobberRegs.insert(StringRef(OS.str()));
+ }
+ continue;
+ }
+
+ // Expr/Input or Output.
+ void *II;
+ void *ExprResult = SI.LookupInlineAsmIdentifier(Operand->getName(),
+ AsmLoc, &II);
+ if (ExprResult) {
+ bool isOutput = (i == 1) && Desc.mayStore();
+ if (isOutput) {
+ std::string Constraint = "=";
+ ++InputIdx;
+ Outputs.push_back(II);
+ OutputExprs.push_back(ExprResult);
+ 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(ExprResult);
+ InputConstraints.push_back(Operand->getConstraint().str());
+ AsmStrRewrites.push_back(AsmOpRewrite(AOK_Input,
+ Operand->getStartLoc(),
+ Operand->getNameLen()));
+ }
+ }
+ }
+ // Free any parsed operands.
+ for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i)
+ delete ParsedOperands[i];
+ ParsedOperands.clear();
+ }
+ }
+
+ // Set the number of Outputs and Inputs.
+ NumOutputs = Outputs.size();
+ NumInputs = Inputs.size();
+
+ // Set the unique clobbers.
+ for (std::set<std::string>::iterator I = ClobberRegs.begin(),
+ E = ClobberRegs.end(); I != E; ++I)
+ Clobbers.push_back(*I);
+
+ // Merge the various outputs and inputs. Output are expected first.
+ if (NumOutputs || NumInputs) {
+ unsigned NumExprs = NumOutputs + NumInputs;
+ Names.resize(NumExprs);
+ Constraints.resize(NumExprs);
+ Exprs.resize(NumExprs);
+ for (unsigned i = 0; i < NumOutputs; ++i) {
+ Names[i] = Outputs[i];
+ Constraints[i] = OutputConstraints[i];
+ Exprs[i] = OutputExprs[i];
+ }
+ for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {
+ Names[j] = Inputs[i];
+ Constraints[j] = InputConstraints[i];
+ Exprs[j] = InputExprs[i];
+ }
+ }
+
+ // Build the IR assembly string.
+ std::string AsmStringIR;
+ raw_string_ostream OS(AsmStringIR);
+ const char *Start = SrcMgr.getMemoryBuffer(0)->getBufferStart();
+ 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 = SrcMgr.getMemoryBuffer(0)->getBufferEnd();
+ if (Start != AsmEnd)
+ OS << StringRef(Start, AsmEnd - Start);
+
+ AsmString = OS.str();
+ return false;
+}
+
/// \brief Create an MCAsmParser instance.
MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM,
MCContext &C, MCStreamer &Out,