Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -46,6 +46,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include @@ -3124,6 +3125,16 @@ ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc); + struct MSAsmLabelEntry { + MSAsmLabelEntry() : InternalName(), Location(), Resolved(false) {} + llvm::SmallString<32> InternalName; + SourceLocation Location; + bool Resolved; + }; + const MSAsmLabelEntry &GetMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate); + void HandleMSAsmLabelsOnScopePop(); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, @@ -8385,6 +8396,8 @@ mutable IdentifierInfo *Ident_super; mutable IdentifierInfo *Ident___float128; + llvm::StringMap MSAsmLabelMap; + protected: friend class Parser; friend class InitializationSequence; Index: lib/Parse/ParseStmtAsm.cpp =================================================================== --- lib/Parse/ParseStmtAsm.cpp +++ lib/Parse/ParseStmtAsm.cpp @@ -93,6 +93,17 @@ return Info.OpDecl; } + void LookupInlineAsmLabel(StringRef &Identifier, llvm::SourceMgr &LSM, + llvm::SMLoc Location, bool Create) { + const llvm::MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(Location)); + unsigned Offset = Location.getPointer() - LBuf->getBufferStart(); + SourceLocation Loc = translateLocation(Offset); + const Sema::MSAsmLabelEntry &Entry = + TheParser.getActions().GetMSAsmLabel(Identifier, Loc, Create); + Identifier = Entry.InternalName; + } + bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset) override { return TheParser.getActions().LookupInlineAsmField(Base, Member, Offset, @@ -133,15 +144,7 @@ } } - void handleDiagnostic(const llvm::SMDiagnostic &D) { - // Compute an offset into the inline asm buffer. - // FIXME: This isn't right if .macro is involved (but hopefully, no - // real-world code does that). - const llvm::SourceMgr &LSM = *D.getSourceMgr(); - const llvm::MemoryBuffer *LBuf = - LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); - unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); - + SourceLocation translateLocation(unsigned Offset) { // Figure out which token that offset points into. const unsigned *TokOffsetPtr = std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset); @@ -157,6 +160,19 @@ Loc = Tok.getLocation(); Loc = Loc.getLocWithOffset(Offset - TokOffset); } + return Loc; + } + + void handleDiagnostic(const llvm::SMDiagnostic &D) { + // Compute an offset into the inline asm buffer. + // FIXME: This isn't right if .macro is involved (but hopefully, no + // real-world code does that). + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + const llvm::MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); + + SourceLocation Loc = translateLocation(Offset); TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); } }; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -1489,6 +1489,8 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { S->mergeNRVOIntoParent(); + HandleMSAsmLabelsOnScopePop(); + if (S->decl_empty()) return; assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && "Scope shouldn't contain decls!"); Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -22,6 +22,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/Support/Format.h" using namespace clang; using namespace sema; @@ -488,3 +489,49 @@ Clobbers, EndLoc); return NS; } + +const Sema::MSAsmLabelEntry& Sema::GetMSAsmLabel(StringRef ExternalLabelName, + SourceLocation Location, + bool AlwaysCreate) { + static uint32_t counter = 0; + + // First, see if this is a label that we already know about. + llvm::StringMap::iterator it = + MSAsmLabelMap.find(ExternalLabelName); + if (it != MSAsmLabelMap.end()) { + if (AlwaysCreate) { + // Resolve the label if it was previously referenced. + it->getValue().Resolved = true; + it->getValue().Location = Location; + } + return it->getValue(); + } + + // Otherwise, insert it, but only resolve it if we have seen the label itself. + std::string InternalName; + llvm::raw_string_ostream OS(InternalName); + // Create an internal name for the label. The name should not be a valid mangled + // name, and should be unique. We use a dot to make the name an invalid mangled + // name. + OS << llvm::format("__MSASMLABEL_.%" PRIu32 "__", counter++); + MSAsmLabelEntry Entry; + Entry.InternalName = OS.str(); + Entry.Location = Location; + if (AlwaysCreate) { + Entry.Resolved = true; + } + MSAsmLabelMap.insert(std::make_pair(ExternalLabelName, Entry)); + return GetMSAsmLabel(ExternalLabelName, Location, false); +} + +void Sema::HandleMSAsmLabelsOnScopePop() { + for (const auto& Entry : MSAsmLabelMap) { + if (!Entry.getValue().Resolved) { + Diag(Entry.getValue().Location, diag::err_undeclared_label_use) + << Entry.getKey(); + } + } + + // Clear the map as we're leaving the function scope. + MSAsmLabelMap.clear(); +} Index: test/CodeGen/mozilla-ms-inline-asm.c =================================================================== --- test/CodeGen/mozilla-ms-inline-asm.c +++ test/CodeGen/mozilla-ms-inline-asm.c @@ -3,6 +3,8 @@ // Some test cases for MS inline asm support from Mozilla code base. +void invoke_copy_to_stack() {} + void invoke(void* that, unsigned methodIndex, unsigned paramCount, void* params) { @@ -18,24 +20,25 @@ // CHECK: call void asm sideeffect inteldialect // CHECK: mov edx,dword ptr $1 // CHECK: test edx,edx -// CHECK: jz noparams +// CHECK: jz {{[^_]*}}__MSASMLABEL_.0__ +// ^ Can't use {{.*}} here because the matching is greedy. // CHECK: mov eax,edx // CHECK: shl eax,$$3 // CHECK: sub esp,eax // CHECK: mov ecx,esp // CHECK: push dword ptr $0 -// CHECK: call invoke_copy_to_stack -// CHECK: noparams: -// CHECK: mov ecx,dword ptr $2 +// CHECK: call $2 +// CHECK: {{.*}}__MSASMLABEL_.0__: +// CHECK: mov ecx,dword ptr $3 // CHECK: push ecx // CHECK: mov edx,[ecx] -// CHECK: mov eax,dword ptr $3 +// CHECK: mov eax,dword ptr $4 // CHECK: call dword ptr[edx+eax*$$4] // CHECK: mov esp,ebp // CHECK: pop ebp // CHECK: ret -// CHECK: "=*m,*m,*m,*m,~{eax},~{ebp},~{ecx},~{edx},~{flags},~{esp},~{dirflag},~{fpsr},~{flags}" -// CHECK: (i8** %8, i32* %7, i8** %5, i32* %6) +// CHECK: "=*m,*m,r,*m,*m,~{eax},~{ebp},~{ecx},~{edx},~{flags},~{esp},~{dirflag},~{fpsr},~{flags}" +// CHECK: (i8** %8, i32* %7, void (...)* bitcast (void ()* @invoke_copy_to_stack to void (...)*), i8** %5, i32* %6) // CHECK: ret void __asm { mov edx,paramCount Index: test/CodeGen/ms-inline-asm.c =================================================================== --- test/CodeGen/ms-inline-asm.c +++ test/CodeGen/ms-inline-asm.c @@ -242,7 +242,7 @@ the_label: } // CHECK: t23 -// CHECK: call void asm sideeffect inteldialect "the_label:", "~{dirflag},~{fpsr},~{flags}"() +// CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.0__:", "~{dirflag},~{fpsr},~{flags}"() } void t24_helper(void) {} @@ -494,3 +494,30 @@ // CHECK: call void asm sideeffect inteldialect "mov gs, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]]) // CHECK: call void asm sideeffect inteldialect "mov ss, word ptr $0", "*m,~{dirflag},~{fpsr},~{flags}"(i16* [[T41_A_ADDR]]) } + +void label1() { + __asm { + label: + jmp label + } + // CHECK-LABEL: define void @label1 + // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.1__:\0A\09jmp {{.*}}__MSASMLABEL_.1__", "~{dirflag},~{fpsr},~{flags}"() +} + +void label2() { + __asm { + jmp label + label: + } + // CHECK-LABEL: define void @label2 + // CHECK: call void asm sideeffect inteldialect "jmp {{.*}}__MSASMLABEL_.2__\0A\09{{.*}}__MSASMLABEL_.2__:", "~{dirflag},~{fpsr},~{flags}"() +} + +void label3() { + __asm { + label: + mov eax, label + } + // CHECK-LABEL: define void @label3 + // CHECK: call void asm sideeffect inteldialect "{{.*}}__MSASMLABEL_.3__:\0A\09mov eax, {{.*}}__MSASMLABEL_.3__", "~{eax},~{dirflag},~{fpsr},~{flags}"() +} Index: test/Parser/ms-inline-asm.c =================================================================== --- test/Parser/ms-inline-asm.c +++ test/Parser/ms-inline-asm.c @@ -48,6 +48,9 @@ void t11() { do { __asm mov eax, 0 __asm { __asm mov edx, 1 } } while(0); } +void t12() { + __asm jmp label // expected-error {{use of undeclared label label}} +} int t_fail() { // expected-note {{to match this}} __asm __asm { // expected-error 3 {{expected}} expected-note {{to match this}} Index: test/Sema/ms-inline-asm.c =================================================================== --- test/Sema/ms-inline-asm.c +++ test/Sema/ms-inline-asm.c @@ -21,7 +21,7 @@ } f(); __asm { - mov eax, LENGTH bar // expected-error {{unable to lookup expression}} + mov eax, LENGTH bar // expected-error {{unable to lookup expression}} expected-error {{use of undeclared label bar}} } f(); __asm { @@ -80,9 +80,10 @@ } A; void t3() { - __asm mov eax, [eax] UndeclaredId // expected-error {{unknown token in expression}} + __asm mov eax, [eax] UndeclaredId // expected-error {{unknown token in expression}} expected-error {{use of undeclared label UndeclaredId}} // FIXME: Only emit one diagnostic here. + // expected-error@+3 {{use of undeclared label A}} // expected-error@+2 {{unexpected type name 'A': expected expression}} // expected-error@+1 {{unknown token in expression}} __asm mov eax, [eax] A