[cfe-commits] r165957 - in /cfe/trunk: lib/Sema/SemaStmtAsm.cpp test/CodeGen/ms-inline-asm.c

Chad Rosier mcrosier at apple.com
Mon Oct 15 12:56:10 PDT 2012


Author: mcrosier
Date: Mon Oct 15 14:56:10 2012
New Revision: 165957

URL: http://llvm.org/viewvc/llvm-project?rev=165957&view=rev
Log:
[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.

Modified:
    cfe/trunk/lib/Sema/SemaStmtAsm.cpp
    cfe/trunk/test/CodeGen/ms-inline-asm.c

Modified: cfe/trunk/lib/Sema/SemaStmtAsm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAsm.cpp?rev=165957&r1=165956&r2=165957&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAsm.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmtAsm.cpp Mon Oct 15 14:56:10 2012
@@ -331,34 +331,11 @@
   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 @@
     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 @@
     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 @@
   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();
+  // 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());
 
-    // 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);
+      // 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 @@
 
   // 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;
-      }
+  // 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;
     }
-  }
-  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;
-      }
-    }
-  }
 
-  // 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);

Modified: cfe/trunk/test/CodeGen/ms-inline-asm.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/ms-inline-asm.c?rev=165957&r1=165956&r2=165957&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/ms-inline-asm.c (original)
+++ cfe/trunk/test/CodeGen/ms-inline-asm.c Mon Oct 15 14:56:10 2012
@@ -59,12 +59,12 @@
 }
 
 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





More information about the cfe-commits mailing list