diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -403,7 +403,7 @@ /// Maps struct tags to struct definitions. StringMap Structs; - /// Maps data location names to types. + /// Maps data location names to typ StringMap KnownType; /// Stack of active macro instantiations. @@ -450,6 +450,9 @@ // Number of locals defined. uint16_t LocalCounter = 0; + // Number of anonymous labels defined. + uint16_t AnonymousLabelCounter = 0; + public: MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, struct tm TM, unsigned CB = 0); @@ -1585,6 +1588,24 @@ Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); return false; } + // Parse anonymous label references. + if (Identifier.equals_insensitive("@b") && AnonymousLabelCounter == 0) { + return Error(FirstTokenLoc, "Expected @@ label before @B reference"); + } + if (Identifier.equals_insensitive("@b") || + Identifier.equals_insensitive("@f")) { + uint16_t AnonymousTarget = AnonymousLabelCounter; + if (Identifier.equals_insensitive("@b")) { + AnonymousTarget--; + } + std::string AnonymousLabel = "@@??"; + raw_string_ostream AnonymousLabelStream(AnonymousLabel); + AnonymousLabelStream << format_hex_no_prefix(AnonymousTarget, 4, + /*Upper=*/true); + MCSymbol *Sym = getContext().getOrCreateSymbol(AnonymousLabel); + Res = MCSymbolRefExpr::create(Sym, getContext()); + return false; + } // Parse symbol variant. std::pair Split; if (!MAI.useParensForSymbolVariant()) { @@ -2267,7 +2288,15 @@ RewrittenLabel); IDVal = RewrittenLabel; } - Sym = getContext().getOrCreateSymbol(IDVal); + // Rewrite anonymous labels + std::string Label = IDVal.str(); + if (IDVal == "@@") { + raw_string_ostream RewrittenLabel(Label); + RewrittenLabel << "??" + << format_hex_no_prefix(AnonymousLabelCounter++, 4, + /*Upper=*/true); + } + Sym = getContext().getOrCreateSymbol(Label); } else Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal); // End of Labels should be treated as end of line for lexing diff --git a/llvm/test/tools/llvm-ml/anonymous_labels.asm b/llvm/test/tools/llvm-ml/anonymous_labels.asm new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/anonymous_labels.asm @@ -0,0 +1,42 @@ +; RUN: llvm-ml -filetype=s %s /Fo - | FileCheck %s + +.code + +t1: + jmp @F + jmp @F +; CHECK-LABEL: t1: +; CHECK-NEXT: jmp "@@??0000" +; CHECK-NEXT: jmp "@@??0000" + +@@: + xor eax, eax +; CHECK-LABEL: "@@??0000": +; CHECK-NEXT: xor eax, eax + +t2: + jmp @B + jmp @B +; CHECK-LABEL: t2: +; CHECK-NEXT: jmp "@@??0000" +; CHECK-NEXT: jmp "@@??0000" + +t3: + jmp @F +; CHECK-LABEL: t3: +; CHECK-NEXT: jmp "@@??0001" + +@@: + xor eax, eax +; CHECK-LABEL: "@@??0001": +; CHECK-NEXT: xor eax, eax + +@@: + xor eax, eax +; CHECK-LABEL: "@@??0002": +; CHECK-NEXT: xor eax, eax + +t4: + jmp @B +; CHECK-LABEL: t4: +; CHECK-NEXT: jmp "@@??0002" diff --git a/llvm/test/tools/llvm-ml/anonymous_labels_errors.asm b/llvm/test/tools/llvm-ml/anonymous_labels_errors.asm new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/anonymous_labels_errors.asm @@ -0,0 +1,16 @@ +; RUN: not llvm-ml -filetype=s %s /Fo - 2>&1 | FileCheck %s --implicit-check-not=error: + +.code + +; CHECK: :[[# @LINE + 2]]:5: error: Expected @@ label before @B reference +; CHECK: :[[# @LINE + 1]]:7: error: Unexpected identifier! +jmp @B + +@@: + jmp @B + jmp @F +@@: + xor eax, eax + +; NOTE: a trailing @F will not fail; fixing this seems to require two passes. +jmp @F