[cfe-commits] r162132 - in /cfe/trunk/lib/Sema: CMakeLists.txt SemaStmt.cpp SemaStmtAsm.cpp

Chad Rosier mcrosier at apple.com
Fri Aug 17 14:19:40 PDT 2012


Author: mcrosier
Date: Fri Aug 17 16:19:40 2012
New Revision: 162132

URL: http://llvm.org/viewvc/llvm-project?rev=162132&view=rev
Log:
[ms-inline asm] Extract AsmStmt handling into a separate file, so as to not
pollute SemaStmt with extraneous asm handling logic.

Added:
    cfe/trunk/lib/Sema/SemaStmtAsm.cpp
Modified:
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/SemaStmt.cpp

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=162132&r1=162131&r2=162132&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Fri Aug 17 16:19:40 2012
@@ -39,6 +39,7 @@
   SemaOverload.cpp
   SemaPseudoObject.cpp
   SemaStmt.cpp
+  SemaStmtAsm.cpp
   SemaStmtAttr.cpp
   SemaTemplate.cpp
   SemaTemplateDeduction.cpp

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=162132&r1=162131&r2=162132&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri Aug 17 16:19:40 2012
@@ -28,27 +28,10 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCInst.h"
-#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetAsmParser.h"
-#include "llvm/MC/MCParser/MCAsmLexer.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
 using namespace clang;
 using namespace sema;
 
@@ -2485,600 +2468,6 @@
   return Owned(Result);
 }
 
