[cfe-commits] r162132 - in /cfe/trunk/lib/Sema: CMakeLists.txt SemaStmt.cpp SemaStmtAsm.cpp
Sean Silva
silvas at purdue.edu
Wed Aug 22 18:37:32 PDT 2012
+ for (unsigned i = 0, e = IDVal.size(); i != e; ++i)
+ Opcode.push_back(tolower(IDVal[i]));
Hey Chad, sorry for commenting on this rather old email, but this use
of 'i' as a variable name inside a loop whose index variable is
already 'i' seems questionable, especially since you're using 'j' for
another inner loop. I discovered this because GCC just gave me an odd
warning over it:
SemaStmtAsm.cpp:594:63: warning: name lookup of ‘i’ changed [enabled by default]
SemaStmtAsm.cpp:509:17: warning: matches this ‘i’ under ISO standard
rules [enabled by default]
SemaStmtAsm.cpp:536:19: warning: matches this ‘i’ under old rules
[enabled by default]
IMO this warning is pointless, but nonetheless, I think it would be
good to change the loop variable to be 'j'.
--Sean Silva
On Fri, Aug 17, 2012 at 5:19 PM, Chad Rosier <mcrosier at apple.com> wrote:
> 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);
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list