[ms-inline asm] Move most of the AsmParsing logic in clang back into the MC
authorChad Rosier <mcrosier@apple.com>
Thu, 18 Oct 2012 15:49:34 +0000 (15:49 +0000)
committerChad Rosier <mcrosier@apple.com>
Thu, 18 Oct 2012 15:49:34 +0000 (15:49 +0000)
layer.  Add the ParseMSInlineAsm() function, which is the new interface to
clang.  Also expose the new MCAsmParserSemaCallback interface, which is used
by the back-end to do name lookup in Sema.  Finally, remove the now defunct
APIs introduced in r165946.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166183 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCParser/MCAsmParser.h
lib/MC/MCParser/AsmParser.cpp

index 52948f749d64b1cebc37354a446c288f24a3bea2..ea20c15fe18e1087989c4c5d849c52523b9375b7 100644 (file)
@@ -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.
index a5d0666317648c00f71a26596c277b47d0d47ef3..78a877baa0bd8600accaced479ce46ef873184c9 100644 (file)
@@ -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,