-/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
-/// ignore "noop" casts in places where an lvalue is required by an inline asm.
-/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
-/// provide a strong guidance to not use it.
-///
-/// This method checks to see if the argument is an acceptable l-value and
-/// returns false if it is a case we can handle.
-static bool CheckAsmLValue(const Expr *E, Sema &S) {
-  // Type dependent expressions will be checked during instantiation.
-  if (E->isTypeDependent())
-    return false;
-
-  if (E->isLValue())
-    return false;  // Cool, this is an lvalue.
-
-  // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
-  // are supposed to allow.
-  const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
-  if (E != E2 && E2->isLValue()) {
-    if (!S.getLangOpts().HeinousExtensions)
-      S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
-        << E->getSourceRange();
-    else
-      S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
-        << E->getSourceRange();
-    // Accept, even if we emitted an error diagnostic.
-    return false;
-  }
-
-  // None of the above, just randomly invalid non-lvalue.
-  return true;
-}
-
-/// isOperandMentioned - Return true if the specified operand # is mentioned
-/// anywhere in the decomposed asm string.
-static bool isOperandMentioned(unsigned OpNo,
-                         ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
-  for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
-    const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
-    if (!Piece.isOperand()) continue;
-
-    // If this is a reference to the input and if the input was the smaller
-    // one, then we have to reject this asm.
-    if (Piece.getOperandNo() == OpNo)
-      return true;
-  }
-  return false;
-}
-
-StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
-                              bool IsVolatile, unsigned NumOutputs,
-                              unsigned NumInputs, IdentifierInfo **Names,
-                              MultiExprArg constraints, MultiExprArg exprs,
-                              Expr *asmString, MultiExprArg clobbers,
-                              SourceLocation RParenLoc, bool MSAsm) {
-  unsigned NumClobbers = clobbers.size();
-  StringLiteral **Constraints =
-    reinterpret_cast<StringLiteral**>(constraints.get());
-  Expr **Exprs = exprs.get();
-  StringLiteral *AsmString = cast<StringLiteral>(asmString);
-  StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
-
-  SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
-
-  // The parser verifies that there is a string literal here.
-  if (!AsmString->isAscii())
-    return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
-      << AsmString->getSourceRange());
-
-  for (unsigned i = 0; i != NumOutputs; i++) {
-    StringLiteral *Literal = Constraints[i];
-    if (!Literal->isAscii())
-      return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
-        << Literal->getSourceRange());
-
-    StringRef OutputName;
-    if (Names[i])
-      OutputName = Names[i]->getName();
-
-    TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
-    if (!Context.getTargetInfo().validateOutputConstraint(Info))
-      return StmtError(Diag(Literal->getLocStart(),
-                            diag::err_asm_invalid_output_constraint)
-                       << Info.getConstraintStr());
-
-    // Check that the output exprs are valid lvalues.
-    Expr *OutputExpr = Exprs[i];
-    if (CheckAsmLValue(OutputExpr, *this)) {
-      return StmtError(Diag(OutputExpr->getLocStart(),
-                  diag::err_asm_invalid_lvalue_in_output)
-        << OutputExpr->getSourceRange());
-    }
-
-    OutputConstraintInfos.push_back(Info);
-  }
-
-  SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
-
-  for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
-    StringLiteral *Literal = Constraints[i];
-    if (!Literal->isAscii())
-      return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
-        << Literal->getSourceRange());
-
-    StringRef InputName;
-    if (Names[i])
-      InputName = Names[i]->getName();
-
-    TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
-    if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
-                                                NumOutputs, Info)) {
-      return StmtError(Diag(Literal->getLocStart(),
-                            diag::err_asm_invalid_input_constraint)
-                       << Info.getConstraintStr());
-    }
-
-    Expr *InputExpr = Exprs[i];
-
-    // Only allow void types for memory constraints.
-    if (Info.allowsMemory() && !Info.allowsRegister()) {
-      if (CheckAsmLValue(InputExpr, *this))
-        return StmtError(Diag(InputExpr->getLocStart(),
-                              diag::err_asm_invalid_lvalue_in_input)
-                         << Info.getConstraintStr()
-                         << InputExpr->getSourceRange());
-    }
-
-    if (Info.allowsRegister()) {
-      if (InputExpr->getType()->isVoidType()) {
-        return StmtError(Diag(InputExpr->getLocStart(),
-                              diag::err_asm_invalid_type_in_input)
-          << InputExpr->getType() << Info.getConstraintStr()
-          << InputExpr->getSourceRange());
-      }
-    }
-
-    ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
-    if (Result.isInvalid())
-      return StmtError();
-
-    Exprs[i] = Result.take();
-    InputConstraintInfos.push_back(Info);
-  }
-
-  // Check that the clobbers are valid.
-  for (unsigned i = 0; i != NumClobbers; i++) {
-    StringLiteral *Literal = Clobbers[i];
-    if (!Literal->isAscii())
-      return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
-        << Literal->getSourceRange());
-
-    StringRef Clobber = Literal->getString();
-
-    if (!Context.getTargetInfo().isValidClobber(Clobber))
-      return StmtError(Diag(Literal->getLocStart(),
-                  diag::err_asm_unknown_register_name) << Clobber);
-  }
-
-  AsmStmt *NS =
-    new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
-                          NumOutputs, NumInputs, Names, Constraints, Exprs,
-                          AsmString, NumClobbers, Clobbers, RParenLoc);
-  // Validate the asm string, ensuring it makes sense given the operands we
-  // have.
-  SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
-  unsigned DiagOffs;
-  if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
-    Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
-           << AsmString->getSourceRange();
-    return StmtError();
-  }
-
-  // Validate tied input operands for type mismatches.
-  for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
-    TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
-
-    // If this is a tied constraint, verify that the output and input have
-    // either exactly the same type, or that they are int/ptr operands with the
-    // same size (int/long, int*/long, are ok etc).
-    if (!Info.hasTiedOperand()) continue;
-
-    unsigned TiedTo = Info.getTiedOperand();
-    unsigned InputOpNo = i+NumOutputs;
-    Expr *OutputExpr = Exprs[TiedTo];
-    Expr *InputExpr = Exprs[InputOpNo];
-
-    if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
-      continue;
-
-    QualType InTy = InputExpr->getType();
-    QualType OutTy = OutputExpr->getType();
-    if (Context.hasSameType(InTy, OutTy))
-      continue;  // All types can be tied to themselves.
-
-    // Decide if the input and output are in the same domain (integer/ptr or
-    // floating point.
-    enum AsmDomain {
-      AD_Int, AD_FP, AD_Other
-    } InputDomain, OutputDomain;
-
-    if (InTy->isIntegerType() || InTy->isPointerType())
-      InputDomain = AD_Int;
-    else if (InTy->isRealFloatingType())
-      InputDomain = AD_FP;
-    else
-      InputDomain = AD_Other;
-
-    if (OutTy->isIntegerType() || OutTy->isPointerType())
-      OutputDomain = AD_Int;
-    else if (OutTy->isRealFloatingType())
-      OutputDomain = AD_FP;
-    else
-      OutputDomain = AD_Other;
-
-    // They are ok if they are the same size and in the same domain.  This
-    // allows tying things like:
-    //   void* to int*
-    //   void* to int            if they are the same size.
-    //   double to long double   if they are the same size.
-    //
-    uint64_t OutSize = Context.getTypeSize(OutTy);
-    uint64_t InSize = Context.getTypeSize(InTy);
-    if (OutSize == InSize && InputDomain == OutputDomain &&
-        InputDomain != AD_Other)
-      continue;
-
-    // If the smaller input/output operand is not mentioned in the asm string,
-    // then we can promote the smaller one to a larger input and the asm string
-    // won't notice.
-    bool SmallerValueMentioned = false;
-
-    // If this is a reference to the input and if the input was the smaller
-    // one, then we have to reject this asm.
-    if (isOperandMentioned(InputOpNo, Pieces)) {
-      // This is a use in the asm string of the smaller operand.  Since we
-      // codegen this by promoting to a wider value, the asm will get printed
-      // "wrong".
-      SmallerValueMentioned |= InSize < OutSize;
-    }
-    if (isOperandMentioned(TiedTo, Pieces)) {
-      // If this is a reference to the output, and if the output is the larger
-      // value, then it's ok because we'll promote the input to the larger type.
-      SmallerValueMentioned |= OutSize < InSize;
-    }
-
-    // If the smaller value wasn't mentioned in the asm string, and if the
-    // output was a register, just extend the shorter one to the size of the
-    // larger one.
-    if (!SmallerValueMentioned && InputDomain != AD_Other &&
-        OutputConstraintInfos[TiedTo].allowsRegister())
-      continue;
-
-    // Either both of the operands were mentioned or the smaller one was
-    // mentioned.  One more special case that we'll allow: if the tied input is
-    // integer, unmentioned, and is a constant, then we'll allow truncating it
-    // down to the size of the destination.
-    if (InputDomain == AD_Int && OutputDomain == AD_Int &&
-        !isOperandMentioned(InputOpNo, Pieces) &&
-        InputExpr->isEvaluatable(Context)) {
-      CastKind castKind =
-        (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
-      InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
-      Exprs[InputOpNo] = InputExpr;
-      NS->setInputExpr(i, InputExpr);
-      continue;
-    }
-
-    Diag(InputExpr->getLocStart(),
-         diag::err_asm_tying_incompatible_types)
-      << InTy << OutTy << OutputExpr->getSourceRange()
-      << InputExpr->getSourceRange();
-    return StmtError();
-  }
-
-  return Owned(NS);
-}
-
-// isMSAsmKeyword - Return true if this is an MS-style inline asm keyword. These
-// require special handling.
-static bool isMSAsmKeyword(StringRef Name) {
-  bool Ret = llvm::StringSwitch<bool>(Name)
-    .Cases("EVEN", "ALIGN", true) // Alignment directives.
-    .Cases("LENGTH", "SIZE", "TYPE", true) // Type and variable sizes.
-    .Case("_emit", true) // _emit Pseudoinstruction.
-    .Default(false);
-  return Ret;
-}
-
-static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
-  StringRef Asm;
-  SmallString<512> TokenBuf;
-  TokenBuf.resize(512);
-  bool StringInvalid = false;
-  Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid);
-  assert (!StringInvalid && "Expected valid string!");
-  return Asm;
-}
-
-static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple,
-                              SourceLocation AsmLoc,
-                              ArrayRef<Token> AsmToks,
-                              const TargetInfo &TI,
-                              std::vector<llvm::BitVector> &AsmRegs,
-                              std::vector<llvm::BitVector> &AsmNames,
-                              std::vector<std::string> &AsmStrings) {
-  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
-
-  // Assume simple asm stmt until we parse a non-register identifer (or we just
-  // need to bail gracefully).
-  IsSimple = true;
-
-  SmallString<512> Asm;
-  unsigned NumAsmStrings = 0;
-  for (unsigned i = 0, e = AsmToks.size(); i != e; ++i) {
-
-    // Determine if this should be considered a new asm.
-    bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
-      AsmToks[i].is(tok::kw_asm);
-
-    // Emit the previous asm string.
-    if (i && isNewAsm) {
-      AsmStrings[NumAsmStrings++] = Asm.c_str();
-      if (AsmToks[i].is(tok::kw_asm)) {
-        ++i; // Skip __asm
-        assert (i != e && "Expected another token.");
-      }
-    }
-
-    // Start a new asm string with the opcode.
-    if (isNewAsm) {
-      AsmRegs[NumAsmStrings].resize(AsmToks.size());
-      AsmNames[NumAsmStrings].resize(AsmToks.size());
-
-      StringRef Piece = AsmToks[i].getIdentifierInfo()->getName();
-      // MS-style inline asm keywords require special handling.
-      if (isMSAsmKeyword(Piece))
-        IsSimple = false;
-
-      // TODO: Verify this is a valid opcode.
-      Asm = Piece;
-      continue;
-    }
-
-    if (i && AsmToks[i].hasLeadingSpace())
-      Asm += ' ';
-
-    // Check the operand(s).
-    switch (AsmToks[i].getKind()) {
-    default:
-      IsSimple = false;
-      Asm += getSpelling(SemaRef, AsmToks[i]);
-      break;
-    case tok::comma: Asm += ","; break;
-    case tok::colon: Asm += ":"; break;
-    case tok::l_square: Asm += "["; break;
-    case tok::r_square: Asm += "]"; break;
-    case tok::l_brace: Asm += "{"; break;
-    case tok::r_brace: Asm += "}"; break;
-    case tok::numeric_constant:
-      Asm += getSpelling(SemaRef, AsmToks[i]);
-      break;
-    case tok::identifier: {
-      IdentifierInfo *II = AsmToks[i].getIdentifierInfo();
-      StringRef Name = II->getName();
-
-      // Valid register?
-      if (TI.isValidGCCRegisterName(Name)) {
-        AsmRegs[NumAsmStrings].set(i);
-        Asm += Name;
-        break;
-      }
-
-      IsSimple = false;
-
-      // MS-style inline asm keywords require special handling.
-      if (isMSAsmKeyword(Name)) {
-        IsSimple = false;
-        Asm += Name;
-        break;
-      }
-
-      // FIXME: Why are we missing this segment register?
-      if (Name == "fs") {
-        Asm += Name;
-        break;
-      }
-
-      // Lookup the identifier.
-      // TODO: Someone with more experience with clang should verify this the
-      // proper way of doing a symbol lookup.
-      DeclarationName DeclName(II);
-      Scope *CurScope = SemaRef.getCurScope();
-      LookupResult R(SemaRef, DeclName, AsmLoc, Sema::LookupOrdinaryName);
-      if (!SemaRef.LookupName(R, CurScope, false/*AllowBuiltinCreation*/))
-        break;
-
-      assert (R.isSingleResult() && "Expected a single result?!");
-      NamedDecl *Decl = R.getFoundDecl();
-      switch (Decl->getKind()) {
-      default:
-        assert(0 && "Unknown decl kind.");
-        break;
-      case Decl::Var: {
-      case Decl::ParmVar:
-        AsmNames[NumAsmStrings].set(i);
-
-        VarDecl *Var = cast<VarDecl>(Decl);
-        QualType Ty = Var->getType();
-        (void)Ty; // Avoid warning.
-        // TODO: Patch identifier with valid operand.  One potential idea is to
-        // probe the backend with type information to guess the possible
-        // operand.
-        break;
-      }
-      }
-      break;
-    }
-    }
-  }
-
-  // Emit the final (and possibly only) asm string.
-  AsmStrings[NumAsmStrings] = Asm.c_str();
-}
-
-// Build the unmodified MSAsmString.
-static std::string buildMSAsmString(Sema &SemaRef,
-                                    ArrayRef<Token> AsmToks,
-                                    unsigned &NumAsmStrings) {
-  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
-  NumAsmStrings = 0;
-
-  SmallString<512> Asm;
-  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
-    bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
-      AsmToks[i].is(tok::kw_asm);
-
-    if (isNewAsm) {
-      ++NumAsmStrings;
-      if (i)
-        Asm += '\n';
-      if (AsmToks[i].is(tok::kw_asm)) {
-        i++; // Skip __asm
-        assert (i != e && "Expected another token");
-      }
-    }
-
-    if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
-      Asm += ' ';
-
-    Asm += getSpelling(SemaRef, AsmToks[i]);
-  }
-  return Asm.c_str();
-}
-
-StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc,
-                                SourceLocation LBraceLoc,
-                                ArrayRef<Token> AsmToks,
-                                SourceLocation EndLoc) {
-  // MS-style inline assembly is not fully supported, so emit a warning.
-  Diag(AsmLoc, diag::warn_unsupported_msasm);
-  SmallVector<StringRef,4> Clobbers;
-  std::set<std::string> ClobberRegs;
-  SmallVector<IdentifierInfo*, 4> Inputs;
-  SmallVector<IdentifierInfo*, 4> Outputs;
-
-  // Empty asm statements don't need to instantiate the AsmParser, etc.
-  if (AsmToks.empty()) {
-    StringRef AsmString;
-    MSAsmStmt *NS =
-      new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
-                              /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
-                              AsmString, Clobbers, EndLoc);
-    return Owned(NS);
-  }
-
-  unsigned NumAsmStrings;
-  std::string AsmString = buildMSAsmString(*this, AsmToks, NumAsmStrings);
-
-  bool IsSimple;
-  std::vector<llvm::BitVector> Regs;
-  std::vector<llvm::BitVector> Names;
-  std::vector<std::string> PatchedAsmStrings;
-
-  Regs.resize(NumAsmStrings);
-  Names.resize(NumAsmStrings);
-  PatchedAsmStrings.resize(NumAsmStrings);
-
-  // Rewrite operands to appease the AsmParser.
-  patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks,
-                    Context.getTargetInfo(), Regs, Names, PatchedAsmStrings);
-
-  // patchMSAsmStrings doesn't correctly patch non-simple asm statements.
-  if (!IsSimple) {
-    MSAsmStmt *NS =
-      new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
-                              /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
-                              AsmString, Clobbers, EndLoc);
-    return Owned(NS);
-  }
-
-  // Initialize targets and assembly printers/parsers.
-  llvm::InitializeAllTargetInfos();
-  llvm::InitializeAllTargetMCs();
-  llvm::InitializeAllAsmParsers();
-
-  // Get the target specific parser.
-  std::string Error;
-  const std::string &TT = Context.getTargetInfo().getTriple().getTriple();
-  const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
-
-  OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
-  OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
-  OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
-  OwningPtr<llvm::MCSubtargetInfo>
-    STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
-
-  for (unsigned i = 0, e = PatchedAsmStrings.size(); i != e; ++i) {
-    llvm::SourceMgr SrcMgr;
-    llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
-    llvm::MemoryBuffer *Buffer =
-      llvm::MemoryBuffer::getMemBuffer(PatchedAsmStrings[i], "<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());
-
-    // Prime the lexer.
-    Parser->Lex();
-
-    // Parse the opcode.
-    StringRef IDVal;
-    Parser->ParseIdentifier(IDVal);
-
-    // Canonicalize the opcode to lower case.
-    SmallString<128> Opcode;
-    for (unsigned i = 0, e = IDVal.size(); i != e; ++i)
-      Opcode.push_back(tolower(IDVal[i]));
-
-    // Parse the operands.
-    llvm::SMLoc IDLoc;
-    SmallVector<llvm::MCParsedAsmOperand*, 8> Operands;
-    bool HadError = TargetParser->ParseInstruction(Opcode.str(), IDLoc,
-                                                   Operands);
-    assert (!HadError && "Unexpected error parsing instruction");
-
-    // Match the MCInstr.
-    SmallVector<llvm::MCInst, 2> Instrs;
-    HadError = TargetParser->MatchInstruction(IDLoc, Operands, Instrs);
-    assert (!HadError && "Unexpected error matching instruction");
-    assert ((Instrs.size() == 1) && "Expected only a single instruction.");
-
-    // Get the instruction descriptor.
-    llvm::MCInst Inst = Instrs[0];
-    const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
-    const llvm::MCInstrDesc &Desc = MII->get(Inst.getOpcode());
-    llvm::MCInstPrinter *IP =
-      TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
-
-    // Build the list of clobbers.
-    for (unsigned i = 0, e = Desc.getNumDefs(); i != e; ++i) {
-      const llvm::MCOperand &Op = Inst.getOperand(i);
-      if (!Op.isReg())
-        continue;
-
-      std::string Reg;
-      llvm::raw_string_ostream OS(Reg);
-      IP->printRegName(OS, Op.getReg());
-
-      StringRef Clobber(OS.str());
-      if (!Context.getTargetInfo().isValidClobber(Clobber))
-        return StmtError(Diag(AsmLoc, diag::err_asm_unknown_register_name) <<
-                         Clobber);
-      ClobberRegs.insert(Reg);
-    }
-  }
-  for (std::set<std::string>::iterator I = ClobberRegs.begin(),
-         E = ClobberRegs.end(); I != E; ++I)
-    Clobbers.push_back(*I);
-
-  MSAsmStmt *NS =
-    new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
-                            /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
-                            AsmString, Clobbers, EndLoc);
-  return Owned(NS);
-}
-
 StmtResult
 Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc,
                            SourceLocation RParen, Decl *Parm,

