On Wed, Aug 22, 2012 at 6:37 PM, Sean Silva <[email protected]> wrote: > + 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'.
For posterity, I fixed this in r162424. > > --Sean Silva > > On Fri, Aug 17, 2012 at 5:19 PM, Chad Rosier <[email protected]> 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 >> [email protected] >> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
