[ms] [llvm-ml] Add support for anonymous labels (`@@`, `@B`, `@F`)

ml.exe and ml64.exe support the use of anonymous labels, with @B and @F referring to the previous and next anonymous label respectively.

We add similar support to llvm-ml, with the exception that we are unable to emit an error message for an @F expression not followed by a @@ label.

Reviewed By: rnk

Differential Revision: https://reviews.llvm.org/D128944
This commit is contained in:
Eric Astor 2022-07-06 12:31:50 -04:00
parent 8262ff44c5
commit 7d1a295484
3 changed files with 84 additions and 57 deletions

View File

@ -1585,6 +1585,16 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,
Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);
return false;
}
// Parse directional local label references.
if (Identifier.equals_insensitive("@b") ||
Identifier.equals_insensitive("@f")) {
bool Before = Identifier.equals_insensitive("@b");
MCSymbol *Sym = getContext().getDirectionalLocalSymbol(0, Before);
if (Before && Sym->isUndefined())
return Error(FirstTokenLoc, "Expected @@ label before @B reference");
Res = MCSymbolRefExpr::create(Sym, getContext());
return false;
}
// Parse symbol variant.
std::pair<StringRef, StringRef> Split;
if (!MAI.useParensForSymbolVariant()) {
@ -1714,34 +1724,10 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,
case AsmToken::BigNum:
return TokError("literal value out of range for directive");
case AsmToken::Integer: {
SMLoc Loc = getTok().getLoc();
int64_t IntVal = getTok().getIntVal();
Res = MCConstantExpr::create(IntVal, getContext());
EndLoc = Lexer.getTok().getEndLoc();
Lex(); // Eat token.
// Look for 'b' or 'f' following an Integer as a directional label.
if (Lexer.getKind() == AsmToken::Identifier) {
StringRef IDVal = getTok().getString();
// Look up the symbol variant if used.
std::pair<StringRef, StringRef> Split = IDVal.split('@');
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
if (Split.first.size() != IDVal.size()) {
Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);
if (Variant == MCSymbolRefExpr::VK_Invalid)
return TokError("invalid variant '" + Split.second + "'");
IDVal = Split.first;
}
if (IDVal == "f" || IDVal == "b") {
MCSymbol *Sym =
Ctx.getDirectionalLocalSymbol(IntVal, IDVal == "b");
Res = MCSymbolRefExpr::create(Sym, Variant, getContext());
if (IDVal == "b" && Sym->isUndefined())
return Error(Loc, "directional label undefined");
DirLabels.push_back(std::make_tuple(Loc, CppHashInfo, Sym));
EndLoc = Lexer.getTok().getEndLoc();
Lex(); // Eat identifier.
}
}
return false;
}
case AsmToken::String: {
@ -2110,29 +2096,9 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info,
AsmToken ID = getTok();
SMLoc IDLoc = ID.getLoc();
StringRef IDVal;
int64_t LocalLabelVal = -1;
if (Lexer.is(AsmToken::HashDirective))
return parseCppHashLineFilenameComment(IDLoc);
// Allow an integer followed by a ':' as a directional local label.
if (Lexer.is(AsmToken::Integer)) {
LocalLabelVal = getTok().getIntVal();
if (LocalLabelVal < 0) {
if (!TheCondState.Ignore) {
Lex(); // always eat a token
return Error(IDLoc, "unexpected token at start of statement");
}
IDVal = "";
} else {
IDVal = getTok().getString();
Lex(); // Consume the integer token to be used as an identifier token.
if (Lexer.getKind() != AsmToken::Colon) {
if (!TheCondState.Ignore) {
Lex(); // always eat a token
return Error(IDLoc, "unexpected token at start of statement");
}
}
}
} else if (Lexer.is(AsmToken::Dot)) {
if (Lexer.is(AsmToken::Dot)) {
// Treat '.' as a valid identifier in this context.
Lex();
IDVal = ".";
@ -2257,19 +2223,22 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info,
// FIXME: This doesn't diagnose assignment to a symbol which has been
// implicitly marked as external.
MCSymbol *Sym;
if (LocalLabelVal == -1) {
if (ParsingMSInlineAsm && SI) {
StringRef RewrittenLabel =
SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);
assert(!RewrittenLabel.empty() &&
"We should have an internal name here.");
Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),
RewrittenLabel);
IDVal = RewrittenLabel;
}
if (ParsingMSInlineAsm && SI) {
StringRef RewrittenLabel =
SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);
assert(!RewrittenLabel.empty() &&
"We should have an internal name here.");
Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),
RewrittenLabel);
IDVal = RewrittenLabel;
}
// Handle directional local labels
if (IDVal == "@@") {
Sym = Ctx.createDirectionalLocalSymbol(0);
} else {
Sym = getContext().getOrCreateSymbol(IDVal);
} else
Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal);
}
// End of Labels should be treated as end of line for lexing
// purposes but that information is not available to the Lexer who
// does not understand Labels. This may cause us to see a Hash

View File

@ -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 [[TEMP1:[[:alpha:][:digit:]]+]]
; CHECK-NEXT: jmp [[TEMP1]]
@@:
xor eax, eax
; CHECK: [[TEMP1]]:
; CHECK-NEXT: xor eax, eax
t2:
jmp @B
jmp @B
; CHECK-LABEL: t2:
; CHECK-NEXT: jmp [[TEMP1]]
; CHECK-NEXT: jmp [[TEMP1]]
t3:
jmp @F
; CHECK-LABEL: t3:
; CHECK-NEXT: jmp [[TEMP2:[[:alpha:][:digit:]]+]]
@@:
xor eax, eax
; CHECK: [[TEMP2]]:
; CHECK-NEXT: xor eax, eax
@@:
xor eax, eax
; CHECK: [[TEMP3:[[:alpha:][:digit:]]+]]:
; CHECK-NEXT: xor eax, eax
t4:
jmp @B
; CHECK-LABEL: t4:
; CHECK-NEXT: jmp [[TEMP3]]

View File

@ -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