Added: cfe/trunk/lib/Sema/SemaStmtAsm.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAsm.cpp?rev=162132&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAsm.cpp (added)
+++ cfe/trunk/lib/Sema/SemaStmtAsm.cpp Fri Aug 17 16:19:40 2012
@@ -0,0 +1,635 @@
+//===--- SemaStmtAsm.cpp - Semantic Analysis for Statements ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements semantic analysis for inline asm statements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+using namespace clang;
+using namespace sema;
+
+/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently
+/// ignore "noop" casts in places where an lvalue is required by an inline asm.
+/// We emulate this behavior when -fheinous-gnu-extensions is specified, but
+/// provide a strong guidance to not use it.
+///
+/// This method checks to see if the argument is an acceptable l-value and
+/// returns false if it is a case we can handle.
+static bool CheckAsmLValue(const Expr *E, Sema &S) {
+  // Type dependent expressions will be checked during instantiation.
+  if (E->isTypeDependent())
+    return false;
+
+  if (E->isLValue())
+    return false;  // Cool, this is an lvalue.
+
+  // Okay, this is not an lvalue, but perhaps it is the result of a cast that we
+  // are supposed to allow.
+  const Expr *E2 = E->IgnoreParenNoopCasts(S.Context);
+  if (E != E2 && E2->isLValue()) {
+    if (!S.getLangOpts().HeinousExtensions)
+      S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue)
+        << E->getSourceRange();
+    else
+      S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue)
+        << E->getSourceRange();
+    // Accept, even if we emitted an error diagnostic.
+    return false;
+  }
+
+  // None of the above, just randomly invalid non-lvalue.
+  return true;
+}
+
+/// isOperandMentioned - Return true if the specified operand # is mentioned
+/// anywhere in the decomposed asm string.
+static bool isOperandMentioned(unsigned OpNo,
+                         ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) {
+  for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) {
+    const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p];
+    if (!Piece.isOperand()) continue;
+
+    // If this is a reference to the input and if the input was the smaller
+    // one, then we have to reject this asm.
+    if (Piece.getOperandNo() == OpNo)
+      return true;
+  }
+  return false;
+}
+
+StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple,
+                              bool IsVolatile, unsigned NumOutputs,
+                              unsigned NumInputs, IdentifierInfo **Names,
+                              MultiExprArg constraints, MultiExprArg exprs,
+                              Expr *asmString, MultiExprArg clobbers,
+                              SourceLocation RParenLoc, bool MSAsm) {
+  unsigned NumClobbers = clobbers.size();
+  StringLiteral **Constraints =
+    reinterpret_cast<StringLiteral**>(constraints.get());
+  Expr **Exprs = exprs.get();
+  StringLiteral *AsmString = cast<StringLiteral>(asmString);
+  StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get());
+
+  SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
+
+  // The parser verifies that there is a string literal here.
+  if (!AsmString->isAscii())
+    return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character)
+      << AsmString->getSourceRange());
+
+  for (unsigned i = 0; i != NumOutputs; i++) {
+    StringLiteral *Literal = Constraints[i];
+    if (!Literal->isAscii())
+      return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+        << Literal->getSourceRange());
+
+    StringRef OutputName;
+    if (Names[i])
+      OutputName = Names[i]->getName();
+
+    TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName);
+    if (!Context.getTargetInfo().validateOutputConstraint(Info))
+      return StmtError(Diag(Literal->getLocStart(),
+                            diag::err_asm_invalid_output_constraint)
+                       << Info.getConstraintStr());
+
+    // Check that the output exprs are valid lvalues.
+    Expr *OutputExpr = Exprs[i];
+    if (CheckAsmLValue(OutputExpr, *this)) {
+      return StmtError(Diag(OutputExpr->getLocStart(),
+                  diag::err_asm_invalid_lvalue_in_output)
+        << OutputExpr->getSourceRange());
+    }
+
+    OutputConstraintInfos.push_back(Info);
+  }
+
+  SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos;
+
+  for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
+    StringLiteral *Literal = Constraints[i];
+    if (!Literal->isAscii())
+      return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+        << Literal->getSourceRange());
+
+    StringRef InputName;
+    if (Names[i])
+      InputName = Names[i]->getName();
+
+    TargetInfo::ConstraintInfo Info(Literal->getString(), InputName);
+    if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(),
+                                                NumOutputs, Info)) {
+      return StmtError(Diag(Literal->getLocStart(),
+                            diag::err_asm_invalid_input_constraint)
+                       << Info.getConstraintStr());
+    }
+
+    Expr *InputExpr = Exprs[i];
+
+    // Only allow void types for memory constraints.
+    if (Info.allowsMemory() && !Info.allowsRegister()) {
+      if (CheckAsmLValue(InputExpr, *this))
+        return StmtError(Diag(InputExpr->getLocStart(),
+                              diag::err_asm_invalid_lvalue_in_input)
+                         << Info.getConstraintStr()
+                         << InputExpr->getSourceRange());
+    }
+
+    if (Info.allowsRegister()) {
+      if (InputExpr->getType()->isVoidType()) {
+        return StmtError(Diag(InputExpr->getLocStart(),
+                              diag::err_asm_invalid_type_in_input)
+          << InputExpr->getType() << Info.getConstraintStr()
+          << InputExpr->getSourceRange());
+      }
+    }
+
+    ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]);
+    if (Result.isInvalid())
+      return StmtError();
+
+    Exprs[i] = Result.take();
+    InputConstraintInfos.push_back(Info);
+  }
+
+  // Check that the clobbers are valid.
+  for (unsigned i = 0; i != NumClobbers; i++) {
+    StringLiteral *Literal = Clobbers[i];
+    if (!Literal->isAscii())
+      return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character)
+        << Literal->getSourceRange());
+
+    StringRef Clobber = Literal->getString();
+
+    if (!Context.getTargetInfo().isValidClobber(Clobber))
+      return StmtError(Diag(Literal->getLocStart(),
+                  diag::err_asm_unknown_register_name) << Clobber);
+  }
+
+  AsmStmt *NS =
+    new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm,
+                          NumOutputs, NumInputs, Names, Constraints, Exprs,
+                          AsmString, NumClobbers, Clobbers, RParenLoc);
+  // Validate the asm string, ensuring it makes sense given the operands we
+  // have.
+  SmallVector<AsmStmt::AsmStringPiece, 8> Pieces;
+  unsigned DiagOffs;
+  if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) {
+    Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID)
+           << AsmString->getSourceRange();
+    return StmtError();
+  }
+
+  // Validate tied input operands for type mismatches.
+  for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) {
+    TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
+
+    // If this is a tied constraint, verify that the output and input have
+    // either exactly the same type, or that they are int/ptr operands with the
+    // same size (int/long, int*/long, are ok etc).
+    if (!Info.hasTiedOperand()) continue;
+
+    unsigned TiedTo = Info.getTiedOperand();
+    unsigned InputOpNo = i+NumOutputs;
+    Expr *OutputExpr = Exprs[TiedTo];
+    Expr *InputExpr = Exprs[InputOpNo];
+
+    if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent())
+      continue;
+
+    QualType InTy = InputExpr->getType();
+    QualType OutTy = OutputExpr->getType();
+    if (Context.hasSameType(InTy, OutTy))
+      continue;  // All types can be tied to themselves.
+
+    // Decide if the input and output are in the same domain (integer/ptr or
+    // floating point.
+    enum AsmDomain {
+      AD_Int, AD_FP, AD_Other
+    } InputDomain, OutputDomain;
+
+    if (InTy->isIntegerType() || InTy->isPointerType())
+      InputDomain = AD_Int;
+    else if (InTy->isRealFloatingType())
+      InputDomain = AD_FP;
+    else
+      InputDomain = AD_Other;
+
+    if (OutTy->isIntegerType() || OutTy->isPointerType())
+      OutputDomain = AD_Int;
+    else if (OutTy->isRealFloatingType())
+      OutputDomain = AD_FP;
+    else
+      OutputDomain = AD_Other;
+
+    // They are ok if they are the same size and in the same domain.  This
+    // allows tying things like:
+    //   void* to int*
+    //   void* to int            if they are the same size.
+    //   double to long double   if they are the same size.
+    //
+    uint64_t OutSize = Context.getTypeSize(OutTy);
+    uint64_t InSize = Context.getTypeSize(InTy);
+    if (OutSize == InSize && InputDomain == OutputDomain &&
+        InputDomain != AD_Other)
+      continue;
+
+    // If the smaller input/output operand is not mentioned in the asm string,
+    // then we can promote the smaller one to a larger input and the asm string
+    // won't notice.
+    bool SmallerValueMentioned = false;
+
+    // If this is a reference to the input and if the input was the smaller
+    // one, then we have to reject this asm.
+    if (isOperandMentioned(InputOpNo, Pieces)) {
+      // This is a use in the asm string of the smaller operand.  Since we
+      // codegen this by promoting to a wider value, the asm will get printed
+      // "wrong".
+      SmallerValueMentioned |= InSize < OutSize;
+    }
+    if (isOperandMentioned(TiedTo, Pieces)) {
+      // If this is a reference to the output, and if the output is the larger
+      // value, then it's ok because we'll promote the input to the larger type.
+      SmallerValueMentioned |= OutSize < InSize;
+    }
+
+    // If the smaller value wasn't mentioned in the asm string, and if the
+    // output was a register, just extend the shorter one to the size of the
+    // larger one.
+    if (!SmallerValueMentioned && InputDomain != AD_Other &&
+        OutputConstraintInfos[TiedTo].allowsRegister())
+      continue;
+
+    // Either both of the operands were mentioned or the smaller one was
+    // mentioned.  One more special case that we'll allow: if the tied input is
+    // integer, unmentioned, and is a constant, then we'll allow truncating it
+    // down to the size of the destination.
+    if (InputDomain == AD_Int && OutputDomain == AD_Int &&
+        !isOperandMentioned(InputOpNo, Pieces) &&
+        InputExpr->isEvaluatable(Context)) {
+      CastKind castKind =
+        (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast);
+      InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take();
+      Exprs[InputOpNo] = InputExpr;
+      NS->setInputExpr(i, InputExpr);
+      continue;
+    }
+
+    Diag(InputExpr->getLocStart(),
+         diag::err_asm_tying_incompatible_types)
+      << InTy << OutTy << OutputExpr->getSourceRange()
+      << InputExpr->getSourceRange();
+    return StmtError();
+  }
+
+  return Owned(NS);
+}
+
+// isMSAsmKeyword - Return true if this is an MS-style inline asm keyword. These
+// require special handling.
+static bool isMSAsmKeyword(StringRef Name) {
+  bool Ret = llvm::StringSwitch<bool>(Name)
+    .Cases("EVEN", "ALIGN", true) // Alignment directives.
+    .Cases("LENGTH", "SIZE", "TYPE", true) // Type and variable sizes.
+    .Case("_emit", true) // _emit Pseudoinstruction.
+    .Default(false);
+  return Ret;
+}
+
+static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
+  StringRef Asm;
+  SmallString<512> TokenBuf;
+  TokenBuf.resize(512);
+  bool StringInvalid = false;
+  Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid);
+  assert (!StringInvalid && "Expected valid string!");
+  return Asm;
+}
+
+static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple,
+                              SourceLocation AsmLoc,
+                              ArrayRef<Token> AsmToks,
+                              const TargetInfo &TI,
+                              std::vector<llvm::BitVector> &AsmRegs,
+                              std::vector<llvm::BitVector> &AsmNames,
+                              std::vector<std::string> &AsmStrings) {
+  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+
+  // Assume simple asm stmt until we parse a non-register identifer (or we just
+  // need to bail gracefully).
+  IsSimple = true;
+
+  SmallString<512> Asm;
+  unsigned NumAsmStrings = 0;
+  for (unsigned i = 0, e = AsmToks.size(); i != e; ++i) {
+
+    // Determine if this should be considered a new asm.
+    bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
+      AsmToks[i].is(tok::kw_asm);
+
+    // Emit the previous asm string.
+    if (i && isNewAsm) {
+      AsmStrings[NumAsmStrings++] = Asm.c_str();
+      if (AsmToks[i].is(tok::kw_asm)) {
+        ++i; // Skip __asm
+        assert (i != e && "Expected another token.");
+      }
+    }
+
+    // Start a new asm string with the opcode.
+    if (isNewAsm) {
+      AsmRegs[NumAsmStrings].resize(AsmToks.size());
+      AsmNames[NumAsmStrings].resize(AsmToks.size());
+
+      StringRef Piece = AsmToks[i].getIdentifierInfo()->getName();
+      // MS-style inline asm keywords require special handling.
+      if (isMSAsmKeyword(Piece))
+        IsSimple = false;
+
+      // TODO: Verify this is a valid opcode.
+      Asm = Piece;
+      continue;
+    }
+
+    if (i && AsmToks[i].hasLeadingSpace())
+      Asm += ' ';
+
+    // Check the operand(s).
+    switch (AsmToks[i].getKind()) {
+    default:
+      IsSimple = false;
+      Asm += getSpelling(SemaRef, AsmToks[i]);
+      break;
+    case tok::comma: Asm += ","; break;
+    case tok::colon: Asm += ":"; break;
+    case tok::l_square: Asm += "["; break;
+    case tok::r_square: Asm += "]"; break;
+    case tok::l_brace: Asm += "{"; break;
+    case tok::r_brace: Asm += "}"; break;
+    case tok::numeric_constant:
+      Asm += getSpelling(SemaRef, AsmToks[i]);
+      break;
+    case tok::identifier: {
+      IdentifierInfo *II = AsmToks[i].getIdentifierInfo();
+      StringRef Name = II->getName();
+
+      // Valid register?
+      if (TI.isValidGCCRegisterName(Name)) {
+        AsmRegs[NumAsmStrings].set(i);
+        Asm += Name;
+        break;
+      }
+
+      IsSimple = false;
+
+      // MS-style inline asm keywords require special handling.
+      if (isMSAsmKeyword(Name)) {
+        IsSimple = false;
+        Asm += Name;
+        break;
+      }
+
+      // FIXME: Why are we missing this segment register?
+      if (Name == "fs") {
+        Asm += Name;
+        break;
+      }
+
+      // Lookup the identifier.
+      // TODO: Someone with more experience with clang should verify this the
+      // proper way of doing a symbol lookup.
+      DeclarationName DeclName(II);
+      Scope *CurScope = SemaRef.getCurScope();
+      LookupResult R(SemaRef, DeclName, AsmLoc, Sema::LookupOrdinaryName);
+      if (!SemaRef.LookupName(R, CurScope, false/*AllowBuiltinCreation*/))
+        break;
+
+      assert (R.isSingleResult() && "Expected a single result?!");
+      NamedDecl *Decl = R.getFoundDecl();
+      switch (Decl->getKind()) {
+      default:
+        assert(0 && "Unknown decl kind.");
+        break;
+      case Decl::Var: {
+      case Decl::ParmVar:
+        AsmNames[NumAsmStrings].set(i);
+
+        VarDecl *Var = cast<VarDecl>(Decl);
+        QualType Ty = Var->getType();
+        (void)Ty; // Avoid warning.
+        // TODO: Patch identifier with valid operand.  One potential idea is to
+        // probe the backend with type information to guess the possible
+        // operand.
+        break;
+      }
+      }
+      break;
+    }
+    }
+  }
+
+  // Emit the final (and possibly only) asm string.
+  AsmStrings[NumAsmStrings] = Asm.c_str();
+}
+
+// Build the unmodified MSAsmString.
+static std::string buildMSAsmString(Sema &SemaRef,
+                                    ArrayRef<Token> AsmToks,
+                                    unsigned &NumAsmStrings) {
+  assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
+  NumAsmStrings = 0;
+
+  SmallString<512> Asm;
+  for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) {
+    bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() ||
+      AsmToks[i].is(tok::kw_asm);
+
+    if (isNewAsm) {
+      ++NumAsmStrings;
+      if (i)
+        Asm += '\n';
+      if (AsmToks[i].is(tok::kw_asm)) {
+        i++; // Skip __asm
+        assert (i != e && "Expected another token");
+      }
+    }
+
+    if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm)
+      Asm += ' ';
+
+    Asm += getSpelling(SemaRef, AsmToks[i]);
+  }
+  return Asm.c_str();
+}
+
+StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc,
+                                SourceLocation LBraceLoc,
+                                ArrayRef<Token> AsmToks,
+                                SourceLocation EndLoc) {
+  // MS-style inline assembly is not fully supported, so emit a warning.
+  Diag(AsmLoc, diag::warn_unsupported_msasm);
+  SmallVector<StringRef,4> Clobbers;
+  std::set<std::string> ClobberRegs;
+  SmallVector<IdentifierInfo*, 4> Inputs;
+  SmallVector<IdentifierInfo*, 4> Outputs;
+
+  // Empty asm statements don't need to instantiate the AsmParser, etc.
+  if (AsmToks.empty()) {
+    StringRef AsmString;
+    MSAsmStmt *NS =
+      new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
+                              /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
+                              AsmString, Clobbers, EndLoc);
+    return Owned(NS);
+  }
+
+  unsigned NumAsmStrings;
+  std::string AsmString = buildMSAsmString(*this, AsmToks, NumAsmStrings);
+
+  bool IsSimple;
+  std::vector<llvm::BitVector> Regs;
+  std::vector<llvm::BitVector> Names;
+  std::vector<std::string> PatchedAsmStrings;
+
+  Regs.resize(NumAsmStrings);
+  Names.resize(NumAsmStrings);
+  PatchedAsmStrings.resize(NumAsmStrings);
+
+  // Rewrite operands to appease the AsmParser.
+  patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks,
+                    Context.getTargetInfo(), Regs, Names, PatchedAsmStrings);
+
+  // patchMSAsmStrings doesn't correctly patch non-simple asm statements.
+  if (!IsSimple) {
+    MSAsmStmt *NS =
+      new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
+                              /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
+                              AsmString, Clobbers, EndLoc);
+    return Owned(NS);
+  }
+
+  // Initialize targets and assembly printers/parsers.
+  llvm::InitializeAllTargetInfos();
+  llvm::InitializeAllTargetMCs();
+  llvm::InitializeAllAsmParsers();
+
+  // Get the target specific parser.
+  std::string Error;
+  const std::string &TT = Context.getTargetInfo().getTriple().getTriple();
+  const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
+
+  OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
+  OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+  OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
+  OwningPtr<llvm::MCSubtargetInfo>
+    STI(TheTarget->createMCSubtargetInfo(TT, "", ""));
+
+  for (unsigned i = 0, e = PatchedAsmStrings.size(); i != e; ++i) {
+    llvm::SourceMgr SrcMgr;
+    llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
+    llvm::MemoryBuffer *Buffer =
+      llvm::MemoryBuffer::getMemBuffer(PatchedAsmStrings[i], "<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());
+
+    // Prime the lexer.
+    Parser->Lex();
+
+    // Parse the opcode.
+    StringRef IDVal;
+    Parser->ParseIdentifier(IDVal);
+
+    // Canonicalize the opcode to lower case.
+    SmallString<128> Opcode;
+    for (unsigned i = 0, e = IDVal.size(); i != e; ++i)
+      Opcode.push_back(tolower(IDVal[i]));
+
+    // Parse the operands.
+    llvm::SMLoc IDLoc;
+    SmallVector<llvm::MCParsedAsmOperand*, 8> Operands;
+    bool HadError = TargetParser->ParseInstruction(Opcode.str(), IDLoc,
+                                                   Operands);
+    assert (!HadError && "Unexpected error parsing instruction");
+
+    // Match the MCInstr.
+    SmallVector<llvm::MCInst, 2> Instrs;
+    HadError = TargetParser->MatchInstruction(IDLoc, Operands, Instrs);
+    assert (!HadError && "Unexpected error matching instruction");
+    assert ((Instrs.size() == 1) && "Expected only a single instruction.");
+
+    // Get the instruction descriptor.
+    llvm::MCInst Inst = Instrs[0];
+    const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
+    const llvm::MCInstrDesc &Desc = MII->get(Inst.getOpcode());
+    llvm::MCInstPrinter *IP =
+      TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
+
+    // Build the list of clobbers.
+    for (unsigned i = 0, e = Desc.getNumDefs(); i != e; ++i) {
+      const llvm::MCOperand &Op = Inst.getOperand(i);
+      if (!Op.isReg())
+        continue;
+
+      std::string Reg;
+      llvm::raw_string_ostream OS(Reg);
+      IP->printRegName(OS, Op.getReg());
+
+      StringRef Clobber(OS.str());
+      if (!Context.getTargetInfo().isValidClobber(Clobber))
+        return StmtError(Diag(AsmLoc, diag::err_asm_unknown_register_name) <<
+                         Clobber);
+      ClobberRegs.insert(Reg);
+    }
+  }
+  for (std::set<std::string>::iterator I = ClobberRegs.begin(),
+         E = ClobberRegs.end(); I != E; ++I)
+    Clobbers.push_back(*I);
+
+  MSAsmStmt *NS =
+    new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple,
+                            /*IsVolatile*/ true, AsmToks, Inputs, Outputs,
+                            AsmString, Clobbers, EndLoc);
+  return Owned(NS);
+}





More information about the cfe-commits mailing list