diff options
author | dim <dim@FreeBSD.org> | 2012-08-19 10:33:04 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-08-19 10:33:04 +0000 |
commit | cc73504950eb7b5dff2dded9bedd67bc36d64641 (patch) | |
tree | 5b9c2fa9d79942fbdce3d618e37e27c18263af9a /lib/Sema/SemaStmt.cpp | |
parent | 554bcb69c2d785a011a30e7db87a36a87fe7db10 (diff) | |
download | FreeBSD-src-cc73504950eb7b5dff2dded9bedd67bc36d64641.zip FreeBSD-src-cc73504950eb7b5dff2dded9bedd67bc36d64641.tar.gz |
Vendor import of clang trunk r162107:
http://llvm.org/svn/llvm-project/cfe/trunk@162107
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 329 |
1 files changed, 221 insertions, 108 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index d22deb2..86884b7 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -28,6 +28,7 @@ #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" @@ -35,11 +36,15 @@ #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" @@ -1516,7 +1521,6 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc) { @@ -1698,9 +1702,9 @@ static bool ObjCEnumerationCollection(Expr *Collection) { && Collection->getType()->getAs<ObjCObjectPointerType>() != 0; } -/// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement. +/// ActOnCXXForRangeStmt - Check and build a C++11 for-range statement. /// -/// C++0x [stmt.ranged]: +/// C++11 [stmt.ranged]: /// A range-based for statement is equivalent to /// /// { @@ -1717,15 +1721,14 @@ static bool ObjCEnumerationCollection(Expr *Collection) { /// The body of the loop is not available yet, since it cannot be analysed until /// we have determined the type of the for-range-declaration. StmtResult -Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc, +Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc) { if (!First || !Range) return StmtError(); if (ObjCEnumerationCollection(Range)) - return ActOnObjCForCollectionStmt(ForLoc, LParenLoc, First, Range, - RParenLoc); + return ActOnObjCForCollectionStmt(ForLoc, First, Range, RParenLoc); DeclStmt *DS = dyn_cast<DeclStmt>(First); assert(DS && "first part of for range not a decl stmt"); @@ -2759,165 +2762,225 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, return Owned(NS); } -// needSpaceAsmToken - This function handles whitespace around asm punctuation. -// Returns true if a space should be emitted. -static inline bool needSpaceAsmToken(Token currTok) { - static Token prevTok; - - // No need for space after prevToken. - switch(prevTok.getKind()) { - default: - break; - case tok::l_square: - case tok::r_square: - case tok::l_brace: - case tok::r_brace: - case tok::colon: - prevTok = currTok; - return false; - } +// 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; +} - // No need for a space before currToken. - switch(currTok.getKind()) { - default: - break; - case tok::l_square: - case tok::r_square: - case tok::l_brace: - case tok::r_brace: - case tok::comma: - case tok::colon: - prevTok = currTok; - return false; - } - prevTok = currTok; - return true; +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, - ArrayRef<unsigned> LineEnds, 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. + // Assume simple asm stmt until we parse a non-register identifer (or we just + // need to bail gracefully). IsSimple = true; - for (unsigned i = 0, e = LineEnds.size(); i != e; ++i) { - SmallString<512> Asm; + 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."); + } + } - // Check the operands. - for (unsigned j = (i == 0) ? 0 : LineEnds[i-1], e = LineEnds[i]; j != e; ++j) { + // Start a new asm string with the opcode. + if (isNewAsm) { + AsmRegs[NumAsmStrings].resize(AsmToks.size()); + AsmNames[NumAsmStrings].resize(AsmToks.size()); - IdentifierInfo *II; - if (j == 0 || (i > 0 && j == LineEnds[i-1])) { - II = AsmToks[j].getIdentifierInfo(); - Asm = II->getName().str(); - continue; + 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; } - if (needSpaceAsmToken(AsmToks[j])) - Asm += " "; + IsSimple = false; - switch (AsmToks[j].getKind()) { - default: - //llvm_unreachable("Unknown token."); + // MS-style inline asm keywords require special handling. + if (isMSAsmKeyword(Name)) { + IsSimple = false; + Asm += Name; 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: { - SmallString<32> TokenBuf; - TokenBuf.resize(32); - bool StringInvalid = false; - Asm += SemaRef.PP.getSpelling(AsmToks[j], TokenBuf, &StringInvalid); - assert (!StringInvalid && "Expected valid string!"); + } + + // FIXME: Why are we missing this segment register? + if (Name == "fs") { + Asm += Name; break; } - case tok::identifier: { - II = AsmToks[j].getIdentifierInfo(); - StringRef Name = II->getName(); - // Valid registers don't need modification. - if (TI.isValidGCCRegisterName(Name)) { - 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; - // TODO: Lookup the identifier. - IsSimple = false; + 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; + } } - } // AsmToks[i].getKind() + break; + } } - AsmStrings[i] = Asm.c_str(); } + + // 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, - ArrayRef<unsigned> LineEnds) { + unsigned &NumAsmStrings) { assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); + NumAsmStrings = 0; + SmallString<512> Asm; - SmallString<512> TokenBuf; - TokenBuf.resize(512); - unsigned AsmLineNum = 0; for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { - const char *ThisTokBuf = &TokenBuf[0]; - bool StringInvalid = false; - unsigned ThisTokLen = - Lexer::getSpelling(AsmToks[i], ThisTokBuf, SemaRef.getSourceManager(), - SemaRef.getLangOpts(), &StringInvalid); - if (i && (!AsmLineNum || i != LineEnds[AsmLineNum-1]) && - needSpaceAsmToken(AsmToks[i])) - Asm += ' '; - Asm += StringRef(ThisTokBuf, ThisTokLen); - if (i + 1 == LineEnds[AsmLineNum] && i + 1 != AsmToks.size()) { - Asm += '\n'; - ++AsmLineNum; + 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, - ArrayRef<unsigned> LineEnds, 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, /* IsSimple */ true, - /* IsVolatile */ true, AsmToks, LineEnds, + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, + /*IsVolatile*/ true, AsmToks, Inputs, Outputs, AsmString, Clobbers, EndLoc); return Owned(NS); } - std::string AsmString = buildMSAsmString(*this, AsmToks, LineEnds); + 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; - PatchedAsmStrings.resize(LineEnds.size()); + + Regs.resize(NumAsmStrings); + Names.resize(NumAsmStrings); + PatchedAsmStrings.resize(NumAsmStrings); // Rewrite operands to appease the AsmParser. - patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks, LineEnds, - Context.getTargetInfo(), PatchedAsmStrings); + 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, /* IsSimple */ true, - /* IsVolatile */ true, AsmToks, LineEnds, + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, + /*IsVolatile*/ true, AsmToks, Inputs, Outputs, AsmString, Clobbers, EndLoc); return Owned(NS); } @@ -2947,7 +3010,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, // Tell SrcMgr about this buffer, which is what the parser will pick up. SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); - OwningPtr<llvm::MCStreamer> Str; + OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); OwningPtr<llvm::MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); OwningPtr<llvm::MCTargetAsmParser> @@ -2956,13 +3019,63 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, Parser->setAssemblerDialect(1); Parser->setTargetParser(*TargetParser.get()); - // TODO: Start parsing. + // 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, IsSimple, /* IsVolatile */ true, - AsmToks, LineEnds, AsmString, Clobbers, EndLoc); - + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, + /*IsVolatile*/ true, AsmToks, Inputs, Outputs, + AsmString, Clobbers, EndLoc); return Owned(NS); } |