//===----------------------------------------------------------------------===//
#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/AsmCond.h"
#include "llvm/MC/MCParser/AsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
MCAsmParserSemaCallback::~MCAsmParserSemaCallback() {}
namespace {
-
/// \brief Helper types for tracking macro definitions.
typedef std::vector<AsmToken> MCAsmMacroArgument;
typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;
-typedef std::pair<StringRef, MCAsmMacroArgument> MCAsmMacroParameter;
+
+struct MCAsmMacroParameter {
+ StringRef Name;
+ MCAsmMacroArgument Value;
+ bool Required;
+
+ MCAsmMacroParameter() : Required(false) { }
+};
+
typedef std::vector<MCAsmMacroParameter> MCAsmMacroParameters;
struct MCAsmMacro {
MCAsmMacroParameters Parameters;
public:
- MCAsmMacro(StringRef N, StringRef B, const MCAsmMacroParameters &P) :
+ MCAsmMacro(StringRef N, StringRef B, ArrayRef<MCAsmMacroParameter> P) :
Name(N), Body(B), Parameters(P) {}
-
- MCAsmMacro(const MCAsmMacro& Other)
- : Name(Other.Name), Body(Other.Body), Parameters(Other.Parameters) {}
};
/// \brief Helper class for storing information about an active macro
AssemblerDialect = i;
}
+ virtual void Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = None);
virtual bool Warning(SMLoc L, const Twine &Msg,
ArrayRef<SMRange> Ranges = None);
virtual bool Error(SMLoc L, const Twine &Msg,
bool parseCppHashLineFilenameComment(const SMLoc &L);
void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body,
- MCAsmMacroParameters Parameters);
+ ArrayRef<MCAsmMacroParameter> Parameters);
bool expandMacro(raw_svector_ostream &OS, StringRef Body,
- const MCAsmMacroParameters &Parameters,
- const MCAsmMacroArguments &A,
+ ArrayRef<MCAsmMacroParameter> Parameters,
+ ArrayRef<MCAsmMacroArgument> A,
const SMLoc &L);
/// \brief Are macros enabled in the parser?
/// \brief Handle exit from macro instantiation.
void handleMacroExit();
- /// \brief Extract AsmTokens for a macro argument. If the argument delimiter
- /// is initially unknown, set it to AsmToken::Eof. It will be set to the
- /// correct delimiter by the method.
- bool parseMacroArgument(MCAsmMacroArgument &MA,
- AsmToken::TokenKind &ArgumentDelimiter);
+ /// \brief Extract AsmTokens for a macro argument.
+ bool parseMacroArgument(MCAsmMacroArgument &MA);
/// \brief Parse all macro arguments for a given macro.
bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A);
enum DirectiveKind {
DK_NO_DIRECTIVE, // Placeholder
DK_SET, DK_EQU, DK_EQUIV, DK_ASCII, DK_ASCIZ, DK_STRING, DK_BYTE, DK_SHORT,
- DK_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, DK_SINGLE,
- DK_FLOAT, DK_DOUBLE, DK_ALIGN, DK_ALIGN32, DK_BALIGN, DK_BALIGNW,
+ DK_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, DK_OCTA,
+ DK_SINGLE, DK_FLOAT, DK_DOUBLE, DK_ALIGN, DK_ALIGN32, DK_BALIGN, DK_BALIGNW,
DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR,
DK_BUNDLE_ALIGN_MODE, DK_BUNDLE_LOCK, DK_BUNDLE_UNLOCK,
DK_ZERO, DK_EXTERN, DK_GLOBL, DK_GLOBAL,
DK_CFI_RESTORE, DK_CFI_ESCAPE, DK_CFI_SIGNAL_FRAME, DK_CFI_UNDEFINED,
DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE,
DK_MACROS_ON, DK_MACROS_OFF, DK_MACRO, DK_ENDM, DK_ENDMACRO, DK_PURGEM,
- DK_SLEB128, DK_ULEB128
+ DK_SLEB128, DK_ULEB128,
+ DK_END
};
/// \brief Maps directive name --> DirectiveKind enum, for
// ".ascii", ".asciz", ".string"
bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);
bool parseDirectiveValue(unsigned Size); // ".byte", ".long", ...
+ bool parseDirectiveOctaValue(); // ".octa"
bool parseDirectiveRealValue(const fltSemantics &); // ".single", ...
bool parseDirectiveFill(); // ".fill"
bool parseDirectiveZero(); // ".zero"
MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);
void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
raw_svector_ostream &OS);
- bool parseDirectiveRept(SMLoc DirectiveLoc); // ".rept"
+ bool parseDirectiveRept(SMLoc DirectiveLoc, StringRef Directive);
bool parseDirectiveIrp(SMLoc DirectiveLoc); // ".irp"
bool parseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc"
bool parseDirectiveEndr(SMLoc DirectiveLoc); // ".endr"
// "align"
bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info);
+ // "end"
+ bool parseDirectiveEnd(SMLoc DirectiveLoc);
+
void initializeDirectiveKindMap();
};
}
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer));
// Initialize the platform / file format parser.
- //
- // FIXME: This is a hack, we need to (majorly) cleanup how these objects are
- // created.
- if (_MAI.hasMicrosoftFastStdCallMangling()) {
- PlatformParser = createCOFFAsmParser();
- PlatformParser->Initialize(*this);
- } else if (_MAI.hasSubsectionsViaSymbols()) {
- PlatformParser = createDarwinAsmParser();
- PlatformParser->Initialize(*this);
- IsDarwin = true;
- } else {
- PlatformParser = createELFAsmParser();
- PlatformParser->Initialize(*this);
+ switch (_Ctx.getObjectFileInfo()->getObjectFileType()) {
+ case MCObjectFileInfo::IsCOFF:
+ PlatformParser = createCOFFAsmParser();
+ PlatformParser->Initialize(*this);
+ break;
+ case MCObjectFileInfo::IsMachO:
+ PlatformParser = createDarwinAsmParser();
+ PlatformParser->Initialize(*this);
+ IsDarwin = true;
+ break;
+ case MCObjectFileInfo::IsELF:
+ PlatformParser = createELFAsmParser();
+ PlatformParser->Initialize(*this);
+ break;
}
initializeDirectiveKindMap();
"while in macro instantiation");
}
+void AsmParser::Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) {
+ printMessage(L, SourceMgr::DK_Note, Msg, Ranges);
+ printMacroInstantiations();
+}
+
bool AsmParser::Warning(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) {
if (FatalAssemblerWarnings)
return Error(L, Msg, Ranges);
void AsmParser::checkForValidSection() {
if (!ParsingInlineAsm && !getStreamer().getCurrentSection().first) {
TokError("expected section directive before assembly directive");
- Out.InitToTextSection();
+ Out.InitSections();
}
}
Res = MCUnaryExpr::CreateLNot(Res, getContext());
return false;
case AsmToken::Dollar:
+ case AsmToken::At:
case AsmToken::String:
case AsmToken::Identifier: {
StringRef Identifier;
return true;
}
}
+ // Parse symbol variant
+ std::pair<StringRef, StringRef> Split;
+ if (!MAI.useParensForSymbolVariant()) {
+ Split = Identifier.split('@');
+ } else if (Lexer.is(AsmToken::LParen)) {
+ Lexer.Lex(); // eat (
+ StringRef VName;
+ parseIdentifier(VName);
+ if (Lexer.isNot(AsmToken::RParen)) {
+ return Error(Lexer.getTok().getLoc(),
+ "unexpected token in variant, expected ')'");
+ }
+ Lexer.Lex(); // eat )
+ Split = std::make_pair(Identifier, VName);
+ }
EndLoc = SMLoc::getFromPointer(Identifier.end());
// This is a symbol reference.
StringRef SymbolName = Identifier;
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
- std::pair<StringRef, StringRef> Split = Identifier.split('@');
-
- if (Split.first.size() != Identifier.size() &&
- FirstTokenKind != AsmToken::String) {
- SymbolName = Split.first;
- StringRef VariantName = Split.second;
- // Lookup the symbol variant.
- Variant = MCSymbolRefExpr::getVariantKindForName(VariantName);
- if (Variant == MCSymbolRefExpr::VK_Invalid) {
+ // Lookup the symbol variant if used.
+ if (Split.second.size()) {
+ Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);
+ if (Variant != MCSymbolRefExpr::VK_Invalid) {
+ SymbolName = Split.first;
+ } else if (MAI.doesAllowAtInName() && !MAI.useParensForSymbolVariant()) {
Variant = MCSymbolRefExpr::VK_None;
- return TokError("invalid variant '" + VariantName + "'");
+ } else {
+ return Error(SMLoc::getFromPointer(Split.second.begin()),
+ "invalid variant '" + Split.second + "'");
}
}
Res = MCSymbolRefExpr::Create(Sym, Variant, getContext());
return false;
}
+ case AsmToken::BigNum:
+ return TokError("literal value out of range for directive");
case AsmToken::Integer: {
SMLoc Loc = getTok().getLoc();
int64_t IntVal = getTok().getIntVal();
MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(),
IDLoc);
+ getTargetParser().onLabelParsed(Sym);
+
// Consume any end of statement token, if present, to avoid spurious
// AddBlankLine calls().
if (Lexer.is(AsmToken::EndOfStatement)) {
if (!getTargetParser().ParseDirective(ID))
return false;
- // Next, check the extention directive map to see if any extension has
+ // Next, check the extension directive map to see if any extension has
// registered itself to parse this directive.
std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =
ExtensionDirectiveMap.lookup(IDVal);
case DK_QUAD:
case DK_8BYTE:
return parseDirectiveValue(8);
+ case DK_OCTA:
+ return parseDirectiveOctaValue();
case DK_SINGLE:
case DK_FLOAT:
return parseDirectiveRealValue(APFloat::IEEEsingle);
case DK_CODE16GCC:
return TokError(Twine(IDVal) + " not supported yet");
case DK_REPT:
- return parseDirectiveRept(IDLoc);
+ return parseDirectiveRept(IDLoc, IDVal);
case DK_IRP:
return parseDirectiveIrp(IDLoc);
case DK_IRPC:
return parseDirectiveEndMacro(IDVal);
case DK_PURGEM:
return parseDirectivePurgeMacro(IDLoc);
+ case DK_END:
+ return parseDirectiveEnd(IDLoc);
}
return Error(IDLoc, "unknown directive");
}
bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
- const MCAsmMacroParameters &Parameters,
- const MCAsmMacroArguments &A, const SMLoc &L) {
+ ArrayRef<MCAsmMacroParameter> Parameters,
+ ArrayRef<MCAsmMacroArgument> A, const SMLoc &L) {
unsigned NParameters = Parameters.size();
- if (NParameters != 0 && NParameters != A.size())
+ if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
return Error(L, "Wrong number of arguments");
// A macro without parameters is handled differently on Darwin:
std::size_t End = Body.size(), Pos = 0;
for (; Pos != End; ++Pos) {
// Check for a substitution or escape.
- if (!NParameters) {
+ if (IsDarwin && !NParameters) {
// This macro has no parameters, look for $0, $1, etc.
if (Body[Pos] != '$' || Pos + 1 == End)
continue;
if (Pos == End)
break;
- if (!NParameters) {
+ if (IsDarwin && !NParameters) {
switch (Body[Pos + 1]) {
// $$ => $
case '$':
StringRef Argument(Begin, I - (Pos + 1));
unsigned Index = 0;
for (; Index < NParameters; ++Index)
- if (Parameters[Index].first == Argument)
+ if (Parameters[Index].Name == Argument)
break;
if (Index == NParameters) {
}
}
-bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA,
- AsmToken::TokenKind &ArgumentDelimiter) {
+namespace {
+class AsmLexerSkipSpaceRAII {
+public:
+ AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) : Lexer(Lexer) {
+ Lexer.setSkipSpace(SkipSpace);
+ }
+
+ ~AsmLexerSkipSpaceRAII() {
+ Lexer.setSkipSpace(true);
+ }
+
+private:
+ AsmLexer &Lexer;
+};
+}
+
+bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA) {
unsigned ParenLevel = 0;
unsigned AddTokens = 0;
- // gas accepts arguments separated by whitespace, except on Darwin
- if (!IsDarwin)
- Lexer.setSkipSpace(false);
+ // Darwin doesn't use spaces to delmit arguments.
+ AsmLexerSkipSpaceRAII ScopedSkipSpace(Lexer, IsDarwin);
for (;;) {
- if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) {
- Lexer.setSkipSpace(true);
+ if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))
return TokError("unexpected token in macro instantiation");
- }
- if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) {
- // Spaces and commas cannot be mixed to delimit parameters
- if (ArgumentDelimiter == AsmToken::Eof)
- ArgumentDelimiter = AsmToken::Comma;
- else if (ArgumentDelimiter != AsmToken::Comma) {
- Lexer.setSkipSpace(true);
- return TokError("expected ' ' for macro argument separator");
- }
+ if (ParenLevel == 0 && Lexer.is(AsmToken::Comma))
break;
- }
if (Lexer.is(AsmToken::Space)) {
Lex(); // Eat spaces
// Spaces can delimit parameters, but could also be part an expression.
// If the token after a space is an operator, add the token and the next
// one into this argument
- if (ArgumentDelimiter == AsmToken::Space ||
- ArgumentDelimiter == AsmToken::Eof) {
+ if (!IsDarwin) {
if (isOperator(Lexer.getKind())) {
// Check to see whether the token is used as an operator,
// or part of an identifier
}
if (!AddTokens && ParenLevel == 0) {
- if (ArgumentDelimiter == AsmToken::Eof &&
- !isOperator(Lexer.getKind()))
- ArgumentDelimiter = AsmToken::Space;
break;
}
}
Lex();
}
- Lexer.setSkipSpace(true);
if (ParenLevel != 0)
return TokError("unbalanced parentheses in macro argument");
return false;
bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
MCAsmMacroArguments &A) {
const unsigned NParameters = M ? M->Parameters.size() : 0;
- // Argument delimiter is initially unknown. It will be set by
- // parseMacroArgument()
- AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof;
+ bool NamedParametersFound = false;
+ SmallVector<SMLoc, 4> FALocs;
+
+ A.resize(NParameters);
+ FALocs.resize(NParameters);
// Parse two kinds of macro invocations:
// - macros defined without any parameters accept an arbitrary number of them
// - macros defined with parameters accept at most that many of them
for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;
++Parameter) {
- MCAsmMacroArgument MA;
+ SMLoc IDLoc = Lexer.getLoc();
+ MCAsmMacroParameter FA;
- if (parseMacroArgument(MA, ArgumentDelimiter))
+ if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) {
+ if (parseIdentifier(FA.Name)) {
+ Error(IDLoc, "invalid argument identifier for formal argument");
+ eatToEndOfStatement();
+ return true;
+ }
+
+ if (!Lexer.is(AsmToken::Equal)) {
+ TokError("expected '=' after formal parameter identifier");
+ eatToEndOfStatement();
+ return true;
+ }
+ Lex();
+
+ NamedParametersFound = true;
+ }
+
+ if (NamedParametersFound && FA.Name.empty()) {
+ Error(IDLoc, "cannot mix positional and keyword arguments");
+ eatToEndOfStatement();
return true;
+ }
+
+ if (parseMacroArgument(FA.Value))
+ return true;
+
+ unsigned PI = Parameter;
+ if (!FA.Name.empty()) {
+ unsigned FAI = 0;
+ for (FAI = 0; FAI < NParameters; ++FAI)
+ if (M->Parameters[FAI].Name == FA.Name)
+ break;
+
+ if (FAI >= NParameters) {
+ Error(IDLoc,
+ "parameter named '" + FA.Name + "' does not exist for macro '" +
+ M->Name + "'");
+ return true;
+ }
+ PI = FAI;
+ }
+
+ if (!FA.Value.empty()) {
+ if (A.size() <= PI)
+ A.resize(PI + 1);
+ A[PI] = FA.Value;
- if (!MA.empty() || !NParameters)
- A.push_back(MA);
- else if (NParameters) {
- if (!M->Parameters[Parameter].second.empty())
- A.push_back(M->Parameters[Parameter].second);
+ if (FALocs.size() <= PI)
+ FALocs.resize(PI + 1);
+
+ FALocs[PI] = Lexer.getLoc();
}
// At the end of the statement, fill in remaining arguments that have
// default values. If there aren't any, then the next argument is
// required but missing
if (Lexer.is(AsmToken::EndOfStatement)) {
- if (NParameters && Parameter < NParameters - 1) {
- if (M->Parameters[Parameter + 1].second.empty())
- return TokError("macro argument '" +
- Twine(M->Parameters[Parameter + 1].first) +
- "' is missing");
- else
- continue;
+ bool Failure = false;
+ for (unsigned FAI = 0; FAI < NParameters; ++FAI) {
+ if (A[FAI].empty()) {
+ if (M->Parameters[FAI].Required) {
+ Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),
+ "missing value for required parameter "
+ "'" + M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");
+ Failure = true;
+ }
+
+ if (!M->Parameters[FAI].Value.empty())
+ A[FAI] = M->Parameters[FAI].Value;
+ }
}
- return false;
+ return Failure;
}
if (Lexer.is(AsmToken::Comma))
Lex();
}
- return TokError("Too many arguments");
+
+ return TokError("too many positional arguments");
}
const MCAsmMacro *AsmParser::lookupMacro(StringRef Name) {
if (parseMacroArguments(M, A))
return true;
- // Remove any trailing empty arguments. Do this after-the-fact as we have
- // to keep empty arguments in the middle of the list or positionality
- // gets off. e.g., "foo 1, , 2" vs. "foo 1, 2,"
- while (!A.empty() && A.back().empty())
- A.pop_back();
-
// Macro instantiation is lexical, unfortunately. We construct a new buffer
// to hold the macro body with substitutions.
SmallString<256> Buf;
if (Lexer.isNot(AsmToken::EndOfStatement))
return TokError("unexpected token in assignment");
- // Error on assignment to '.'.
- if (Name == ".") {
- return Error(EqualLoc, ("assignment to pseudo-symbol '.' is unsupported "
- "(use '.space' or '.org').)"));
- }
-
// Eat the end of statement marker.
Lex();
// Don't count these checks as uses.
Sym->setUsed(false);
+ } else if (Name == ".") {
+ if (Out.EmitValueToOffset(Value, 0)) {
+ Error(EqualLoc, "expected absolute expression");
+ eatToEndOfStatement();
+ }
+ return false;
} else
Sym = getContext().GetOrCreateSymbol(Name);
- // FIXME: Handle '.'.
-
// Do the assignment.
Out.EmitAssignment(Sym, Value);
if (NoDeadStrip)
/// ::= string
bool AsmParser::parseIdentifier(StringRef &Res) {
// The assembler has relaxed rules for accepting identifiers, in particular we
- // allow things like '.globl $foo', which would normally be separate
- // tokens. At this level, we have already lexed so we cannot (currently)
+ // allow things like '.globl $foo' and '.def @feat.00', which would normally be
+ // separate tokens. At this level, we have already lexed so we cannot (currently)
// handle this as a context dependent token, instead we detect adjacent tokens
// and return the combined identifier.
- if (Lexer.is(AsmToken::Dollar)) {
- SMLoc DollarLoc = getLexer().getLoc();
+ if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {
+ SMLoc PrefixLoc = getLexer().getLoc();
- // Consume the dollar sign, and check for a following identifier.
+ // Consume the prefix character, and check for a following identifier.
Lex();
if (Lexer.isNot(AsmToken::Identifier))
return true;
- // We have a '$' followed by an identifier, make sure they are adjacent.
- if (DollarLoc.getPointer() + 1 != getTok().getLoc().getPointer())
+ // We have a '$' or '@' followed by an identifier, make sure they are adjacent.
+ if (PrefixLoc.getPointer() + 1 != getTok().getLoc().getPointer())
return true;
// Construct the joined identifier and consume the token.
Res =
- StringRef(DollarLoc.getPointer(), getTok().getIdentifier().size() + 1);
+ StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1);
Lex();
return false;
}
return false;
}
+/// ParseDirectiveOctaValue
+/// ::= .octa [ hexconstant (, hexconstant)* ]
+bool AsmParser::parseDirectiveOctaValue() {
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ checkForValidSection();
+
+ for (;;) {
+ if (Lexer.getKind() == AsmToken::Error)
+ return true;
+ if (Lexer.getKind() != AsmToken::Integer &&
+ Lexer.getKind() != AsmToken::BigNum)
+ return TokError("unknown token in expression");
+
+ SMLoc ExprLoc = getLexer().getLoc();
+ APInt IntValue = getTok().getAPIntVal();
+ Lex();
+
+ uint64_t hi, lo;
+ if (IntValue.isIntN(64)) {
+ hi = 0;
+ lo = IntValue.getZExtValue();
+ } else if (IntValue.isIntN(128)) {
+ // It might actually have more than 128 bits, but the top ones are zero.
+ hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue();
+ lo = IntValue.getLoBits(64).getZExtValue();
+ } else
+ return Error(ExprLoc, "literal value out of range for directive");
+
+ if (MAI.isLittleEndian()) {
+ getStreamer().EmitIntValue(lo, 8);
+ getStreamer().EmitIntValue(hi, 8);
+ } else {
+ getStreamer().EmitIntValue(hi, 8);
+ getStreamer().EmitIntValue(lo, 8);
+ }
+
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ // FIXME: Improve diagnostic.
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+ }
+ }
+
+ Lex();
+ return false;
+}
+
/// parseDirectiveRealValue
/// ::= (.single | .double) [ expression (, expression)* ]
bool AsmParser::parseDirectiveRealValue(const fltSemantics &Semantics) {
bool AsmParser::parseDirectiveFill() {
checkForValidSection();
+ SMLoc RepeatLoc = getLexer().getLoc();
int64_t NumValues;
if (parseAbsoluteExpression(NumValues))
return true;
+ if (NumValues < 0) {
+ Warning(RepeatLoc,
+ "'.fill' directive with negative repeat count has no effect");
+ NumValues = 0;
+ }
+
int64_t FillSize = 1;
int64_t FillExpr = 0;
+ SMLoc SizeLoc, ExprLoc;
if (getLexer().isNot(AsmToken::EndOfStatement)) {
if (getLexer().isNot(AsmToken::Comma))
return TokError("unexpected token in '.fill' directive");
Lex();
+ SizeLoc = getLexer().getLoc();
if (parseAbsoluteExpression(FillSize))
return true;
return TokError("unexpected token in '.fill' directive");
Lex();
+ ExprLoc = getLexer().getLoc();
if (parseAbsoluteExpression(FillExpr))
return true;
}
}
- if (FillSize != 1 && FillSize != 2 && FillSize != 4 && FillSize != 8)
- return TokError("invalid '.fill' size, expected 1, 2, 4, or 8");
+ if (FillSize < 0) {
+ Warning(SizeLoc, "'.fill' directive with negative size has no effect");
+ NumValues = 0;
+ }
+ if (FillSize > 8) {
+ Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8");
+ FillSize = 8;
+ }
+
+ if (!isUInt<32>(FillExpr) && FillSize > 4)
+ Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits");
+
+ int64_t NonZeroFillSize = FillSize > 4 ? 4 : FillSize;
+ FillExpr &= ~0ULL >> (64 - NonZeroFillSize * 8);
- for (uint64_t i = 0, e = NumValues; i != e; ++i)
- getStreamer().EmitIntValue(FillExpr, FillSize);
+ for (uint64_t i = 0, e = NumValues; i != e; ++i) {
+ getStreamer().EmitIntValue(FillExpr, NonZeroFillSize);
+ getStreamer().EmitIntValue(0, FillSize - NonZeroFillSize);
+ }
return false;
}
}
/// parseDirectiveCFIStartProc
-/// ::= .cfi_startproc
+/// ::= .cfi_startproc [simple]
bool AsmParser::parseDirectiveCFIStartProc() {
- getStreamer().EmitCFIStartProc();
+ StringRef Simple;
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ if (parseIdentifier(Simple) || Simple != "simple")
+ return TokError("unexpected token in .cfi_startproc directive");
+
+ getStreamer().EmitCFIStartProc(!Simple.empty());
return false;
}
}
/// parseDirectiveMacro
-/// ::= .macro name [parameters]
+/// ::= .macro name[,] [parameters]
bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
StringRef Name;
if (parseIdentifier(Name))
return TokError("expected identifier in '.macro' directive");
+ if (getLexer().is(AsmToken::Comma))
+ Lex();
+
MCAsmMacroParameters Parameters;
- // Argument delimiter is initially unknown. It will be set by
- // parseMacroArgument()
- AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof;
- if (getLexer().isNot(AsmToken::EndOfStatement)) {
- for (;;) {
- MCAsmMacroParameter Parameter;
- if (parseIdentifier(Parameter.first))
- return TokError("expected identifier in '.macro' directive");
+ while (getLexer().isNot(AsmToken::EndOfStatement)) {
+ MCAsmMacroParameter Parameter;
+ if (parseIdentifier(Parameter.Name))
+ return TokError("expected identifier in '.macro' directive");
+
+ if (Lexer.is(AsmToken::Colon)) {
+ Lex(); // consume ':'
+
+ SMLoc QualLoc;
+ StringRef Qualifier;
+
+ QualLoc = Lexer.getLoc();
+ if (parseIdentifier(Qualifier))
+ return Error(QualLoc, "missing parameter qualifier for "
+ "'" + Parameter.Name + "' in macro '" + Name + "'");
+
+ if (Qualifier == "req")
+ Parameter.Required = true;
+ else
+ return Error(QualLoc, Qualifier + " is not a valid parameter qualifier "
+ "for '" + Parameter.Name + "' in macro '" + Name + "'");
+ }
- if (getLexer().is(AsmToken::Equal)) {
- Lex();
- if (parseMacroArgument(Parameter.second, ArgumentDelimiter))
- return true;
- }
+ if (getLexer().is(AsmToken::Equal)) {
+ Lex();
- Parameters.push_back(Parameter);
+ SMLoc ParamLoc;
- if (getLexer().is(AsmToken::Comma))
- Lex();
- else if (getLexer().is(AsmToken::EndOfStatement))
- break;
+ ParamLoc = Lexer.getLoc();
+ if (parseMacroArgument(Parameter.Value))
+ return true;
+
+ if (Parameter.Required)
+ Warning(ParamLoc, "pointless default value for required parameter "
+ "'" + Parameter.Name + "' in macro '" + Name + "'");
}
+
+ Parameters.push_back(Parameter);
+
+ if (getLexer().is(AsmToken::Comma))
+ Lex();
}
// Eat the end of statement.
Lex();
AsmToken EndToken, StartToken = getTok();
+ unsigned MacroDepth = 0;
// Lex the macro definition.
for (;;) {
return Error(DirectiveLoc, "no matching '.endmacro' in definition");
// Otherwise, check whether we have reach the .endmacro.
- if (getLexer().is(AsmToken::Identifier) &&
- (getTok().getIdentifier() == ".endm" ||
- getTok().getIdentifier() == ".endmacro")) {
- EndToken = getTok();
- Lex();
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return TokError("unexpected token in '" + EndToken.getIdentifier() +
- "' directive");
- break;
+ if (getLexer().is(AsmToken::Identifier)) {
+ if (getTok().getIdentifier() == ".endm" ||
+ getTok().getIdentifier() == ".endmacro") {
+ if (MacroDepth == 0) { // Outermost macro.
+ EndToken = getTok();
+ Lex();
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '" + EndToken.getIdentifier() +
+ "' directive");
+ break;
+ } else {
+ // Otherwise we just found the end of an inner macro.
+ --MacroDepth;
+ }
+ } else if (getTok().getIdentifier() == ".macro") {
+ // We allow nested macros. Those aren't instantiated until the outermost
+ // macro is expanded so just ignore them for now.
+ ++MacroDepth;
+ }
}
// Otherwise, scan til the end of the statement.
///
/// With the support added for named parameters there may be code out there that
/// is transitioning from positional parameters. In versions of gas that did
-/// not support named parameters they would be ignored on the macro defintion.
+/// not support named parameters they would be ignored on the macro definition.
/// But to support both styles of parameters this is not possible so if a macro
-/// defintion has named parameters but does not use them and has what appears
+/// definition has named parameters but does not use them and has what appears
/// to be positional parameters, strings like $1, $2, ... and $n, then issue a
/// warning that the positional parameter found in body which have no effect.
/// Hoping the developer will either remove the named parameters from the macro
-/// definiton so the positional parameters get used if that was what was
+/// definition so the positional parameters get used if that was what was
/// intended or change the macro to use the named parameters. It is possible
/// this warning will trigger when the none of the named parameters are used
/// and the strings like $1 are infact to simply to be passed trough unchanged.
void AsmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef Name,
StringRef Body,
- MCAsmMacroParameters Parameters) {
+ ArrayRef<MCAsmMacroParameter> Parameters) {
// If this macro is not defined with named parameters the warning we are
// checking for here doesn't apply.
unsigned NParameters = Parameters.size();
StringRef Argument(Begin, I - (Pos + 1));
unsigned Index = 0;
for (; Index < NParameters; ++Index)
- if (Parameters[Index].first == Argument)
+ if (Parameters[Index].Name == Argument)
break;
if (Index == NParameters) {
return false;
}
+/// parseDirectiveEnd
+/// ::= .end
+bool AsmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.end' directive");
+
+ Lex();
+
+ while (Lexer.isNot(AsmToken::Eof))
+ Lex();
+
+ return false;
+}
+
/// parseDirectiveEndIf
/// ::= .endif
bool AsmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {
DirectiveKindMap[".4byte"] = DK_4BYTE;
DirectiveKindMap[".quad"] = DK_QUAD;
DirectiveKindMap[".8byte"] = DK_8BYTE;
+ DirectiveKindMap[".octa"] = DK_OCTA;
DirectiveKindMap[".single"] = DK_SINGLE;
DirectiveKindMap[".float"] = DK_FLOAT;
DirectiveKindMap[".double"] = DK_DOUBLE;
DirectiveKindMap[".code16"] = DK_CODE16;
DirectiveKindMap[".code16gcc"] = DK_CODE16GCC;
DirectiveKindMap[".rept"] = DK_REPT;
+ DirectiveKindMap[".rep"] = DK_REPT;
DirectiveKindMap[".irp"] = DK_IRP;
DirectiveKindMap[".irpc"] = DK_IRPC;
DirectiveKindMap[".endr"] = DK_ENDR;
DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF;
DirectiveKindMap[".elseif"] = DK_ELSEIF;
DirectiveKindMap[".else"] = DK_ELSE;
+ DirectiveKindMap[".end"] = DK_END;
DirectiveKindMap[".endif"] = DK_ENDIF;
DirectiveKindMap[".skip"] = DK_SKIP;
DirectiveKindMap[".space"] = DK_SPACE;
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
// We Are Anonymous.
- StringRef Name;
- MCAsmMacroParameters Parameters;
- MacroLikeBodies.push_back(MCAsmMacro(Name, Body, Parameters));
+ MacroLikeBodies.push_back(MCAsmMacro(StringRef(), Body, None));
return &MacroLikeBodies.back();
}
Lex();
}
-bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc) {
+/// parseDirectiveRept
+/// ::= .rep | .rept count
+bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) {
+ const MCExpr *CountExpr;
+ SMLoc CountLoc = getTok().getLoc();
+ if (parseExpression(CountExpr))
+ return true;
+
int64_t Count;
- if (parseAbsoluteExpression(Count))
- return TokError("unexpected token in '.rept' directive");
+ if (!CountExpr->EvaluateAsAbsolute(Count)) {
+ eatToEndOfStatement();
+ return Error(CountLoc, "unexpected token in '" + Dir + "' directive");
+ }
if (Count < 0)
- return TokError("Count is negative");
+ return Error(CountLoc, "Count is negative");
if (Lexer.isNot(AsmToken::EndOfStatement))
- return TokError("unexpected token in '.rept' directive");
+ return TokError("unexpected token in '" + Dir + "' directive");
// Eat the end of statement.
Lex();
// Macro instantiation is lexical, unfortunately. We construct a new buffer
// to hold the macro body with substitutions.
SmallString<256> Buf;
- MCAsmMacroParameters Parameters;
- MCAsmMacroArguments A;
raw_svector_ostream OS(Buf);
while (Count--) {
- if (expandMacro(OS, M->Body, Parameters, A, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, None, None, getTok().getLoc()))
return true;
}
instantiateMacroLikeBody(M, DirectiveLoc, OS);
/// parseDirectiveIrp
/// ::= .irp symbol,values
bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) {
- MCAsmMacroParameters Parameters;
MCAsmMacroParameter Parameter;
- if (parseIdentifier(Parameter.first))
+ if (parseIdentifier(Parameter.Name))
return TokError("expected identifier in '.irp' directive");
- Parameters.push_back(Parameter);
-
if (Lexer.isNot(AsmToken::Comma))
return TokError("expected comma in '.irp' directive");
raw_svector_ostream OS(Buf);
for (MCAsmMacroArguments::iterator i = A.begin(), e = A.end(); i != e; ++i) {
- MCAsmMacroArguments Args;
- Args.push_back(*i);
-
- if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, Parameter, *i, getTok().getLoc()))
return true;
}
/// parseDirectiveIrpc
/// ::= .irpc symbol,values
bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) {
- MCAsmMacroParameters Parameters;
MCAsmMacroParameter Parameter;
- if (parseIdentifier(Parameter.first))
+ if (parseIdentifier(Parameter.Name))
return TokError("expected identifier in '.irpc' directive");
- Parameters.push_back(Parameter);
-
if (Lexer.isNot(AsmToken::Comma))
return TokError("expected comma in '.irpc' directive");
raw_svector_ostream OS(Buf);
StringRef Values = A.front().front().getString();
- std::size_t I, End = Values.size();
- for (I = 0; I < End; ++I) {
+ for (std::size_t I = 0, End = Values.size(); I != End; ++I) {
MCAsmMacroArgument Arg;
Arg.push_back(AsmToken(AsmToken::Identifier, Values.slice(I, I + 1)));
- MCAsmMacroArguments Args;
- Args.push_back(Arg);
-
- if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, Parameter, Arg, getTok().getLoc()))
return true;
}
AsmStrRewrites.push_back(AsmRewrite(AOK_Input, Start, SymName.size()));
}
}
+
+ // Consider implicit defs to be clobbers. Think of cpuid and push.
+ const uint16_t *ImpDefs = Desc.getImplicitDefs();
+ for (unsigned I = 0, E = Desc.getNumImplicitDefs(); I != E; ++I)
+ ClobberRegs.push_back(ImpDefs[I]);
}
// Set the number of Outputs and Inputs.