Index: llvm/include/llvm/MC/MCExpr.h =================================================================== --- llvm/include/llvm/MC/MCExpr.h +++ llvm/include/llvm/MC/MCExpr.h @@ -581,6 +581,9 @@ virtual bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const = 0; + // This should be set when assigned expressions are not valid ".set" + // expressions, e.g. registers, and must be inlined. + virtual bool inlineAssignedExpr() const { return false; } virtual void visitUsedExpr(MCStreamer& Streamer) const = 0; virtual MCFragment *findAssociatedFragment() const = 0; Index: llvm/include/llvm/MC/MCParser/MCAsmParser.h =================================================================== --- llvm/include/llvm/MC/MCParser/MCAsmParser.h +++ llvm/include/llvm/MC/MCParser/MCAsmParser.h @@ -214,6 +214,8 @@ return rv; } + void clearPendingErrors() { PendingErrors.clear(); } + bool addErrorSuffix(const Twine &Suffix); /// Get the next AsmToken in the stream, possibly handling file Index: llvm/include/llvm/MC/MCParser/MCAsmParserUtils.h =================================================================== --- llvm/include/llvm/MC/MCParser/MCAsmParserUtils.h +++ llvm/include/llvm/MC/MCParser/MCAsmParserUtils.h @@ -25,7 +25,7 @@ /// On success, returns false and sets the Symbol and Value output parameters. bool parseAssignmentExpression(StringRef Name, bool allow_redef, MCAsmParser &Parser, MCSymbol *&Symbol, - const MCExpr *&Value); + const MCExpr *&Value, bool AllowExtendedExpr = false); } // namespace MCParserUtils Index: llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h =================================================================== --- llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h +++ llvm/include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -371,6 +371,11 @@ SemaCallback = Callback; } + // Target-specific parsing of assembler-level variable assignment. + virtual bool parseAssignmentExpression(const MCExpr *&Res, SMLoc &EndLoc) { + return getParser().parseExpression(Res, EndLoc); + } + virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) = 0; Index: llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/lib/MC/MCAsmStreamer.cpp +++ llvm/lib/MC/MCAsmStreamer.cpp @@ -545,12 +545,19 @@ } void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { - OS << ".set "; - Symbol->print(OS, MAI); - OS << ", "; - Value->print(OS, MAI); + // Do not emit a .set on inlined target assignments. + bool EmitSet = true; + if (auto *E = dyn_cast(Value)) + if (E->inlineAssignedExpr()) + EmitSet = false; + if (EmitSet) { + OS << ".set "; + Symbol->print(OS, MAI); + OS << ", "; + Value->print(OS, MAI); - EmitEOL(); + EmitEOL(); + } MCStreamer::EmitAssignment(Symbol, Value); } Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -334,7 +334,7 @@ StringRef parseStringToComma(); bool parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip = false); + bool NoDeadStrip = false, bool AllowExtendedExpr = false); unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind); @@ -1113,13 +1113,17 @@ // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. - if (Sym->isVariable() && - isa(Sym->getVariableValue(/*SetUsed*/ false))) { - if (Variant) - return Error(EndLoc, "unexpected modifier on variable reference"); - - Res = Sym->getVariableValue(/*SetUsed*/ false); - return false; + if (Sym->isVariable()) { + auto V = Sym->getVariableValue(/*SetUsed*/ false); + bool DoInline = isa(V); + if (auto TV = dyn_cast(V)) + DoInline = TV->inlineAssignedExpr(); + if (DoInline) { + if (Variant) + return Error(EndLoc, "unexpected modifier on variable reference"); + Res = Sym->getVariableValue(/*SetUsed*/ false); + return false; + } } // Otherwise create a symbol ref. @@ -1814,7 +1818,7 @@ // identifier '=' ... -> assignment statement Lex(); - return parseAssignment(IDVal, true); + return parseAssignment(IDVal, true, /*NoDeadStrip*/ false, /*AllowExtendedExpr*/true); default: // Normal instruction or directive. break; @@ -2750,11 +2754,11 @@ } bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip) { + bool NoDeadStrip, bool AllowExtendedExpr) { MCSymbol *Sym; const MCExpr *Value; if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, - Value)) + Value, AllowExtendedExpr)) return true; if (!Sym) { @@ -5791,14 +5795,17 @@ bool parseAssignmentExpression(StringRef Name, bool allow_redef, MCAsmParser &Parser, MCSymbol *&Sym, - const MCExpr *&Value) { + const MCExpr *&Value, bool AllowExtendedExpr) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Parser.getTok().getLoc(); - - if (Parser.parseExpression(Value)) { - return Parser.TokError("missing expression"); - } + SMLoc EndLoc; + if (AllowExtendedExpr) { + if (Parser.getTargetParser().parseAssignmentExpression(Value, EndLoc)) { + return Parser.TokError("missing expression"); + } + } else if (Parser.parseExpression(Value, EndLoc)) + return Parser.TokError("missing expression"); // Note: we don't count b as used in "a = b". This is to allow // a = b Index: llvm/lib/MC/MCParser/MCAsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/MCAsmParser.cpp +++ llvm/lib/MC/MCParser/MCAsmParser.cpp @@ -86,7 +86,6 @@ } bool MCAsmParser::Error(SMLoc L, const Twine &Msg, SMRange Range) { - HadError = true; MCPendingError PErr; PErr.Loc = L; Index: llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -9,6 +9,7 @@ #include "InstPrinter/X86IntelInstPrinter.h" #include "MCTargetDesc/X86BaseInfo.h" +#include "MCTargetDesc/X86MCExpr.h" #include "MCTargetDesc/X86TargetStreamer.h" #include "X86AsmInstrumentation.h" #include "X86AsmParserCommon.h" @@ -953,6 +954,8 @@ void SetFrameRegister(unsigned RegNo) override; + bool parseAssignmentExpression(const MCExpr *&Res, SMLoc &EndLoc) override; + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; @@ -2018,6 +2021,9 @@ if (getLexer().isNot(AsmToken::LParen)) { SMLoc ExprEnd; if (getParser().parseExpression(Disp, ExprEnd)) return nullptr; + // Disp may be a variable, handle register values. + if (auto *RE = dyn_cast(Disp)) + return X86Operand::CreateReg(RE->getRegNo(), MemStart, ExprEnd); // After parsing the base expression we could either have a parenthesized // memory address or not. If not, return now. If so, eat the (. @@ -2182,6 +2188,25 @@ return X86Operand::CreateMem(getPointerWidth(), Disp, MemStart, MemEnd); } +// Parse either a standard expression or a register. +bool X86AsmParser::parseAssignmentExpression(const MCExpr *&Res, + SMLoc &EndLoc) { + MCAsmParser &Parser = getParser(); + if (Parser.parseExpression(Res, EndLoc)) { + SMLoc StartLoc = Parser.getTok().getLoc(); + // Normal Expression parse fails, check if it could be a register. + unsigned RegNo; + if (Parser.getTargetParser().ParseRegister(RegNo, StartLoc, EndLoc)) + return true; + // Clear previous parse error and return correct expression. + Parser.clearPendingErrors(); + Res = X86MCExpr::create(RegNo, Parser.getContext()); + return false; + } + + return false; +} + bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { MCAsmParser &Parser = getParser(); Index: llvm/lib/Target/X86/MCTargetDesc/X86MCExpr.h =================================================================== --- /dev/null +++ llvm/lib/Target/X86/MCTargetDesc/X86MCExpr.h @@ -0,0 +1,75 @@ +//=--- X86MCExpr.h - X86 specific MC expression classes ---*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes X86-specific MCExprs, i.e, registers used for +// extended variable assignments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_X86_MCTARGETDESC_X86MCEXPR_H +#define LLVM_LIB_TARGET_X86_MCTARGETDESC_X86MCEXPR_H + +#include "InstPrinter/X86ATTInstPrinter.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +class X86MCExpr : public MCTargetExpr { + +private: + const int64_t RegNo; // All + + explicit X86MCExpr(int64_t R) : RegNo(R) {} + +public: + /// @name Construction + /// @{ + + static const X86MCExpr *create(int64_t RegNo, MCContext &Ctx) { + return new (Ctx) X86MCExpr(RegNo); + } + + /// @} + /// @name Accessors + /// @{ + + /// getSubExpr - Get the child of this expression. + int64_t getRegNo() const { return RegNo; } + + /// @} + + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override { + if (MAI->getAssemblerDialect() == 0) + OS << '%'; + OS << X86ATTInstPrinter::getRegisterName(RegNo); + } + + bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, + const MCFixup *Fixup) const override { + return false; + } + // Register values should be inlined as they are not valid .set expressions. + bool inlineAssignedExpr() const override { return true; } + void visitUsedExpr(MCStreamer &Streamer) const override{}; + MCFragment *findAssociatedFragment() const override { return nullptr; } + + // There are no TLS X86MCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } +}; + +} // end namespace llvm + +#endif Index: llvm/test/MC/X86/pr37425.s =================================================================== --- /dev/null +++ llvm/test/MC/X86/pr37425.s @@ -0,0 +1,16 @@ +// RUN: llvm-mc -triple x86_64-unknown-unknown -defsym=ERR=0 %s -o - | FileCheck %s +// RUN: not llvm-mc -triple x86_64-unknown-unknown -defsym=ERR=1 %s -o - 2>&1 | FileCheck --check-prefix=ERR %s + +// CHECK-NOT: .set var_xdata +var_xdata = %rcx + +// CHECK: xorq %rcx, %rcx +xorq var_xdata, var_xdata + +.if (ERR==1) +// ERR: [[@LINE+2]]:15: error: unknown token in expression in '.set' directive +// ERR: [[@LINE+1]]:15: error: missing expression in '.set' directive +.set err_var, %rcx +.endif + +