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 @@ -1122,8 +1122,22 @@ } const AsmToken *tok = &Lexer.Lex(); + bool StartOfStatement = Lexer.isAtStartOfStatement(); while (tok->is(AsmToken::Identifier)) { + if (StartOfStatement) { + AsmToken NextTok; + + MutableArrayRef Buf(NextTok); + size_t ReadCount = Lexer.peekTokens(Buf); + if (ReadCount && NextTok.is(AsmToken::Identifier) && + (NextTok.getString().equals_lower("equ") || + NextTok.getString().equals_lower("textequ"))) { + // This looks like an EQU or TEXTEQU directive; don't expand the + // identifier, allowing for redefinitions. + break; + } + } auto it = Variables.find(tok->getIdentifier().lower()); const llvm::MCAsmMacro *M = getContext().lookupMacro(tok->getIdentifier().lower()); @@ -3327,35 +3341,38 @@ /// ::= name "=" expression /// | name "equ" expression (not redefinable) /// | name "equ" text-list -/// | name "textequ" text-list +/// | name "textequ" text-list (redefinability unspecified) bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name, DirectiveKind DirKind) { Variable &Var = Variables[Name.lower()]; if (Var.Name.empty()) { Var.Name = Name; - } else if (!Var.Redefinable) { - return TokError("invalid variable redefinition"); } - Var.Redefinable = (DirKind != DK_EQU); SMLoc StartLoc = Lexer.getLoc(); if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) { // "equ" and "textequ" both allow text expressions. std::string Value; - if (!parseTextItem(Value)) { - Var.IsText = true; - Var.TextValue = Value; + std::string TextItem; + if (!parseTextItem(TextItem)) { + Value += TextItem; // Accept a text-list, not just one text-item. auto parseItem = [&]() -> bool { - if (parseTextItem(Value)) + if (parseTextItem(TextItem)) return TokError("expected text item"); - Var.TextValue += Value; + Value += TextItem; return false; }; if (parseOptionalToken(AsmToken::Comma) && parseMany(parseItem)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + if (!Var.Redefinable && (!Var.IsText || Var.TextValue != Value)) + return Error(getTok().getLoc(), "invalid variable redefinition"); + Var.IsText = true; + Var.TextValue = Value; + Var.Redefinable = true; + return false; } } @@ -3367,19 +3384,28 @@ SMLoc EndLoc; if (parseExpression(Expr, EndLoc)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + + int64_t Value; + if (!Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) { + // Not an absolute expression; define as a text replacement. + StringRef ExprAsString = StringRef( + StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer()); + if (!Var.Redefinable && (!Var.IsText && Var.TextValue != ExprAsString)) + return Error(getTok().getLoc(), "invalid variable redefinition"); + Var.IsText = true; + Var.TextValue = ExprAsString.str(); + } else { + if (!Var.Redefinable && (Var.IsText || Var.NumericValue != Value)) + return Error(getTok().getLoc(), "invalid variable redefinition"); + Var.NumericValue = Value; + } + Var.Redefinable = (DirKind == DK_ASSIGN); + MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name); Sym->setRedefinable(Var.Redefinable); Sym->setVariableValue(Expr); Sym->setExternal(false); - if (Expr->evaluateAsAbsolute(Var.NumericValue, - getStreamer().getAssemblerPtr())) - return false; - - // Not an absolute expression; define as a text replacement. - Var.IsText = true; - Var.TextValue = StringRef(StartLoc.getPointer(), - EndLoc.getPointer() - StartLoc.getPointer()).str(); return false; } diff --git a/llvm/test/tools/llvm-ml/variable_redef.asm b/llvm/test/tools/llvm-ml/variable_redef.asm new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/variable_redef.asm @@ -0,0 +1,76 @@ +; RUN: llvm-ml -filetype=s %s /Fo - | FileCheck %s + +.data + +; = can be redefined at any time. +assigned_number = 1 +t1_original BYTE assigned_number +assigned_number = 1 +t1_reset BYTE assigned_number +assigned_number = 2 +t1_changed BYTE assigned_number + +; CHECK-LABEL: t1_original: +; CHECK-NEXT: .byte 1 + +; CHECK-LABEL: t1_reset: +; CHECK-NEXT: .byte 1 + +; CHECK-LABEL: t1_changed: +; CHECK-NEXT: .byte 2 + +; EQU can be redundantly set, but can't be changed. +equated_number equ 3 +t2_original BYTE equated_number +equated_number equ 3 +t2_reset BYTE equated_number + +; CHECK-LABEL: t2_original: +; CHECK-NEXT: .byte 3 + +; CHECK-LABEL: t2_reset: +; CHECK-NEXT: .byte 3 + +; EQU can be redefined at any time. +equated_text equ <4, 5> +t3_original BYTE equated_text +equated_text equ <4, 5> +t3_reset BYTE equated_text +equated_text equ <5, 6> +t3_changed BYTE equated_text + +; CHECK-LABEL: t3_original: +; CHECK-NEXT: .byte 4 +; CHECK-NEXT: .byte 5 + +; CHECK-LABEL: t3_reset: +; CHECK-NEXT: .byte 4 +; CHECK-NEXT: .byte 5 + +; CHECK-LABEL: t3_changed: +; CHECK-NEXT: .byte 5 +; CHECK-NEXT: .byte 6 + +; TEXTEQU can be redefined at any time. +textequated_text textequ <7, 8> +t4_original BYTE textequated_text +textequated_text textequ <7, 8> +t4_reset BYTE textequated_text +textequated_text textequ <9, 10> +t4_changed BYTE textequated_text + +; CHECK-LABEL: t4_original: +; CHECK-NEXT: .byte 7 +; CHECK-NEXT: .byte 8 + +; CHECK-LABEL: t4_reset: +; CHECK-NEXT: .byte 7 +; CHECK-NEXT: .byte 8 + +; CHECK-LABEL: t4_changed: +; CHECK-NEXT: .byte 9 +; CHECK-NEXT: .byte 10 + +.code + +end diff --git a/llvm/test/tools/llvm-ml/variable_redef_errors.asm b/llvm/test/tools/llvm-ml/variable_redef_errors.asm new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/variable_redef_errors.asm @@ -0,0 +1,12 @@ +; RUN: not llvm-ml -filetype=s %s /Fo - 2>&1 | FileCheck %s --implicit-check-not=error: + +.data + +; EQU can't be redefined to a new value +equated_number equ 3 +; CHECK: :[[# @LINE + 1]]:21: error: invalid variable redefinition +equated_number equ 4 + +.code + +end