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;
return rv;
}
+ void clearPendingErrors() { PendingErrors.clear(); }
+
bool addErrorSuffix(const Twine &Suffix);
/// Get the next AsmToken in the stream, possibly handling file
/// 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
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;
}
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<MCTargetExpr>(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);
}
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);
// If this is an absolute variable reference, substitute it now to preserve
// semantics in the face of reassignment.
- if (Sym->isVariable() &&
- isa<MCConstantExpr>(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<MCConstantExpr>(V);
+ if (auto TV = dyn_cast<MCTargetExpr>(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.
// identifier '=' ... -> assignment statement
Lex();
- return parseAssignment(IDVal, true);
+ return parseAssignment(IDVal, true, /*NoDeadStrip*/ false, /*AllowExtendedExpr*/true);
default: // Normal instruction or directive.
break;
}
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) {
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
}
bool MCAsmParser::Error(SMLoc L, const Twine &Msg, SMRange Range) {
- HadError = true;
MCPendingError PErr;
PErr.Loc = L;
#include "InstPrinter/X86IntelInstPrinter.h"
#include "MCTargetDesc/X86BaseInfo.h"
+#include "MCTargetDesc/X86MCExpr.h"
#include "MCTargetDesc/X86TargetStreamer.h"
#include "X86AsmInstrumentation.h"
#include "X86AsmParserCommon.h"
void SetFrameRegister(unsigned RegNo) override;
+ bool parseAssignmentExpression(const MCExpr *&Res, SMLoc &EndLoc) override;
+
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override;
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<X86MCExpr>(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 (.
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();
--- /dev/null
+//=--- 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
--- /dev/null
+// 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
+
+