2009-06-22 04:16:42 +08:00
|
|
|
//===- AsmParser.cpp - Parser for Assembly Files --------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This class implements the parser for assembly files.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-09-24 09:59:56 +08:00
|
|
|
#include "llvm/ADT/APFloat.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/ADT/APInt.h"
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/None.h"
|
2014-01-07 19:48:04 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2010-07-19 02:31:38 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2009-07-28 07:20:52 +08:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2010-07-19 02:31:38 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2016-08-27 01:58:37 +08:00
|
|
|
#include "llvm/MC/MCCodeView.h"
|
2009-06-24 06:01:43 +08:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/MC/MCDirectives.h"
|
2011-07-26 08:24:13 +08:00
|
|
|
#include "llvm/MC/MCDwarf.h"
|
2009-08-31 16:06:59 +08:00
|
|
|
#include "llvm/MC/MCExpr.h"
|
2012-10-18 23:49:34 +08:00
|
|
|
#include "llvm/MC/MCInstPrinter.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/MC/MCInstrDesc.h"
|
2012-10-18 23:49:34 +08:00
|
|
|
#include "llvm/MC/MCInstrInfo.h"
|
2013-12-10 04:26:40 +08:00
|
|
|
#include "llvm/MC/MCObjectFileInfo.h"
|
2010-07-19 02:31:38 +08:00
|
|
|
#include "llvm/MC/MCParser/AsmCond.h"
|
|
|
|
#include "llvm/MC/MCParser/AsmLexer.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
2010-07-19 02:31:38 +08:00
|
|
|
#include "llvm/MC/MCParser/MCAsmParser.h"
|
2015-06-23 03:35:57 +08:00
|
|
|
#include "llvm/MC/MCParser/MCAsmParserUtils.h"
|
2010-07-19 02:31:38 +08:00
|
|
|
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
2016-01-27 18:01:28 +08:00
|
|
|
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
2011-07-20 13:58:47 +08:00
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/MC/MCSection.h"
|
2009-06-24 06:01:43 +08:00
|
|
|
#include "llvm/MC/MCStreamer.h"
|
2009-06-30 07:43:14 +08:00
|
|
|
#include "llvm/MC/MCSymbol.h"
|
2015-11-12 21:33:00 +08:00
|
|
|
#include "llvm/MC/MCValue.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
2016-07-27 13:51:56 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/Support/Dwarf.h"
|
2012-01-28 23:28:41 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2011-06-30 00:05:14 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2010-06-29 05:45:58 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/Support/SMLoc.h"
|
2010-07-19 02:31:38 +08:00
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2009-06-22 04:54:55 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
2010-12-20 04:43:38 +08:00
|
|
|
#include <cctype>
|
2016-08-24 01:14:32 +08:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
2014-04-30 07:26:49 +08:00
|
|
|
#include <deque>
|
2016-08-24 01:14:32 +08:00
|
|
|
#include <memory>
|
2016-07-27 13:51:56 +08:00
|
|
|
#include <sstream>
|
2012-10-18 23:49:34 +08:00
|
|
|
#include <string>
|
2016-08-24 01:14:32 +08:00
|
|
|
#include <tuple>
|
|
|
|
#include <utility>
|
2010-07-19 02:31:38 +08:00
|
|
|
#include <vector>
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2009-06-22 04:16:42 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2012-12-18 08:30:54 +08:00
|
|
|
MCAsmParserSemaCallback::~MCAsmParserSemaCallback() {}
|
2012-10-19 15:00:09 +08:00
|
|
|
|
2016-07-27 13:51:56 +08:00
|
|
|
static cl::opt<unsigned> AsmMacroMaxNestingDepth(
|
|
|
|
"asm-macro-max-nesting-depth", cl::init(20), cl::Hidden,
|
|
|
|
cl::desc("The maximum nesting depth allowed for assembly macros."));
|
|
|
|
|
2010-07-13 01:54:38 +08:00
|
|
|
namespace {
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2013-01-17 02:56:50 +08:00
|
|
|
/// \brief Helper types for tracking macro definitions.
|
|
|
|
typedef std::vector<AsmToken> MCAsmMacroArgument;
|
|
|
|
typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;
|
2014-02-19 11:00:23 +08:00
|
|
|
|
|
|
|
struct MCAsmMacroParameter {
|
|
|
|
StringRef Name;
|
|
|
|
MCAsmMacroArgument Value;
|
2014-02-19 11:00:29 +08:00
|
|
|
bool Required;
|
2014-04-23 14:56:28 +08:00
|
|
|
bool Vararg;
|
2014-02-19 11:00:29 +08:00
|
|
|
|
2014-04-23 14:56:28 +08:00
|
|
|
MCAsmMacroParameter() : Required(false), Vararg(false) {}
|
2014-02-19 11:00:23 +08:00
|
|
|
};
|
|
|
|
|
2013-01-17 02:56:50 +08:00
|
|
|
typedef std::vector<MCAsmMacroParameter> MCAsmMacroParameters;
|
|
|
|
|
|
|
|
struct MCAsmMacro {
|
|
|
|
StringRef Name;
|
|
|
|
StringRef Body;
|
|
|
|
MCAsmMacroParameters Parameters;
|
|
|
|
|
|
|
|
public:
|
2014-10-04 02:32:55 +08:00
|
|
|
MCAsmMacro(StringRef N, StringRef B, MCAsmMacroParameters P)
|
|
|
|
: Name(N), Body(B), Parameters(std::move(P)) {}
|
2013-01-17 02:56:50 +08:00
|
|
|
};
|
|
|
|
|
2010-07-19 02:54:11 +08:00
|
|
|
/// \brief Helper class for storing information about an active macro
|
|
|
|
/// instantiation.
|
|
|
|
struct MacroInstantiation {
|
|
|
|
/// The location of the instantiation.
|
|
|
|
SMLoc InstantiationLoc;
|
|
|
|
|
2012-12-01 09:38:48 +08:00
|
|
|
/// The buffer where parsing should resume upon instantiation completion.
|
|
|
|
int ExitBuffer;
|
|
|
|
|
2010-07-19 02:54:11 +08:00
|
|
|
/// The location where parsing should resume upon instantiation completion.
|
|
|
|
SMLoc ExitLoc;
|
|
|
|
|
2014-07-25 01:08:39 +08:00
|
|
|
/// The depth of TheCondStack at the start of the instantiation.
|
|
|
|
size_t CondStackDepth;
|
|
|
|
|
2010-07-19 02:54:11 +08:00
|
|
|
public:
|
2014-08-28 03:49:03 +08:00
|
|
|
MacroInstantiation(SMLoc IL, int EB, SMLoc EL, size_t CondStackDepth);
|
2010-07-19 02:54:11 +08:00
|
|
|
};
|
|
|
|
|
2012-10-23 07:58:19 +08:00
|
|
|
struct ParseStatementInfo {
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief The parsed operands from the last parsed statement.
|
2014-06-09 00:18:35 +08:00
|
|
|
SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands;
|
2012-10-23 07:58:19 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief The opcode from the last parsed instruction.
|
2012-10-23 07:58:19 +08:00
|
|
|
unsigned Opcode;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Was there an error parsing the inline assembly?
|
2012-12-13 06:45:52 +08:00
|
|
|
bool ParseError;
|
|
|
|
|
2012-10-23 07:58:19 +08:00
|
|
|
SmallVectorImpl<AsmRewrite> *AsmRewrites;
|
|
|
|
|
2014-04-24 14:44:33 +08:00
|
|
|
ParseStatementInfo() : Opcode(~0U), ParseError(false), AsmRewrites(nullptr) {}
|
2012-10-23 07:58:19 +08:00
|
|
|
ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites)
|
2012-12-13 06:45:52 +08:00
|
|
|
: Opcode(~0), ParseError(false), AsmRewrites(rewrites) {}
|
2012-10-23 07:58:19 +08:00
|
|
|
};
|
|
|
|
|
2010-07-19 02:31:38 +08:00
|
|
|
/// \brief The concrete assembly parser instance.
|
|
|
|
class AsmParser : public MCAsmParser {
|
2015-02-16 06:54:22 +08:00
|
|
|
AsmParser(const AsmParser &) = delete;
|
|
|
|
void operator=(const AsmParser &) = delete;
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2010-07-19 02:31:38 +08:00
|
|
|
private:
|
|
|
|
AsmLexer Lexer;
|
|
|
|
MCContext &Ctx;
|
|
|
|
MCStreamer &Out;
|
2011-06-16 02:33:28 +08:00
|
|
|
const MCAsmInfo &MAI;
|
2010-07-19 02:31:38 +08:00
|
|
|
SourceMgr &SrcMgr;
|
2011-10-16 18:48:29 +08:00
|
|
|
SourceMgr::DiagHandlerTy SavedDiagHandler;
|
|
|
|
void *SavedDiagContext;
|
2014-10-04 02:32:55 +08:00
|
|
|
std::unique_ptr<MCAsmParserExtension> PlatformParser;
|
2011-04-12 05:49:50 +08:00
|
|
|
|
2010-07-19 02:31:38 +08:00
|
|
|
/// This is the current buffer index we're lexing from as managed by the
|
|
|
|
/// SourceMgr object.
|
2014-07-06 18:33:31 +08:00
|
|
|
unsigned CurBuffer;
|
2010-07-19 02:31:38 +08:00
|
|
|
|
|
|
|
AsmCond TheCondState;
|
|
|
|
std::vector<AsmCond> TheCondStack;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief maps directive names to handler methods in parser
|
2013-01-16 06:59:42 +08:00
|
|
|
/// extensions. Extensions register themselves in this map by calling
|
2013-02-21 06:21:35 +08:00
|
|
|
/// addDirectiveHandler.
|
2013-01-16 06:59:42 +08:00
|
|
|
StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap;
|
2010-07-19 02:38:02 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Map of currently defined macros.
|
2014-10-04 02:32:55 +08:00
|
|
|
StringMap<MCAsmMacro> MacroMap;
|
2010-07-19 02:47:21 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Stack of active macro instantiations.
|
2010-07-19 02:54:11 +08:00
|
|
|
std::vector<MacroInstantiation*> ActiveMacros;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief List of bodies of anonymous macros.
|
2013-08-04 17:06:29 +08:00
|
|
|
std::deque<MCAsmMacro> MacroLikeBodies;
|
|
|
|
|
2010-07-19 02:38:02 +08:00
|
|
|
/// Boolean tracking whether macro substitution is enabled.
|
2013-01-15 02:08:41 +08:00
|
|
|
unsigned MacrosEnabledFlag : 1;
|
2010-07-19 02:38:02 +08:00
|
|
|
|
2015-04-27 18:50:29 +08:00
|
|
|
/// \brief Keeps track of how many .macro's have been instantiated.
|
|
|
|
unsigned NumOfMacroInstantiations;
|
|
|
|
|
2011-10-13 05:38:39 +08:00
|
|
|
/// The values from the last parsed cpp hash file line comment if any.
|
2016-04-14 03:46:54 +08:00
|
|
|
struct CppHashInfoTy {
|
|
|
|
StringRef Filename;
|
2016-04-22 04:09:35 +08:00
|
|
|
int64_t LineNumber = 0;
|
2016-04-14 03:46:54 +08:00
|
|
|
SMLoc Loc;
|
2016-04-22 04:09:35 +08:00
|
|
|
unsigned Buf = 0;
|
2016-04-14 03:46:54 +08:00
|
|
|
};
|
|
|
|
CppHashInfoTy CppHashInfo;
|
|
|
|
|
|
|
|
/// \brief List of forward directional labels for diagnosis at the end.
|
|
|
|
SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels;
|
|
|
|
|
2013-06-22 04:51:39 +08:00
|
|
|
/// When generating dwarf for assembly source files we need to calculate the
|
|
|
|
/// logical line number based on the last parsed cpp hash file line comment
|
2013-08-20 21:33:18 +08:00
|
|
|
/// and current line. Since this is slow and messes up the SourceMgr's
|
2013-06-22 04:51:39 +08:00
|
|
|
/// cache we save the last info we queried with SrcMgr.FindLineNumber().
|
|
|
|
SMLoc LastQueryIDLoc;
|
2014-07-06 18:33:31 +08:00
|
|
|
unsigned LastQueryBuffer;
|
2013-06-22 04:51:39 +08:00
|
|
|
unsigned LastQueryLine;
|
2011-10-13 05:38:39 +08:00
|
|
|
|
2012-02-01 02:14:05 +08:00
|
|
|
/// AssemblerDialect. ~OU means unset value and use value provided by MAI.
|
|
|
|
unsigned AssemblerDialect;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief is Darwin compatibility enabled?
|
2012-09-20 04:36:12 +08:00
|
|
|
bool IsDarwin;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Are we parsing ms-style inline assembly?
|
2012-10-13 08:26:04 +08:00
|
|
|
bool ParsingInlineAsm;
|
|
|
|
|
2010-07-19 02:31:38 +08:00
|
|
|
public:
|
2011-08-17 02:33:49 +08:00
|
|
|
AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
|
2010-07-19 02:31:38 +08:00
|
|
|
const MCAsmInfo &MAI);
|
2015-04-11 10:11:45 +08:00
|
|
|
~AsmParser() override;
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2014-03-08 15:14:16 +08:00
|
|
|
bool Run(bool NoInitialTextSection, bool NoFinalize = false) override;
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2014-03-08 15:14:16 +08:00
|
|
|
void addDirectiveHandler(StringRef Directive,
|
|
|
|
ExtensionDirectiveHandler Handler) override {
|
2013-01-16 08:50:52 +08:00
|
|
|
ExtensionDirectiveMap[Directive] = Handler;
|
2010-07-19 02:31:38 +08:00
|
|
|
}
|
|
|
|
|
2015-04-21 19:50:52 +08:00
|
|
|
void addAliasForDirective(StringRef Directive, StringRef Alias) override {
|
|
|
|
DirectiveKindMap[Directive] = DirectiveKindMap[Alias];
|
|
|
|
}
|
|
|
|
|
2010-07-19 02:31:38 +08:00
|
|
|
public:
|
|
|
|
/// @name MCAsmParser Interface
|
|
|
|
/// {
|
|
|
|
|
2014-03-08 15:14:16 +08:00
|
|
|
SourceMgr &getSourceManager() override { return SrcMgr; }
|
|
|
|
MCAsmLexer &getLexer() override { return Lexer; }
|
|
|
|
MCContext &getContext() override { return Ctx; }
|
|
|
|
MCStreamer &getStreamer() override { return Out; }
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2016-08-27 01:58:37 +08:00
|
|
|
CodeViewContext &getCVContext() { return Ctx.getCVContext(); }
|
|
|
|
|
2014-03-08 15:14:16 +08:00
|
|
|
unsigned getAssemblerDialect() override {
|
2012-02-01 02:14:05 +08:00
|
|
|
if (AssemblerDialect == ~0U)
|
2012-12-18 08:30:54 +08:00
|
|
|
return MAI.getAssemblerDialect();
|
2012-02-01 02:14:05 +08:00
|
|
|
else
|
|
|
|
return AssemblerDialect;
|
|
|
|
}
|
2014-03-08 15:14:16 +08:00
|
|
|
void setAssemblerDialect(unsigned i) override {
|
2012-02-01 02:14:05 +08:00
|
|
|
AssemblerDialect = i;
|
|
|
|
}
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
void Note(SMLoc L, const Twine &Msg, SMRange Range = None) override;
|
|
|
|
bool Warning(SMLoc L, const Twine &Msg, SMRange Range = None) override;
|
|
|
|
bool printError(SMLoc L, const Twine &Msg, SMRange Range = None) override;
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2014-03-08 15:14:16 +08:00
|
|
|
const AsmToken &Lex() override;
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2016-09-03 07:15:29 +08:00
|
|
|
void setParsingInlineAsm(bool V) override {
|
|
|
|
ParsingInlineAsm = V;
|
|
|
|
Lexer.setParsingMSInlineAsm(V);
|
|
|
|
}
|
2014-03-08 15:14:16 +08:00
|
|
|
bool isParsingInlineAsm() override { return ParsingInlineAsm; }
|
2012-10-18 23:49:34 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
bool parseMSInlineAsm(void *AsmLoc, std::string &AsmString,
|
2012-10-18 23:49:34 +08:00
|
|
|
unsigned &NumOutputs, unsigned &NumInputs,
|
2012-10-24 01:43:43 +08:00
|
|
|
SmallVectorImpl<std::pair<void *,bool> > &OpDecls,
|
2012-10-18 23:49:34 +08:00
|
|
|
SmallVectorImpl<std::string> &Constraints,
|
|
|
|
SmallVectorImpl<std::string> &Clobbers,
|
2014-03-08 15:14:16 +08:00
|
|
|
const MCInstrInfo *MII, const MCInstPrinter *IP,
|
|
|
|
MCAsmParserSemaCallback &SI) override;
|
2012-10-13 08:26:04 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
bool parseExpression(const MCExpr *&Res);
|
2014-03-08 15:14:16 +08:00
|
|
|
bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override;
|
|
|
|
bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override;
|
|
|
|
bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override;
|
2015-06-25 17:52:02 +08:00
|
|
|
bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res,
|
|
|
|
SMLoc &EndLoc) override;
|
2014-03-08 15:14:16 +08:00
|
|
|
bool parseAbsoluteExpression(int64_t &Res) override;
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2016-09-24 03:25:15 +08:00
|
|
|
/// \brief Parse a floating point expression using the float \p Semantics
|
|
|
|
/// and set \p Res to the value.
|
|
|
|
bool parseRealValue(const fltSemantics &Semantics, APInt &Res);
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Parse an identifier or string (as a quoted identifier)
|
2013-01-12 08:05:00 +08:00
|
|
|
/// and set \p Res to the identifier contents.
|
2014-03-08 15:14:16 +08:00
|
|
|
bool parseIdentifier(StringRef &Res) override;
|
|
|
|
void eatToEndOfStatement() override;
|
2013-01-12 08:05:00 +08:00
|
|
|
|
2016-10-10 23:24:54 +08:00
|
|
|
bool checkForValidSection() override;
|
2016-07-18 23:24:03 +08:00
|
|
|
|
2010-07-19 02:31:38 +08:00
|
|
|
/// }
|
|
|
|
|
|
|
|
private:
|
2014-09-22 10:21:35 +08:00
|
|
|
bool parseStatement(ParseStatementInfo &Info,
|
|
|
|
MCAsmParserSemaCallback *SI);
|
2016-03-08 02:11:16 +08:00
|
|
|
bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites);
|
2015-09-21 07:35:59 +08:00
|
|
|
bool parseCppHashLineFilenameComment(SMLoc L);
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body,
|
2014-02-10 01:13:11 +08:00
|
|
|
ArrayRef<MCAsmMacroParameter> Parameters);
|
2012-06-04 07:57:14 +08:00
|
|
|
bool expandMacro(raw_svector_ostream &OS, StringRef Body,
|
2014-02-10 01:13:11 +08:00
|
|
|
ArrayRef<MCAsmMacroParameter> Parameters,
|
2015-04-27 18:50:29 +08:00
|
|
|
ArrayRef<MCAsmMacroArgument> A, bool EnableAtPseudoVariable,
|
2015-09-21 07:35:59 +08:00
|
|
|
SMLoc L);
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2013-01-17 02:56:50 +08:00
|
|
|
/// \brief Are macros enabled in the parser?
|
2013-09-21 07:08:21 +08:00
|
|
|
bool areMacrosEnabled() {return MacrosEnabledFlag;}
|
2013-01-17 02:56:50 +08:00
|
|
|
|
|
|
|
/// \brief Control a flag in the parser that enables or disables macros.
|
2013-09-21 07:08:21 +08:00
|
|
|
void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;}
|
2013-01-17 02:56:50 +08:00
|
|
|
|
|
|
|
/// \brief Lookup a previously defined macro.
|
|
|
|
/// \param Name Macro name.
|
|
|
|
/// \returns Pointer to macro. NULL if no such macro was defined.
|
2013-09-21 07:08:21 +08:00
|
|
|
const MCAsmMacro* lookupMacro(StringRef Name);
|
2013-01-17 02:56:50 +08:00
|
|
|
|
|
|
|
/// \brief Define a new macro with the given name and information.
|
2014-10-04 02:32:55 +08:00
|
|
|
void defineMacro(StringRef Name, MCAsmMacro Macro);
|
2013-01-17 02:56:50 +08:00
|
|
|
|
|
|
|
/// \brief Undefine a macro. If no such macro was defined, it's a no-op.
|
2013-09-21 07:08:21 +08:00
|
|
|
void undefineMacro(StringRef Name);
|
2013-01-17 02:56:50 +08:00
|
|
|
|
|
|
|
/// \brief Are we inside a macro instantiation?
|
2013-09-21 07:08:21 +08:00
|
|
|
bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}
|
2013-01-17 02:56:50 +08:00
|
|
|
|
2013-08-20 21:33:18 +08:00
|
|
|
/// \brief Handle entry to macro instantiation.
|
2013-01-17 02:56:50 +08:00
|
|
|
///
|
|
|
|
/// \param M The macro.
|
|
|
|
/// \param NameLoc Instantiation location.
|
2013-09-21 07:08:21 +08:00
|
|
|
bool handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc);
|
2013-01-17 02:56:50 +08:00
|
|
|
|
|
|
|
/// \brief Handle exit from macro instantiation.
|
2013-09-21 07:08:21 +08:00
|
|
|
void handleMacroExit();
|
2013-01-17 02:56:50 +08:00
|
|
|
|
2014-01-30 02:57:46 +08:00
|
|
|
/// \brief Extract AsmTokens for a macro argument.
|
2014-04-23 14:56:28 +08:00
|
|
|
bool parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg);
|
2013-01-17 02:56:50 +08:00
|
|
|
|
|
|
|
/// \brief Parse all macro arguments for a given macro.
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A);
|
2013-01-17 02:56:50 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
void printMacroInstantiations();
|
|
|
|
void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg,
|
2016-09-17 02:30:20 +08:00
|
|
|
SMRange Range = None) const {
|
|
|
|
ArrayRef<SMRange> Ranges(Range);
|
2011-10-16 13:47:55 +08:00
|
|
|
SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges);
|
2010-09-28 01:42:11 +08:00
|
|
|
}
|
2011-10-13 05:38:39 +08:00
|
|
|
static void DiagHandler(const SMDiagnostic &Diag, void *Context);
|
2010-09-28 01:42:11 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Enter the specified file. This returns true on failure.
|
|
|
|
bool enterIncludeFile(const std::string &Filename);
|
|
|
|
|
|
|
|
/// \brief Process the specified file for the .incbin directive.
|
2011-12-15 05:47:48 +08:00
|
|
|
/// This returns true on failure.
|
2016-09-23 08:41:06 +08:00
|
|
|
bool processIncbinFile(const std::string &Filename, int64_t Skip = 0,
|
|
|
|
const MCExpr *Count = nullptr, SMLoc Loc = SMLoc());
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2012-09-14 22:57:36 +08:00
|
|
|
/// \brief Reset the current lexer position to that given by \p Loc. The
|
2010-07-19 02:54:11 +08:00
|
|
|
/// current token is not set; clients should ensure Lex() is called
|
|
|
|
/// subsequently.
|
2012-12-01 09:38:48 +08:00
|
|
|
///
|
2014-07-06 18:33:31 +08:00
|
|
|
/// \param InBuffer If not 0, should be the known buffer id that contains the
|
2012-12-01 09:38:48 +08:00
|
|
|
/// location.
|
2014-07-06 18:33:31 +08:00
|
|
|
void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0);
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2010-07-19 04:15:59 +08:00
|
|
|
/// \brief Parse up to the end of statement and a return the contents from the
|
|
|
|
/// current token until the end of the statement; the current token on exit
|
|
|
|
/// will be either the EndOfStatement or EOF.
|
2014-03-08 15:14:16 +08:00
|
|
|
StringRef parseStringToEndOfStatement() override;
|
2010-07-19 04:15:59 +08:00
|
|
|
|
2012-05-12 19:18:51 +08:00
|
|
|
/// \brief Parse until the end of a statement or a comma is encountered,
|
|
|
|
/// return the contents from the current token up to the end or comma.
|
2013-09-21 07:08:21 +08:00
|
|
|
StringRef parseStringToComma();
|
2012-05-12 19:18:51 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseAssignment(StringRef Name, bool allow_redef,
|
2012-09-14 07:11:31 +08:00
|
|
|
bool NoDeadStrip = false);
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2015-04-28 08:17:39 +08:00
|
|
|
unsigned getBinOpPrecedence(AsmToken::TokenKind K,
|
|
|
|
MCBinaryExpr::Opcode &Kind);
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc);
|
|
|
|
bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc);
|
|
|
|
bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc);
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc);
|
2010-10-29 04:02:27 +08:00
|
|
|
|
2016-09-08 00:15:31 +08:00
|
|
|
bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName);
|
|
|
|
bool parseCVFileId(int64_t &FileId, StringRef DirectiveName);
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Generic (target and platform independent) directive parsing.
|
2013-01-11 06:44:57 +08:00
|
|
|
enum DirectiveKind {
|
2013-01-11 07:40:56 +08:00
|
|
|
DK_NO_DIRECTIVE, // Placeholder
|
|
|
|
DK_SET, DK_EQU, DK_EQUIV, DK_ASCII, DK_ASCIZ, DK_STRING, DK_BYTE, DK_SHORT,
|
2015-11-12 21:33:00 +08:00
|
|
|
DK_RELOC,
|
2014-02-02 00:20:59 +08:00
|
|
|
DK_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, DK_OCTA,
|
2016-08-24 05:34:53 +08:00
|
|
|
DK_DC, DK_DC_A, DK_DC_B, DK_DC_D, DK_DC_L, DK_DC_S, DK_DC_W, DK_DC_X,
|
2016-09-24 03:25:15 +08:00
|
|
|
DK_DCB, DK_DCB_B, DK_DCB_D, DK_DCB_L, DK_DCB_S, DK_DCB_W, DK_DCB_X,
|
2016-09-24 05:53:36 +08:00
|
|
|
DK_DS, DK_DS_B, DK_DS_D, DK_DS_L, DK_DS_P, DK_DS_S, DK_DS_W, DK_DS_X,
|
2014-02-02 00:20:59 +08:00
|
|
|
DK_SINGLE, DK_FLOAT, DK_DOUBLE, DK_ALIGN, DK_ALIGN32, DK_BALIGN, DK_BALIGNW,
|
2013-01-12 06:55:28 +08:00
|
|
|
DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR,
|
2013-01-11 07:40:56 +08:00
|
|
|
DK_BUNDLE_ALIGN_MODE, DK_BUNDLE_LOCK, DK_BUNDLE_UNLOCK,
|
2013-08-29 01:50:59 +08:00
|
|
|
DK_ZERO, DK_EXTERN, DK_GLOBL, DK_GLOBAL,
|
2016-04-12 02:33:45 +08:00
|
|
|
DK_LAZY_REFERENCE, DK_NO_DEAD_STRIP, DK_SYMBOL_RESOLVER,
|
2016-03-15 09:43:05 +08:00
|
|
|
DK_PRIVATE_EXTERN, DK_REFERENCE, DK_WEAK_DEFINITION, DK_WEAK_REFERENCE,
|
2013-01-11 07:40:56 +08:00
|
|
|
DK_WEAK_DEF_CAN_BE_HIDDEN, DK_COMM, DK_COMMON, DK_LCOMM, DK_ABORT,
|
|
|
|
DK_INCLUDE, DK_INCBIN, DK_CODE16, DK_CODE16GCC, DK_REPT, DK_IRP, DK_IRPC,
|
2014-06-19 04:57:28 +08:00
|
|
|
DK_IF, DK_IFEQ, DK_IFGE, DK_IFGT, DK_IFLE, DK_IFLT, DK_IFNE, DK_IFB,
|
2015-03-18 22:20:54 +08:00
|
|
|
DK_IFNB, DK_IFC, DK_IFEQS, DK_IFNC, DK_IFNES, DK_IFDEF, DK_IFNDEF,
|
|
|
|
DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF,
|
2013-01-16 06:59:42 +08:00
|
|
|
DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS,
|
2016-09-08 00:15:31 +08:00
|
|
|
DK_CV_FILE, DK_CV_FUNC_ID, DK_CV_INLINE_SITE_ID, DK_CV_LOC, DK_CV_LINETABLE,
|
|
|
|
DK_CV_INLINE_LINETABLE, DK_CV_DEF_RANGE, DK_CV_STRINGTABLE,
|
|
|
|
DK_CV_FILECHECKSUMS,
|
2013-01-16 06:59:42 +08:00
|
|
|
DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA,
|
|
|
|
DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER,
|
|
|
|
DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA,
|
|
|
|
DK_CFI_REMEMBER_STATE, DK_CFI_RESTORE_STATE, DK_CFI_SAME_VALUE,
|
|
|
|
DK_CFI_RESTORE, DK_CFI_ESCAPE, DK_CFI_SIGNAL_FRAME, DK_CFI_UNDEFINED,
|
2013-09-26 22:49:40 +08:00
|
|
|
DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE,
|
2014-07-25 01:08:39 +08:00
|
|
|
DK_MACROS_ON, DK_MACROS_OFF,
|
|
|
|
DK_MACRO, DK_EXITM, DK_ENDM, DK_ENDMACRO, DK_PURGEM,
|
2013-12-18 10:53:03 +08:00
|
|
|
DK_SLEB128, DK_ULEB128,
|
2014-07-25 00:26:06 +08:00
|
|
|
DK_ERR, DK_ERROR, DK_WARNING,
|
2013-12-18 10:53:03 +08:00
|
|
|
DK_END
|
2013-01-11 06:44:57 +08:00
|
|
|
};
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Maps directive name --> DirectiveKind enum, for
|
2013-01-16 06:59:42 +08:00
|
|
|
/// directives parsed by this class.
|
|
|
|
StringMap<DirectiveKind> DirectiveKindMap;
|
2013-01-11 06:44:57 +08:00
|
|
|
|
|
|
|
// ".ascii", ".asciz", ".string"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);
|
2015-11-12 21:33:00 +08:00
|
|
|
bool parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc"
|
2016-10-24 22:35:29 +08:00
|
|
|
bool parseDirectiveValue(StringRef IDVal,
|
|
|
|
unsigned Size); // ".byte", ".long", ...
|
|
|
|
bool parseDirectiveOctaValue(StringRef IDVal); // ".octa", ...
|
|
|
|
bool parseDirectiveRealValue(StringRef IDVal,
|
|
|
|
const fltSemantics &); // ".single", ...
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveFill(); // ".fill"
|
|
|
|
bool parseDirectiveZero(); // ".zero"
|
2012-12-18 08:30:54 +08:00
|
|
|
// ".set", ".equ", ".equiv"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveSet(StringRef IDVal, bool allow_redef);
|
|
|
|
bool parseDirectiveOrg(); // ".org"
|
2010-07-19 02:31:38 +08:00
|
|
|
// ".align{,32}", ".p2align{,w,l}"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveAlign(bool IsPow2, unsigned ValueSize);
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// ".file", ".line", ".loc", ".stabs"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveFile(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveLine();
|
|
|
|
bool parseDirectiveLoc();
|
|
|
|
bool parseDirectiveStabs();
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2016-09-08 00:15:31 +08:00
|
|
|
// ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable",
|
|
|
|
// ".cv_inline_linetable", ".cv_def_range"
|
2016-01-29 08:49:42 +08:00
|
|
|
bool parseDirectiveCVFile();
|
2016-09-08 00:15:31 +08:00
|
|
|
bool parseDirectiveCVFuncId();
|
|
|
|
bool parseDirectiveCVInlineSiteId();
|
2016-01-29 08:49:42 +08:00
|
|
|
bool parseDirectiveCVLoc();
|
|
|
|
bool parseDirectiveCVLinetable();
|
2016-01-30 03:24:12 +08:00
|
|
|
bool parseDirectiveCVInlineLinetable();
|
2016-02-05 09:55:49 +08:00
|
|
|
bool parseDirectiveCVDefRange();
|
2016-01-29 08:49:42 +08:00
|
|
|
bool parseDirectiveCVStringTable();
|
|
|
|
bool parseDirectiveCVFileChecksums();
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// .cfi directives
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
|
2013-09-26 22:49:40 +08:00
|
|
|
bool parseDirectiveCFIWindowSave();
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveCFISections();
|
|
|
|
bool parseDirectiveCFIStartProc();
|
|
|
|
bool parseDirectiveCFIEndProc();
|
|
|
|
bool parseDirectiveCFIDefCfaOffset();
|
|
|
|
bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveCFIAdjustCfaOffset();
|
|
|
|
bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveCFIOffset(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality);
|
|
|
|
bool parseDirectiveCFIRememberState();
|
|
|
|
bool parseDirectiveCFIRestoreState();
|
|
|
|
bool parseDirectiveCFISameValue(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveCFIRestore(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveCFIEscape();
|
|
|
|
bool parseDirectiveCFISignalFrame();
|
|
|
|
bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);
|
2013-01-16 06:59:42 +08:00
|
|
|
|
|
|
|
// macro directives
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);
|
2014-07-25 01:08:39 +08:00
|
|
|
bool parseDirectiveExitMacro(StringRef Directive);
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveEndMacro(StringRef Directive);
|
|
|
|
bool parseDirectiveMacro(SMLoc DirectiveLoc);
|
|
|
|
bool parseDirectiveMacrosOnOff(StringRef Directive);
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2012-12-21 03:05:53 +08:00
|
|
|
// ".bundle_align_mode"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveBundleAlignMode();
|
2012-12-21 03:05:53 +08:00
|
|
|
// ".bundle_lock"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveBundleLock();
|
2012-12-21 03:05:53 +08:00
|
|
|
// ".bundle_unlock"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveBundleUnlock();
|
2012-12-21 03:05:53 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// ".space", ".skip"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveSpace(StringRef IDVal);
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2016-09-24 03:25:15 +08:00
|
|
|
// ".dcb"
|
|
|
|
bool parseDirectiveDCB(StringRef IDVal, unsigned Size);
|
|
|
|
bool parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &);
|
2016-09-24 05:53:36 +08:00
|
|
|
// ".ds"
|
|
|
|
bool parseDirectiveDS(StringRef IDVal, unsigned Size);
|
2016-09-24 03:25:15 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// .sleb128 (Signed=true) and .uleb128 (Signed=false)
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveLEB128(bool Signed);
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Parse a directive like ".globl" which
|
2010-07-19 02:31:38 +08:00
|
|
|
/// accepts a single symbol (which should be a label or an external).
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr);
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm"
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveAbort(); // ".abort"
|
|
|
|
bool parseDirectiveInclude(); // ".include"
|
|
|
|
bool parseDirectiveIncbin(); // ".incbin"
|
2010-07-19 02:31:38 +08:00
|
|
|
|
2014-06-19 04:57:28 +08:00
|
|
|
// ".if", ".ifeq", ".ifge", ".ifgt" , ".ifle", ".iflt" or ".ifne"
|
|
|
|
bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind);
|
2012-05-12 19:18:42 +08:00
|
|
|
// ".ifb" or ".ifnb", depending on ExpectBlank.
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank);
|
2012-05-12 19:18:51 +08:00
|
|
|
// ".ifc" or ".ifnc", depending on ExpectEqual.
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual);
|
2015-03-18 22:20:54 +08:00
|
|
|
// ".ifeqs" or ".ifnes", depending on ExpectEqual.
|
|
|
|
bool parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual);
|
2011-02-09 06:29:56 +08:00
|
|
|
// ".ifdef" or ".ifndef", depending on expect_defined
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined);
|
|
|
|
bool parseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif"
|
|
|
|
bool parseDirectiveElse(SMLoc DirectiveLoc); // ".else"
|
|
|
|
bool parseDirectiveEndIf(SMLoc DirectiveLoc); // .endif
|
2014-03-08 15:14:16 +08:00
|
|
|
bool parseEscapedString(std::string &Data) override;
|
2010-09-17 10:47:07 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
const MCExpr *applyModifierToExpr(const MCExpr *E,
|
2010-09-17 10:47:07 +08:00
|
|
|
MCSymbolRefExpr::VariantKind Variant);
|
2012-05-13 00:31:10 +08:00
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
// Macro-like directives
|
2013-09-21 07:08:21 +08:00
|
|
|
MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);
|
|
|
|
void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
|
2012-06-04 07:57:14 +08:00
|
|
|
raw_svector_ostream &OS);
|
2013-12-28 13:54:33 +08:00
|
|
|
bool parseDirectiveRept(SMLoc DirectiveLoc, StringRef Directive);
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveIrp(SMLoc DirectiveLoc); // ".irp"
|
|
|
|
bool parseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc"
|
|
|
|
bool parseDirectiveEndr(SMLoc DirectiveLoc); // ".endr"
|
2012-10-18 23:49:34 +08:00
|
|
|
|
2013-02-13 05:33:51 +08:00
|
|
|
// "_emit" or "__emit"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info,
|
2013-02-13 05:33:51 +08:00
|
|
|
size_t Len);
|
|
|
|
|
|
|
|
// "align"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info);
|
2013-01-11 06:44:57 +08:00
|
|
|
|
2013-12-18 10:53:03 +08:00
|
|
|
// "end"
|
|
|
|
bool parseDirectiveEnd(SMLoc DirectiveLoc);
|
|
|
|
|
2014-02-24 07:02:23 +08:00
|
|
|
// ".err" or ".error"
|
|
|
|
bool parseDirectiveError(SMLoc DirectiveLoc, bool WithMessage);
|
2014-02-23 23:53:30 +08:00
|
|
|
|
2014-07-25 00:26:06 +08:00
|
|
|
// ".warning"
|
|
|
|
bool parseDirectiveWarning(SMLoc DirectiveLoc);
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
void initializeDirectiveKindMap();
|
2010-07-13 01:54:38 +08:00
|
|
|
};
|
2016-08-24 01:14:32 +08:00
|
|
|
|
|
|
|
} // end anonymous namespace
|
2010-07-13 01:54:38 +08:00
|
|
|
|
2010-07-13 04:51:51 +08:00
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
extern MCAsmParserExtension *createDarwinAsmParser();
|
2010-07-13 05:23:32 +08:00
|
|
|
extern MCAsmParserExtension *createELFAsmParser();
|
2010-10-09 19:01:07 +08:00
|
|
|
extern MCAsmParserExtension *createCOFFAsmParser();
|
2010-07-13 04:51:51 +08:00
|
|
|
|
2016-08-24 01:14:32 +08:00
|
|
|
} // end namespace llvm
|
2010-07-13 04:51:51 +08:00
|
|
|
|
2010-01-20 03:46:13 +08:00
|
|
|
enum { DEFAULT_ADDRSPACE = 0 };
|
|
|
|
|
2015-03-17 02:06:57 +08:00
|
|
|
AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
|
|
|
|
const MCAsmInfo &MAI)
|
|
|
|
: Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM),
|
|
|
|
PlatformParser(nullptr), CurBuffer(SM.getMainFileID()),
|
2016-09-17 02:30:20 +08:00
|
|
|
MacrosEnabledFlag(true), CppHashInfo(), AssemblerDialect(~0U),
|
|
|
|
IsDarwin(false), ParsingInlineAsm(false) {
|
|
|
|
HadError = false;
|
2011-10-16 18:48:29 +08:00
|
|
|
// Save the old handler.
|
|
|
|
SavedDiagHandler = SrcMgr.getDiagHandler();
|
|
|
|
SavedDiagContext = SrcMgr.getDiagContext();
|
|
|
|
// Set our own handler which calls the saved handler.
|
2011-10-13 05:38:39 +08:00
|
|
|
SrcMgr.setDiagHandler(DiagHandler, this);
|
2014-07-06 22:17:29 +08:00
|
|
|
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
|
2010-07-13 01:54:38 +08:00
|
|
|
|
2010-07-13 02:12:02 +08:00
|
|
|
// Initialize the platform / file format parser.
|
2015-08-14 23:48:41 +08:00
|
|
|
switch (Ctx.getObjectFileInfo()->getObjectFileType()) {
|
|
|
|
case MCObjectFileInfo::IsCOFF:
|
2014-10-04 02:32:55 +08:00
|
|
|
PlatformParser.reset(createCOFFAsmParser());
|
|
|
|
break;
|
2015-08-14 23:48:41 +08:00
|
|
|
case MCObjectFileInfo::IsMachO:
|
2014-10-04 02:32:55 +08:00
|
|
|
PlatformParser.reset(createDarwinAsmParser());
|
|
|
|
IsDarwin = true;
|
|
|
|
break;
|
2015-08-14 23:48:41 +08:00
|
|
|
case MCObjectFileInfo::IsELF:
|
2014-10-04 02:32:55 +08:00
|
|
|
PlatformParser.reset(createELFAsmParser());
|
|
|
|
break;
|
2010-07-13 02:12:02 +08:00
|
|
|
}
|
2013-01-11 06:44:57 +08:00
|
|
|
|
2014-10-04 02:32:55 +08:00
|
|
|
PlatformParser->Initialize(*this);
|
2013-01-16 06:59:42 +08:00
|
|
|
initializeDirectiveKindMap();
|
2015-04-27 18:50:29 +08:00
|
|
|
|
|
|
|
NumOfMacroInstantiations = 0;
|
2009-09-28 05:16:52 +08:00
|
|
|
}
|
|
|
|
|
2009-08-27 06:49:51 +08:00
|
|
|
AsmParser::~AsmParser() {
|
2014-05-22 01:53:18 +08:00
|
|
|
assert((HadError || ActiveMacros.empty()) &&
|
|
|
|
"Unexpected active macro instantiation!");
|
2009-08-27 06:49:51 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
void AsmParser::printMacroInstantiations() {
|
2010-07-19 02:54:11 +08:00
|
|
|
// Print the active macro instantiation stack.
|
2013-09-21 07:08:21 +08:00
|
|
|
for (std::vector<MacroInstantiation *>::const_reverse_iterator
|
|
|
|
it = ActiveMacros.rbegin(),
|
|
|
|
ie = ActiveMacros.rend();
|
|
|
|
it != ie; ++it)
|
|
|
|
printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note,
|
2011-10-16 13:43:57 +08:00
|
|
|
"while in macro instantiation");
|
2010-07-19 02:54:11 +08:00
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {
|
|
|
|
printPendingErrors();
|
|
|
|
printMessage(L, SourceMgr::DK_Note, Msg, Range);
|
2014-01-07 10:28:31 +08:00
|
|
|
printMacroInstantiations();
|
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
bool AsmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) {
|
2015-07-28 06:39:14 +08:00
|
|
|
if(getTargetParser().getTargetOptions().MCNoWarn)
|
|
|
|
return false;
|
2014-08-27 02:39:50 +08:00
|
|
|
if (getTargetParser().getTargetOptions().MCFatalWarnings)
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(L, Msg, Range);
|
|
|
|
printMessage(L, SourceMgr::DK_Warning, Msg, Range);
|
2013-09-21 07:08:21 +08:00
|
|
|
printMacroInstantiations();
|
2011-05-20 02:00:13 +08:00
|
|
|
return false;
|
2009-06-30 08:49:23 +08:00
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
bool AsmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) {
|
2010-09-10 06:42:56 +08:00
|
|
|
HadError = true;
|
2016-09-17 02:30:20 +08:00
|
|
|
printMessage(L, SourceMgr::DK_Error, Msg, Range);
|
2013-09-21 07:08:21 +08:00
|
|
|
printMacroInstantiations();
|
2009-06-22 05:22:11 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::enterIncludeFile(const std::string &Filename) {
|
2011-06-01 21:10:15 +08:00
|
|
|
std::string IncludedFile;
|
2014-07-06 18:33:31 +08:00
|
|
|
unsigned NewBuf =
|
|
|
|
SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);
|
|
|
|
if (!NewBuf)
|
2010-01-21 08:19:58 +08:00
|
|
|
return true;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-01-21 08:19:58 +08:00
|
|
|
CurBuffer = NewBuf;
|
2014-07-06 22:17:29 +08:00
|
|
|
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
|
2010-01-21 08:19:58 +08:00
|
|
|
return false;
|
|
|
|
}
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2013-05-15 07:36:24 +08:00
|
|
|
/// Process the specified .incbin file by searching for it in the include paths
|
2012-06-02 18:20:22 +08:00
|
|
|
/// then just emitting the byte contents of the file to the streamer. This
|
2011-12-15 05:47:48 +08:00
|
|
|
/// returns true on failure.
|
2016-09-23 08:41:06 +08:00
|
|
|
bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip,
|
|
|
|
const MCExpr *Count, SMLoc Loc) {
|
2011-12-15 05:47:48 +08:00
|
|
|
std::string IncludedFile;
|
2014-07-06 18:33:31 +08:00
|
|
|
unsigned NewBuf =
|
|
|
|
SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);
|
|
|
|
if (!NewBuf)
|
2011-12-15 05:47:48 +08:00
|
|
|
return true;
|
|
|
|
|
2011-12-15 06:34:45 +08:00
|
|
|
// Pick up the bytes from the file and emit them.
|
2016-09-23 08:41:06 +08:00
|
|
|
StringRef Bytes = SrcMgr.getMemoryBuffer(NewBuf)->getBuffer();
|
|
|
|
Bytes = Bytes.drop_front(Skip);
|
|
|
|
if (Count) {
|
|
|
|
int64_t Res;
|
|
|
|
if (!Count->evaluateAsAbsolute(Res))
|
|
|
|
return Error(Loc, "expected absolute expression");
|
|
|
|
if (Res < 0)
|
|
|
|
return Warning(Loc, "negative count has no effect");
|
|
|
|
Bytes = Bytes.take_front(Res);
|
|
|
|
}
|
|
|
|
getStreamer().EmitBytes(Bytes);
|
2011-12-15 05:47:48 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-06 18:33:31 +08:00
|
|
|
void AsmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer) {
|
|
|
|
CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc);
|
2014-07-06 22:17:29 +08:00
|
|
|
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(),
|
|
|
|
Loc.getPointer());
|
2010-07-19 02:54:11 +08:00
|
|
|
}
|
|
|
|
|
2010-01-20 04:22:31 +08:00
|
|
|
const AsmToken &AsmParser::Lex() {
|
2016-06-03 01:15:05 +08:00
|
|
|
if (Lexer.getTok().is(AsmToken::Error))
|
|
|
|
Error(Lexer.getErrLoc(), Lexer.getErr());
|
|
|
|
|
2016-07-11 20:42:14 +08:00
|
|
|
// if it's a end of statement with a comment in it
|
|
|
|
if (getTok().is(AsmToken::EndOfStatement)) {
|
|
|
|
// if this is a line comment output it.
|
|
|
|
if (getTok().getString().front() != '\n' &&
|
|
|
|
getTok().getString().front() != '\r' && MAI.preserveAsmComments())
|
|
|
|
Out.addExplicitComment(Twine(getTok().getString()));
|
|
|
|
}
|
|
|
|
|
2010-01-21 08:19:58 +08:00
|
|
|
const AsmToken *tok = &Lexer.Lex();
|
2016-07-11 20:42:14 +08:00
|
|
|
|
|
|
|
// Parse comments here to be deferred until end of next statement.
|
2016-06-18 00:06:17 +08:00
|
|
|
while (tok->is(AsmToken::Comment)) {
|
2016-07-11 20:42:14 +08:00
|
|
|
if (MAI.preserveAsmComments())
|
|
|
|
Out.addExplicitComment(Twine(tok->getString()));
|
2016-06-18 00:06:17 +08:00
|
|
|
tok = &Lexer.Lex();
|
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-01-21 08:19:58 +08:00
|
|
|
if (tok->is(AsmToken::Eof)) {
|
|
|
|
// If this is the end of an included file, pop the parent file off the
|
|
|
|
// include stack.
|
|
|
|
SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
|
|
|
|
if (ParentIncludeLoc != SMLoc()) {
|
2013-09-21 07:08:21 +08:00
|
|
|
jumpToLoc(ParentIncludeLoc);
|
2016-06-18 00:06:17 +08:00
|
|
|
return Lex();
|
2010-01-21 08:19:58 +08:00
|
|
|
}
|
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-01-21 08:19:58 +08:00
|
|
|
return *tok;
|
2010-01-20 04:22:31 +08:00
|
|
|
}
|
|
|
|
|
2010-04-06 07:15:42 +08:00
|
|
|
bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) {
|
2010-03-13 10:20:57 +08:00
|
|
|
// Create the initial section, if requested.
|
|
|
|
if (!NoInitialTextSection)
|
2014-10-16 00:12:52 +08:00
|
|
|
Out.InitSections(false);
|
2009-08-27 06:49:51 +08:00
|
|
|
|
2009-06-22 04:54:55 +08:00
|
|
|
// Prime the lexer.
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex();
|
2010-09-10 06:42:56 +08:00
|
|
|
|
|
|
|
HadError = false;
|
2009-08-08 06:46:00 +08:00
|
|
|
AsmCond StartingCondState = TheCondState;
|
|
|
|
|
2011-11-02 06:27:22 +08:00
|
|
|
// If we are generating dwarf for assembly source files save the initial text
|
|
|
|
// section and generate a .file directive.
|
|
|
|
if (getContext().getGenDwarfForAssembly()) {
|
2016-10-14 13:47:37 +08:00
|
|
|
MCSection *Sec = getStreamer().getCurrentSectionOnly();
|
2015-05-28 04:52:32 +08:00
|
|
|
if (!Sec->getBeginSymbol()) {
|
|
|
|
MCSymbol *SectionStartSym = getContext().createTempSymbol();
|
|
|
|
getStreamer().EmitLabel(SectionStartSym);
|
|
|
|
Sec->setBeginSymbol(SectionStartSym);
|
|
|
|
}
|
2015-05-22 00:52:32 +08:00
|
|
|
bool InsertResult = getContext().addGenDwarfSection(Sec);
|
|
|
|
assert(InsertResult && ".text section should not have debug info yet");
|
2015-05-22 01:09:22 +08:00
|
|
|
(void)InsertResult;
|
2014-03-17 09:52:11 +08:00
|
|
|
getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective(
|
|
|
|
0, StringRef(), getContext().getMainFileName()));
|
2011-11-02 06:27:22 +08:00
|
|
|
}
|
|
|
|
|
2009-07-03 05:53:43 +08:00
|
|
|
// While we have input, parse each statement.
|
2009-07-29 00:08:33 +08:00
|
|
|
while (Lexer.isNot(AsmToken::Eof)) {
|
2012-10-23 07:58:19 +08:00
|
|
|
ParseStatementInfo Info;
|
2014-09-22 10:21:35 +08:00
|
|
|
if (!parseStatement(Info, nullptr))
|
2013-09-21 07:08:21 +08:00
|
|
|
continue;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
// If we have a Lexer Error we are on an Error Token. Load in Lexer Error
|
|
|
|
// for printing ErrMsg via Lex() only if no (presumably better) parser error
|
|
|
|
// exists.
|
|
|
|
if (!hasPendingError() && Lexer.getTok().is(AsmToken::Error)) {
|
2016-06-03 01:15:05 +08:00
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
// parseStatement returned true so may need to emit an error.
|
|
|
|
printPendingErrors();
|
|
|
|
|
|
|
|
// Skipping to the next line if needed.
|
|
|
|
if (!getLexer().isAtStartOfStatement())
|
|
|
|
eatToEndOfStatement();
|
2009-07-03 05:53:43 +08:00
|
|
|
}
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
// All errors should have been emitted.
|
|
|
|
assert(!hasPendingError() && "unexpected error from parseStatement");
|
|
|
|
|
[ARM] Implement -mimplicit-it assembler option
This option, compatible with gas's -mimplicit-it, controls the
generation/checking of implicit IT blocks in ARM/Thumb assembly.
This option allows two behaviours that were not possible before:
- When in ARM mode, emit a warning when assembling a conditional
instruction that is not in an IT block. This is enabled with
-mimplicit-it=never and -mimplicit-it=thumb.
- When in Thumb mode, automatically generate IT instructions when an
instruction with a condition code appears outside of an IT block. This
is enabled with -mimplicit-it=thumb and -mimplicit-it=always.
The default option is -mimplicit-it=arm, which matches the existing
behaviour (allow conditional ARM instructions outside IT blocks without
warning, and error if a conditional Thumb instruction is outside an IT
block).
The general strategy for generating IT blocks in Thumb mode is to keep a
small list of instructions which should be in the IT block, and only
emit them when we encounter something in the input which means we cannot
continue the block. This could be caused by:
- A non-predicable instruction
- An instruction with a condition not compatible with the IT block
- The IT block already contains 4 instructions
- A branch-like instruction (including ALU instructions with the PC as
the destination), which cannot appear in the middle of an IT block
- A label (branching into an IT block is not legal)
- A change of section, architecture, ISA, etc
- The end of the assembly file.
Some of these, such as change of section and end of file, are parsed
outside of the ARM asm parser, so I've added a new virtual function to
AsmParser to ensure any previously-parsed instructions have been
emitted. The ARM implementation of this flushes the currently pending IT
block.
We now have to try instruction matching up to 3 times, because we cannot
know if the current IT block is valid before matching, and instruction
matching changes depending on the IT block state (due to the 16-bit ALU
instructions, which set the flags iff not in an IT block). In the common
case of not having an open implicit IT block and the instruction being
matched not needing one, we still only have to run the matcher once.
I've removed the ITState.FirstCond variable, because it does not store
any information that isn't already represented by CurPosition. I've also
updated the comment on CurPosition to accurately describe it's meaning
(which this patch doesn't change).
Differential Revision: https://reviews.llvm.org/D22760
llvm-svn: 276747
2016-07-26 22:19:47 +08:00
|
|
|
getTargetParser().flushPendingInstructions(getStreamer());
|
|
|
|
|
2009-08-08 06:46:00 +08:00
|
|
|
if (TheCondState.TheCond != StartingCondState.TheCond ||
|
|
|
|
TheCondState.Ignore != StartingCondState.Ignore)
|
2016-09-17 02:30:20 +08:00
|
|
|
printError(getTok().getLoc(), "unmatched .ifs or .elses");
|
2010-07-29 04:55:35 +08:00
|
|
|
// Check to see there are no empty DwarfFile slots.
|
2014-04-01 15:35:52 +08:00
|
|
|
const auto &LineTables = getContext().getMCDwarfLineTables();
|
|
|
|
if (!LineTables.empty()) {
|
|
|
|
unsigned Index = 0;
|
|
|
|
for (const auto &File : LineTables.begin()->second.getMCDwarfFiles()) {
|
|
|
|
if (File.Name.empty() && Index != 0)
|
2016-09-17 02:30:20 +08:00
|
|
|
printError(getTok().getLoc(), "unassigned file number: " +
|
|
|
|
Twine(Index) +
|
|
|
|
" for .file directives");
|
2014-04-01 15:35:52 +08:00
|
|
|
++Index;
|
|
|
|
}
|
2010-07-29 04:55:35 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2011-06-16 02:33:28 +08:00
|
|
|
// Check to see that all assembler local symbols were actually defined.
|
|
|
|
// Targets that don't do subsections via symbols may not want this, though,
|
|
|
|
// so conservatively exclude them. Only do this if we're finalizing, though,
|
|
|
|
// as otherwise we won't necessarilly have seen everything yet.
|
2016-04-12 03:50:46 +08:00
|
|
|
if (!NoFinalize) {
|
|
|
|
if (MAI.hasSubsectionsViaSymbols()) {
|
|
|
|
for (const auto &TableEntry : getContext().getSymbols()) {
|
|
|
|
MCSymbol *Sym = TableEntry.getValue();
|
|
|
|
// Variable symbols may not be marked as defined, so check those
|
|
|
|
// explicitly. If we know it's a variable, we have a definition for
|
|
|
|
// the purposes of this check.
|
|
|
|
if (Sym->isTemporary() && !Sym->isVariable() && !Sym->isDefined())
|
|
|
|
// FIXME: We would really like to refer back to where the symbol was
|
|
|
|
// first referenced for a source location. We need to add something
|
|
|
|
// to track that. Currently, we just point to the end of the file.
|
2016-09-17 02:30:20 +08:00
|
|
|
printError(getTok().getLoc(), "assembler local symbol '" +
|
|
|
|
Sym->getName() + "' not defined");
|
2016-04-12 03:50:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Temporary symbols like the ones for directional jumps don't go in the
|
|
|
|
// symbol table. They also need to be diagnosed in all (final) cases.
|
2016-04-14 03:46:54 +08:00
|
|
|
for (std::tuple<SMLoc, CppHashInfoTy, MCSymbol *> &LocSym : DirLabels) {
|
|
|
|
if (std::get<2>(LocSym)->isUndefined()) {
|
|
|
|
// Reset the state of any "# line file" directives we've seen to the
|
|
|
|
// context as it was at the diagnostic site.
|
|
|
|
CppHashInfo = std::get<1>(LocSym);
|
2016-09-17 02:30:20 +08:00
|
|
|
printError(std::get<0>(LocSym), "directional label undefined");
|
2016-04-14 03:46:54 +08:00
|
|
|
}
|
2011-06-16 02:33:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-06 07:15:42 +08:00
|
|
|
// Finalize the output stream if there are no errors and if the client wants
|
|
|
|
// us to.
|
2013-10-05 06:52:31 +08:00
|
|
|
if (!HadError && !NoFinalize)
|
2009-08-21 16:34:18 +08:00
|
|
|
Out.Finish();
|
|
|
|
|
2015-11-17 17:58:07 +08:00
|
|
|
return HadError || getContext().hadError();
|
2009-06-22 04:54:55 +08:00
|
|
|
}
|
|
|
|
|
2016-10-10 23:24:54 +08:00
|
|
|
bool AsmParser::checkForValidSection() {
|
2016-10-14 13:47:37 +08:00
|
|
|
if (!ParsingInlineAsm && !getStreamer().getCurrentSectionOnly()) {
|
2014-10-16 00:12:52 +08:00
|
|
|
Out.InitSections(false);
|
2016-10-10 23:24:54 +08:00
|
|
|
return Error(getTok().getLoc(),
|
|
|
|
"expected section directive before assembly directive");
|
2010-09-10 06:42:59 +08:00
|
|
|
}
|
2016-10-10 23:24:54 +08:00
|
|
|
return false;
|
2010-09-10 06:42:59 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Throw away the rest of the line for testing purposes.
|
2013-02-21 06:21:35 +08:00
|
|
|
void AsmParser::eatToEndOfStatement() {
|
2013-09-21 07:08:21 +08:00
|
|
|
while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))
|
2016-06-03 01:15:05 +08:00
|
|
|
Lexer.Lex();
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2009-06-22 09:29:09 +08:00
|
|
|
// Eat EOL.
|
2009-07-29 00:08:33 +08:00
|
|
|
if (Lexer.is(AsmToken::EndOfStatement))
|
2016-06-03 01:15:05 +08:00
|
|
|
Lexer.Lex();
|
2009-06-22 09:29:09 +08:00
|
|
|
}
|
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
StringRef AsmParser::parseStringToEndOfStatement() {
|
2010-07-19 04:15:59 +08:00
|
|
|
const char *Start = getTok().getLoc().getPointer();
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))
|
2016-06-18 00:06:17 +08:00
|
|
|
Lexer.Lex();
|
2010-07-19 04:15:59 +08:00
|
|
|
|
|
|
|
const char *End = getTok().getLoc().getPointer();
|
|
|
|
return StringRef(Start, End - Start);
|
|
|
|
}
|
2009-06-22 13:51:26 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
StringRef AsmParser::parseStringToComma() {
|
2012-05-12 19:18:51 +08:00
|
|
|
const char *Start = getTok().getLoc().getPointer();
|
|
|
|
|
|
|
|
while (Lexer.isNot(AsmToken::EndOfStatement) &&
|
2013-09-21 07:08:21 +08:00
|
|
|
Lexer.isNot(AsmToken::Comma) && Lexer.isNot(AsmToken::Eof))
|
2016-06-18 00:06:17 +08:00
|
|
|
Lexer.Lex();
|
2012-05-12 19:18:51 +08:00
|
|
|
|
|
|
|
const char *End = getTok().getLoc().getPointer();
|
|
|
|
return StringRef(Start, End - Start);
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Parse a paren expression and return it.
|
2009-06-22 14:32:03 +08:00
|
|
|
/// NOTE: This assumes the leading '(' has already been consumed.
|
|
|
|
///
|
|
|
|
/// parenexpr ::= expr)
|
|
|
|
///
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) {
|
|
|
|
if (parseExpression(Res))
|
|
|
|
return true;
|
2009-07-29 00:08:33 +08:00
|
|
|
if (Lexer.isNot(AsmToken::RParen))
|
2009-06-22 14:32:03 +08:00
|
|
|
return TokError("expected ')' in parentheses expression");
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Lexer.getTok().getEndLoc();
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex();
|
2009-06-22 14:32:03 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-06-22 04:54:55 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Parse a bracket expression and return it.
|
2011-02-25 05:59:22 +08:00
|
|
|
/// NOTE: This assumes the leading '[' has already been consumed.
|
|
|
|
///
|
|
|
|
/// bracketexpr ::= expr]
|
|
|
|
///
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) {
|
|
|
|
if (parseExpression(Res))
|
|
|
|
return true;
|
2016-07-18 23:24:03 +08:00
|
|
|
EndLoc = getTok().getEndLoc();
|
|
|
|
if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression"))
|
|
|
|
return true;
|
2011-02-25 05:59:22 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Parse a primary expression and return it.
|
2009-06-22 14:32:03 +08:00
|
|
|
/// primaryexpr ::= (parenexpr
|
|
|
|
/// primaryexpr ::= symbol
|
|
|
|
/// primaryexpr ::= number
|
2010-04-14 12:40:28 +08:00
|
|
|
/// primaryexpr ::= '.'
|
2009-06-22 14:32:03 +08:00
|
|
|
/// primaryexpr ::= ~,+,- primaryexpr
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
|
2013-01-23 05:09:20 +08:00
|
|
|
SMLoc FirstTokenLoc = getLexer().getLoc();
|
|
|
|
AsmToken::TokenKind FirstTokenKind = Lexer.getKind();
|
|
|
|
switch (FirstTokenKind) {
|
2009-06-22 13:51:26 +08:00
|
|
|
default:
|
|
|
|
return TokError("unknown token in expression");
|
2011-04-12 08:03:13 +08:00
|
|
|
// If we have an error assume that we've already handled it.
|
|
|
|
case AsmToken::Error:
|
|
|
|
return true;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Exclaim:
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex(); // Eat the operator.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parsePrimaryExpr(Res, EndLoc))
|
2009-06-30 04:37:27 +08:00
|
|
|
return true;
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCUnaryExpr::createLNot(Res, getContext());
|
2009-06-30 04:37:27 +08:00
|
|
|
return false;
|
2010-08-25 03:13:42 +08:00
|
|
|
case AsmToken::Dollar:
|
2013-10-19 04:46:28 +08:00
|
|
|
case AsmToken::At:
|
2009-08-01 05:55:09 +08:00
|
|
|
case AsmToken::String:
|
2009-10-16 09:34:54 +08:00
|
|
|
case AsmToken::Identifier: {
|
2010-08-25 03:13:42 +08:00
|
|
|
StringRef Identifier;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseIdentifier(Identifier)) {
|
2016-10-12 21:58:07 +08:00
|
|
|
// We may have failed but $ may be a valid token.
|
|
|
|
if (getTok().is(AsmToken::Dollar)) {
|
2013-09-25 18:47:21 +08:00
|
|
|
if (Lexer.getMAI().getDollarIsPC()) {
|
2016-10-12 21:58:07 +08:00
|
|
|
Lex();
|
2013-09-25 18:47:21 +08:00
|
|
|
// This is a '$' reference, which references the current PC. Emit a
|
|
|
|
// temporary label to the streamer and refer to it.
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = Ctx.createTempSymbol();
|
2013-09-25 18:47:21 +08:00
|
|
|
Out.EmitLabel(Sym);
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
|
2013-10-05 05:26:15 +08:00
|
|
|
getContext());
|
2013-09-25 18:47:21 +08:00
|
|
|
EndLoc = FirstTokenLoc;
|
|
|
|
return false;
|
2014-03-07 06:13:17 +08:00
|
|
|
}
|
|
|
|
return Error(FirstTokenLoc, "invalid token in expression");
|
2013-09-25 18:47:21 +08:00
|
|
|
}
|
2013-01-23 05:09:20 +08:00
|
|
|
}
|
2013-12-05 06:43:20 +08:00
|
|
|
// Parse symbol variant
|
|
|
|
std::pair<StringRef, StringRef> Split;
|
|
|
|
if (!MAI.useParensForSymbolVariant()) {
|
2014-06-19 09:25:43 +08:00
|
|
|
if (FirstTokenKind == AsmToken::String) {
|
|
|
|
if (Lexer.is(AsmToken::At)) {
|
2016-06-18 00:06:17 +08:00
|
|
|
Lex(); // eat @
|
2014-06-19 09:25:43 +08:00
|
|
|
SMLoc AtLoc = getLexer().getLoc();
|
|
|
|
StringRef VName;
|
|
|
|
if (parseIdentifier(VName))
|
|
|
|
return Error(AtLoc, "expected symbol variant after '@'");
|
|
|
|
|
|
|
|
Split = std::make_pair(Identifier, VName);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Split = Identifier.split('@');
|
|
|
|
}
|
2013-12-05 06:43:20 +08:00
|
|
|
} else if (Lexer.is(AsmToken::LParen)) {
|
2016-06-18 00:06:17 +08:00
|
|
|
Lex(); // eat '('.
|
2013-12-05 06:43:20 +08:00
|
|
|
StringRef VName;
|
|
|
|
parseIdentifier(VName);
|
2016-07-18 23:24:03 +08:00
|
|
|
// eat ')'.
|
|
|
|
if (parseToken(AsmToken::RParen,
|
|
|
|
"unexpected token in variant, expected ')'"))
|
|
|
|
return true;
|
2013-12-05 06:43:20 +08:00
|
|
|
Split = std::make_pair(Identifier, VName);
|
|
|
|
}
|
2010-08-25 03:13:42 +08:00
|
|
|
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = SMLoc::getFromPointer(Identifier.end());
|
|
|
|
|
2009-10-16 09:34:54 +08:00
|
|
|
// This is a symbol reference.
|
2013-10-19 04:46:28 +08:00
|
|
|
StringRef SymbolName = Identifier;
|
2016-12-02 02:00:36 +08:00
|
|
|
if (SymbolName.empty())
|
|
|
|
return true;
|
|
|
|
|
2013-10-19 04:46:28 +08:00
|
|
|
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
|
2013-10-16 16:22:49 +08:00
|
|
|
|
2013-10-18 10:14:40 +08:00
|
|
|
// Lookup the symbol variant if used.
|
2013-12-05 06:43:20 +08:00
|
|
|
if (Split.second.size()) {
|
2013-10-18 10:14:40 +08:00
|
|
|
Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);
|
2013-10-19 04:46:28 +08:00
|
|
|
if (Variant != MCSymbolRefExpr::VK_Invalid) {
|
|
|
|
SymbolName = Split.first;
|
2013-12-05 06:43:20 +08:00
|
|
|
} else if (MAI.doesAllowAtInName() && !MAI.useParensForSymbolVariant()) {
|
2013-10-19 04:46:28 +08:00
|
|
|
Variant = MCSymbolRefExpr::VK_None;
|
|
|
|
} else {
|
2014-01-27 06:29:43 +08:00
|
|
|
return Error(SMLoc::getFromPointer(Split.second.begin()),
|
|
|
|
"invalid variant '" + Split.second + "'");
|
2010-09-17 10:47:07 +08:00
|
|
|
}
|
|
|
|
}
|
2010-03-16 07:51:06 +08:00
|
|
|
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
|
2013-10-19 04:46:28 +08:00
|
|
|
|
2009-10-16 09:34:54 +08:00
|
|
|
// If this is an absolute variable reference, substitute it now to preserve
|
|
|
|
// semantics in the face of reassignment.
|
2015-09-01 01:44:53 +08:00
|
|
|
if (Sym->isVariable() &&
|
|
|
|
isa<MCConstantExpr>(Sym->getVariableValue(/*SetUsed*/ false))) {
|
2010-03-16 07:51:06 +08:00
|
|
|
if (Variant)
|
2010-11-09 01:53:02 +08:00
|
|
|
return Error(EndLoc, "unexpected modifier on variable reference");
|
2010-03-16 07:51:06 +08:00
|
|
|
|
2015-09-01 01:44:53 +08:00
|
|
|
Res = Sym->getVariableValue(/*SetUsed*/ false);
|
2009-10-16 09:34:54 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise create a symbol ref.
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCSymbolRefExpr::create(Sym, Variant, getContext());
|
2009-06-22 13:51:26 +08:00
|
|
|
return false;
|
2009-10-16 09:34:54 +08:00
|
|
|
}
|
2014-02-02 00:20:54 +08:00
|
|
|
case AsmToken::BigNum:
|
|
|
|
return TokError("literal value out of range for directive");
|
2010-05-18 07:08:19 +08:00
|
|
|
case AsmToken::Integer: {
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
|
|
|
int64_t IntVal = getTok().getIntVal();
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCConstantExpr::create(IntVal, getContext());
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Lexer.getTok().getEndLoc();
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex(); // Eat token.
|
2010-05-18 07:08:19 +08:00
|
|
|
// Look for 'b' or 'f' following an Integer as a directional label
|
|
|
|
if (Lexer.getKind() == AsmToken::Identifier) {
|
|
|
|
StringRef IDVal = getTok().getString();
|
2013-06-21 00:24:17 +08:00
|
|
|
// Lookup 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);
|
2014-03-22 05:54:46 +08:00
|
|
|
if (Variant == MCSymbolRefExpr::VK_Invalid)
|
2013-06-21 00:24:17 +08:00
|
|
|
return TokError("invalid variant '" + Split.second + "'");
|
2013-08-20 21:33:18 +08:00
|
|
|
IDVal = Split.first;
|
2013-06-21 00:24:17 +08:00
|
|
|
}
|
2013-09-21 07:08:21 +08:00
|
|
|
if (IDVal == "f" || IDVal == "b") {
|
|
|
|
MCSymbol *Sym =
|
2015-05-19 02:43:14 +08:00
|
|
|
Ctx.getDirectionalLocalSymbol(IntVal, IDVal == "b");
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCSymbolRefExpr::create(Sym, Variant, getContext());
|
2012-05-13 00:52:21 +08:00
|
|
|
if (IDVal == "b" && Sym->isUndefined())
|
2016-04-12 03:50:46 +08:00
|
|
|
return Error(Loc, "directional label undefined");
|
2016-04-14 03:46:54 +08:00
|
|
|
DirLabels.push_back(std::make_tuple(Loc, CppHashInfo, Sym));
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Lexer.getTok().getEndLoc();
|
2010-05-18 07:08:19 +08:00
|
|
|
Lex(); // Eat identifier.
|
|
|
|
}
|
|
|
|
}
|
2009-06-22 13:51:26 +08:00
|
|
|
return false;
|
2010-05-18 07:08:19 +08:00
|
|
|
}
|
2011-01-26 05:26:41 +08:00
|
|
|
case AsmToken::Real: {
|
|
|
|
APFloat RealVal(APFloat::IEEEdouble, getTok().getString());
|
2011-02-04 07:17:47 +08:00
|
|
|
uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCConstantExpr::create(IntVal, getContext());
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Lexer.getTok().getEndLoc();
|
2011-01-26 05:26:41 +08:00
|
|
|
Lex(); // Eat token.
|
|
|
|
return false;
|
|
|
|
}
|
2010-04-14 12:40:28 +08:00
|
|
|
case AsmToken::Dot: {
|
|
|
|
// This is a '.' reference, which references the current PC. Emit a
|
|
|
|
// temporary label to the streamer and refer to it.
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = Ctx.createTempSymbol();
|
2010-04-14 12:40:28 +08:00
|
|
|
Out.EmitLabel(Sym);
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
|
2013-01-08 03:00:49 +08:00
|
|
|
EndLoc = Lexer.getTok().getEndLoc();
|
2010-04-14 12:40:28 +08:00
|
|
|
Lex(); // Eat identifier.
|
|
|
|
return false;
|
|
|
|
}
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::LParen:
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex(); // Eat the '('.
|
2013-09-21 07:08:21 +08:00
|
|
|
return parseParenExpr(Res, EndLoc);
|
2011-02-25 05:59:22 +08:00
|
|
|
case AsmToken::LBrac:
|
|
|
|
if (!PlatformParser->HasBracketExpressions())
|
|
|
|
return TokError("brackets expression not supported on this target");
|
|
|
|
Lex(); // Eat the '['.
|
2013-09-21 07:08:21 +08:00
|
|
|
return parseBracketExpr(Res, EndLoc);
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Minus:
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex(); // Eat the operator.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parsePrimaryExpr(Res, EndLoc))
|
2009-06-30 04:37:27 +08:00
|
|
|
return true;
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCUnaryExpr::createMinus(Res, getContext());
|
2009-06-30 04:37:27 +08:00
|
|
|
return false;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Plus:
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex(); // Eat the operator.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parsePrimaryExpr(Res, EndLoc))
|
2009-06-30 04:37:27 +08:00
|
|
|
return true;
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCUnaryExpr::createPlus(Res, getContext());
|
2009-06-30 04:37:27 +08:00
|
|
|
return false;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Tilde:
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex(); // Eat the operator.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parsePrimaryExpr(Res, EndLoc))
|
2009-06-30 04:37:27 +08:00
|
|
|
return true;
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCUnaryExpr::createNot(Res, getContext());
|
2009-06-30 04:37:27 +08:00
|
|
|
return false;
|
2016-08-08 19:50:25 +08:00
|
|
|
// MIPS unary expression operators. The lexer won't generate these tokens if
|
|
|
|
// MCAsmInfo::HasMipsExpressions is false for the target.
|
|
|
|
case AsmToken::PercentCall16:
|
|
|
|
case AsmToken::PercentCall_Hi:
|
|
|
|
case AsmToken::PercentCall_Lo:
|
|
|
|
case AsmToken::PercentDtprel_Hi:
|
|
|
|
case AsmToken::PercentDtprel_Lo:
|
|
|
|
case AsmToken::PercentGot:
|
|
|
|
case AsmToken::PercentGot_Disp:
|
|
|
|
case AsmToken::PercentGot_Hi:
|
|
|
|
case AsmToken::PercentGot_Lo:
|
|
|
|
case AsmToken::PercentGot_Ofst:
|
|
|
|
case AsmToken::PercentGot_Page:
|
|
|
|
case AsmToken::PercentGottprel:
|
|
|
|
case AsmToken::PercentGp_Rel:
|
|
|
|
case AsmToken::PercentHi:
|
|
|
|
case AsmToken::PercentHigher:
|
|
|
|
case AsmToken::PercentHighest:
|
|
|
|
case AsmToken::PercentLo:
|
|
|
|
case AsmToken::PercentNeg:
|
|
|
|
case AsmToken::PercentPcrel_Hi:
|
|
|
|
case AsmToken::PercentPcrel_Lo:
|
|
|
|
case AsmToken::PercentTlsgd:
|
|
|
|
case AsmToken::PercentTlsldm:
|
|
|
|
case AsmToken::PercentTprel_Hi:
|
|
|
|
case AsmToken::PercentTprel_Lo:
|
|
|
|
Lex(); // Eat the operator.
|
|
|
|
if (Lexer.isNot(AsmToken::LParen))
|
|
|
|
return TokError("expected '(' after operator");
|
|
|
|
Lex(); // Eat the operator.
|
|
|
|
if (parseExpression(Res, EndLoc))
|
|
|
|
return true;
|
|
|
|
if (Lexer.isNot(AsmToken::RParen))
|
|
|
|
return TokError("expected ')'");
|
|
|
|
Lex(); // Eat the operator.
|
|
|
|
Res = getTargetParser().createTargetUnaryExpr(Res, FirstTokenKind, Ctx);
|
|
|
|
return !Res;
|
2009-06-22 13:51:26 +08:00
|
|
|
}
|
|
|
|
}
|
2009-06-22 14:32:03 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
bool AsmParser::parseExpression(const MCExpr *&Res) {
|
2010-01-16 03:39:23 +08:00
|
|
|
SMLoc EndLoc;
|
2013-02-21 06:21:35 +08:00
|
|
|
return parseExpression(Res, EndLoc);
|
2010-01-16 03:28:38 +08:00
|
|
|
}
|
|
|
|
|
2010-09-17 10:47:07 +08:00
|
|
|
const MCExpr *
|
2013-09-21 07:08:21 +08:00
|
|
|
AsmParser::applyModifierToExpr(const MCExpr *E,
|
2010-09-17 10:47:07 +08:00
|
|
|
MCSymbolRefExpr::VariantKind Variant) {
|
2013-08-28 04:23:19 +08:00
|
|
|
// Ask the target implementation about this expression first.
|
|
|
|
const MCExpr *NewE = getTargetParser().applyModifierToExpr(E, Variant, Ctx);
|
|
|
|
if (NewE)
|
|
|
|
return NewE;
|
2010-09-17 10:47:07 +08:00
|
|
|
// Recurse over the given expression, rebuilding it to apply the given variant
|
|
|
|
// if there is exactly one symbol.
|
|
|
|
switch (E->getKind()) {
|
|
|
|
case MCExpr::Target:
|
|
|
|
case MCExpr::Constant:
|
2014-04-24 14:44:33 +08:00
|
|
|
return nullptr;
|
2010-09-17 10:47:07 +08:00
|
|
|
|
|
|
|
case MCExpr::SymbolRef: {
|
|
|
|
const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E);
|
|
|
|
|
|
|
|
if (SRE->getKind() != MCSymbolRefExpr::VK_None) {
|
2013-09-21 07:08:21 +08:00
|
|
|
TokError("invalid variant on expression '" + getTok().getIdentifier() +
|
|
|
|
"' (already modified)");
|
2010-09-17 10:47:07 +08:00
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
return MCSymbolRefExpr::create(&SRE->getSymbol(), Variant, getContext());
|
2010-09-17 10:47:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case MCExpr::Unary: {
|
|
|
|
const MCUnaryExpr *UE = cast<MCUnaryExpr>(E);
|
2013-09-21 07:08:21 +08:00
|
|
|
const MCExpr *Sub = applyModifierToExpr(UE->getSubExpr(), Variant);
|
2010-09-17 10:47:07 +08:00
|
|
|
if (!Sub)
|
2014-04-24 14:44:33 +08:00
|
|
|
return nullptr;
|
2015-05-30 09:25:56 +08:00
|
|
|
return MCUnaryExpr::create(UE->getOpcode(), Sub, getContext());
|
2010-09-17 10:47:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case MCExpr::Binary: {
|
|
|
|
const MCBinaryExpr *BE = cast<MCBinaryExpr>(E);
|
2013-09-21 07:08:21 +08:00
|
|
|
const MCExpr *LHS = applyModifierToExpr(BE->getLHS(), Variant);
|
|
|
|
const MCExpr *RHS = applyModifierToExpr(BE->getRHS(), Variant);
|
2010-09-17 10:47:07 +08:00
|
|
|
|
|
|
|
if (!LHS && !RHS)
|
2014-04-24 14:44:33 +08:00
|
|
|
return nullptr;
|
2010-09-17 10:47:07 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (!LHS)
|
|
|
|
LHS = BE->getLHS();
|
|
|
|
if (!RHS)
|
|
|
|
RHS = BE->getRHS();
|
2010-09-17 10:47:07 +08:00
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, getContext());
|
2010-09-17 10:47:07 +08:00
|
|
|
}
|
|
|
|
}
|
2010-09-18 00:34:24 +08:00
|
|
|
|
2012-02-07 13:05:23 +08:00
|
|
|
llvm_unreachable("Invalid expression kind!");
|
2010-09-17 10:47:07 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Parse an expression and return it.
|
2010-10-09 19:00:50 +08:00
|
|
|
///
|
2011-08-21 00:24:13 +08:00
|
|
|
/// expr ::= expr &&,|| expr -> lowest.
|
|
|
|
/// expr ::= expr |,^,&,! expr
|
|
|
|
/// expr ::= expr ==,!=,<>,<,<=,>,>= expr
|
|
|
|
/// expr ::= expr <<,>> expr
|
|
|
|
/// expr ::= expr +,- expr
|
|
|
|
/// expr ::= expr *,/,% expr -> highest.
|
2009-06-22 14:32:03 +08:00
|
|
|
/// expr ::= primaryexpr
|
|
|
|
///
|
2013-02-21 06:21:35 +08:00
|
|
|
bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {
|
2010-02-13 09:28:07 +08:00
|
|
|
// Parse the expression.
|
2014-04-24 14:44:33 +08:00
|
|
|
Res = nullptr;
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parsePrimaryExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc))
|
2010-02-13 09:28:07 +08:00
|
|
|
return true;
|
|
|
|
|
2010-09-17 10:47:07 +08:00
|
|
|
// As a special case, we support 'a op b @ modifier' by rewriting the
|
|
|
|
// expression to include the modifier. This is inefficient, but in general we
|
|
|
|
// expect users to use 'a@modifier op b'.
|
|
|
|
if (Lexer.getKind() == AsmToken::At) {
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
if (Lexer.isNot(AsmToken::Identifier))
|
|
|
|
return TokError("unexpected symbol modifier following '@'");
|
|
|
|
|
|
|
|
MCSymbolRefExpr::VariantKind Variant =
|
2013-09-21 07:08:21 +08:00
|
|
|
MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier());
|
2010-09-17 10:47:07 +08:00
|
|
|
if (Variant == MCSymbolRefExpr::VK_Invalid)
|
|
|
|
return TokError("invalid variant '" + getTok().getIdentifier() + "'");
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
const MCExpr *ModifiedRes = applyModifierToExpr(Res, Variant);
|
2010-09-17 10:47:07 +08:00
|
|
|
if (!ModifiedRes) {
|
|
|
|
return TokError("invalid modifier '" + getTok().getIdentifier() +
|
|
|
|
"' (no symbols present)");
|
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-09-17 10:47:07 +08:00
|
|
|
Res = ModifiedRes;
|
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
2010-02-13 09:28:07 +08:00
|
|
|
// Try to constant fold it up front, if possible.
|
|
|
|
int64_t Value;
|
2015-05-30 09:25:56 +08:00
|
|
|
if (Res->evaluateAsAbsolute(Value))
|
|
|
|
Res = MCConstantExpr::create(Value, getContext());
|
2010-02-13 09:28:07 +08:00
|
|
|
|
|
|
|
return false;
|
2009-06-22 14:32:03 +08:00
|
|
|
}
|
2009-06-23 13:57:07 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
bool AsmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) {
|
2014-04-24 14:44:33 +08:00
|
|
|
Res = nullptr;
|
2013-09-21 07:08:21 +08:00
|
|
|
return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc);
|
2009-08-31 16:08:17 +08:00
|
|
|
}
|
|
|
|
|
2015-06-25 17:52:02 +08:00
|
|
|
bool AsmParser::parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res,
|
|
|
|
SMLoc &EndLoc) {
|
|
|
|
if (parseParenExpr(Res, EndLoc))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for (; ParenDepth > 0; --ParenDepth) {
|
|
|
|
if (parseBinOpRHS(1, Res, EndLoc))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// We don't Lex() the last RParen.
|
|
|
|
// This is the same behavior as parseParenExpression().
|
|
|
|
if (ParenDepth - 1 > 0) {
|
2016-07-18 23:24:03 +08:00
|
|
|
EndLoc = getTok().getEndLoc();
|
|
|
|
if (parseToken(AsmToken::RParen,
|
|
|
|
"expected ')' in parentheses expression"))
|
|
|
|
return true;
|
2015-06-25 17:52:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
bool AsmParser::parseAbsoluteExpression(int64_t &Res) {
|
2009-08-31 16:07:22 +08:00
|
|
|
const MCExpr *Expr;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2009-06-30 10:10:03 +08:00
|
|
|
SMLoc StartLoc = Lexer.getLoc();
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseExpression(Expr))
|
2009-06-30 04:37:27 +08:00
|
|
|
return true;
|
|
|
|
|
2015-05-30 09:25:56 +08:00
|
|
|
if (!Expr->evaluateAsAbsolute(Res))
|
2009-06-30 10:10:03 +08:00
|
|
|
return Error(StartLoc, "expected absolute expression");
|
2009-06-30 04:37:27 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-26 11:15:34 +08:00
|
|
|
static unsigned getDarwinBinOpPrecedence(AsmToken::TokenKind K,
|
|
|
|
MCBinaryExpr::Opcode &Kind,
|
|
|
|
bool ShouldUseLogicalShr) {
|
2009-06-23 13:57:07 +08:00
|
|
|
switch (K) {
|
2009-08-31 16:07:44 +08:00
|
|
|
default:
|
2013-09-21 07:08:21 +08:00
|
|
|
return 0; // not a binop.
|
2009-06-30 04:37:27 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// Lowest Precedence: &&, ||
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::AmpAmp:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::LAnd;
|
2009-06-30 04:37:27 +08:00
|
|
|
return 1;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::PipePipe:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::LOr;
|
2009-06-30 04:37:27 +08:00
|
|
|
return 1;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// Low Precedence: |, &, ^
|
|
|
|
//
|
|
|
|
// FIXME: gas seems to support '!' as an infix operator?
|
2010-09-22 13:05:16 +08:00
|
|
|
case AsmToken::Pipe:
|
|
|
|
Kind = MCBinaryExpr::Or;
|
|
|
|
return 2;
|
|
|
|
case AsmToken::Caret:
|
|
|
|
Kind = MCBinaryExpr::Xor;
|
|
|
|
return 2;
|
|
|
|
case AsmToken::Amp:
|
|
|
|
Kind = MCBinaryExpr::And;
|
|
|
|
return 2;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// Low Intermediate Precedence: ==, !=, <>, <, <=, >, >=
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::EqualEqual:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::EQ;
|
2010-09-22 13:05:16 +08:00
|
|
|
return 3;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::ExclaimEqual:
|
|
|
|
case AsmToken::LessGreater:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::NE;
|
2010-09-22 13:05:16 +08:00
|
|
|
return 3;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Less:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::LT;
|
2010-09-22 13:05:16 +08:00
|
|
|
return 3;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::LessEqual:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::LTE;
|
2010-09-22 13:05:16 +08:00
|
|
|
return 3;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Greater:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::GT;
|
2010-09-22 13:05:16 +08:00
|
|
|
return 3;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::GreaterEqual:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::GTE;
|
2009-06-30 04:37:27 +08:00
|
|
|
return 3;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// Intermediate Precedence: <<, >>
|
2011-08-21 00:24:13 +08:00
|
|
|
case AsmToken::LessLess:
|
|
|
|
Kind = MCBinaryExpr::Shl;
|
|
|
|
return 4;
|
|
|
|
case AsmToken::GreaterGreater:
|
2015-10-26 11:15:34 +08:00
|
|
|
Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;
|
2011-08-21 00:24:13 +08:00
|
|
|
return 4;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// High Intermediate Precedence: +, -
|
2010-10-26 04:18:56 +08:00
|
|
|
case AsmToken::Plus:
|
|
|
|
Kind = MCBinaryExpr::Add;
|
2011-08-21 00:24:13 +08:00
|
|
|
return 5;
|
2010-10-26 04:18:56 +08:00
|
|
|
case AsmToken::Minus:
|
|
|
|
Kind = MCBinaryExpr::Sub;
|
2011-08-21 00:24:13 +08:00
|
|
|
return 5;
|
2010-10-26 04:18:56 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// Highest Precedence: *, /, %
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Star:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::Mul;
|
2011-08-21 00:24:13 +08:00
|
|
|
return 6;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Slash:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::Div;
|
2011-08-21 00:24:13 +08:00
|
|
|
return 6;
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Percent:
|
2009-08-31 16:06:59 +08:00
|
|
|
Kind = MCBinaryExpr::Mod;
|
2011-08-21 00:24:13 +08:00
|
|
|
return 6;
|
2009-06-23 13:57:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-26 11:15:34 +08:00
|
|
|
static unsigned getGNUBinOpPrecedence(AsmToken::TokenKind K,
|
|
|
|
MCBinaryExpr::Opcode &Kind,
|
|
|
|
bool ShouldUseLogicalShr) {
|
|
|
|
switch (K) {
|
|
|
|
default:
|
|
|
|
return 0; // not a binop.
|
|
|
|
|
|
|
|
// Lowest Precedence: &&, ||
|
|
|
|
case AsmToken::AmpAmp:
|
|
|
|
Kind = MCBinaryExpr::LAnd;
|
|
|
|
return 2;
|
|
|
|
case AsmToken::PipePipe:
|
|
|
|
Kind = MCBinaryExpr::LOr;
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
// Low Precedence: ==, !=, <>, <, <=, >, >=
|
|
|
|
case AsmToken::EqualEqual:
|
|
|
|
Kind = MCBinaryExpr::EQ;
|
|
|
|
return 3;
|
|
|
|
case AsmToken::ExclaimEqual:
|
|
|
|
case AsmToken::LessGreater:
|
|
|
|
Kind = MCBinaryExpr::NE;
|
|
|
|
return 3;
|
|
|
|
case AsmToken::Less:
|
|
|
|
Kind = MCBinaryExpr::LT;
|
|
|
|
return 3;
|
|
|
|
case AsmToken::LessEqual:
|
|
|
|
Kind = MCBinaryExpr::LTE;
|
|
|
|
return 3;
|
|
|
|
case AsmToken::Greater:
|
|
|
|
Kind = MCBinaryExpr::GT;
|
|
|
|
return 3;
|
|
|
|
case AsmToken::GreaterEqual:
|
|
|
|
Kind = MCBinaryExpr::GTE;
|
|
|
|
return 3;
|
|
|
|
|
|
|
|
// Low Intermediate Precedence: +, -
|
|
|
|
case AsmToken::Plus:
|
|
|
|
Kind = MCBinaryExpr::Add;
|
|
|
|
return 4;
|
|
|
|
case AsmToken::Minus:
|
|
|
|
Kind = MCBinaryExpr::Sub;
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
// High Intermediate Precedence: |, &, ^
|
|
|
|
//
|
|
|
|
// FIXME: gas seems to support '!' as an infix operator?
|
|
|
|
case AsmToken::Pipe:
|
|
|
|
Kind = MCBinaryExpr::Or;
|
|
|
|
return 5;
|
|
|
|
case AsmToken::Caret:
|
|
|
|
Kind = MCBinaryExpr::Xor;
|
|
|
|
return 5;
|
|
|
|
case AsmToken::Amp:
|
|
|
|
Kind = MCBinaryExpr::And;
|
|
|
|
return 5;
|
|
|
|
|
|
|
|
// Highest Precedence: *, /, %, <<, >>
|
|
|
|
case AsmToken::Star:
|
|
|
|
Kind = MCBinaryExpr::Mul;
|
|
|
|
return 6;
|
|
|
|
case AsmToken::Slash:
|
|
|
|
Kind = MCBinaryExpr::Div;
|
|
|
|
return 6;
|
|
|
|
case AsmToken::Percent:
|
|
|
|
Kind = MCBinaryExpr::Mod;
|
|
|
|
return 6;
|
|
|
|
case AsmToken::LessLess:
|
|
|
|
Kind = MCBinaryExpr::Shl;
|
|
|
|
return 6;
|
|
|
|
case AsmToken::GreaterGreater:
|
|
|
|
Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;
|
|
|
|
return 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned AsmParser::getBinOpPrecedence(AsmToken::TokenKind K,
|
|
|
|
MCBinaryExpr::Opcode &Kind) {
|
|
|
|
bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr();
|
|
|
|
return IsDarwin ? getDarwinBinOpPrecedence(K, Kind, ShouldUseLogicalShr)
|
|
|
|
: getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr);
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief Parse all binary operators with precedence >= 'Precedence'.
|
2009-06-23 13:57:07 +08:00
|
|
|
/// Res contains the LHS of the expression on input.
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,
|
2010-01-16 03:28:38 +08:00
|
|
|
SMLoc &EndLoc) {
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2009-08-31 16:06:59 +08:00
|
|
|
MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;
|
2009-06-30 04:37:27 +08:00
|
|
|
unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind);
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2009-06-23 13:57:07 +08:00
|
|
|
// If the next token is lower precedence than we are allowed to eat, return
|
|
|
|
// successfully with what we ate already.
|
|
|
|
if (TokPrec < Precedence)
|
|
|
|
return false;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex();
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2009-06-23 13:57:07 +08:00
|
|
|
// Eat the next primary expression.
|
2009-08-31 16:07:22 +08:00
|
|
|
const MCExpr *RHS;
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parsePrimaryExpr(RHS, EndLoc))
|
|
|
|
return true;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2009-06-23 13:57:07 +08:00
|
|
|
// If BinOp binds less tightly with RHS than the operator after RHS, let
|
|
|
|
// the pending operator take RHS as its LHS.
|
2009-08-31 16:06:59 +08:00
|
|
|
MCBinaryExpr::Opcode Dummy;
|
2009-06-30 04:37:27 +08:00
|
|
|
unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy);
|
2013-09-21 07:08:21 +08:00
|
|
|
if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS, EndLoc))
|
|
|
|
return true;
|
2009-06-23 13:57:07 +08:00
|
|
|
|
2009-06-30 04:37:27 +08:00
|
|
|
// Merge LHS and RHS according to operator.
|
2015-05-30 09:25:56 +08:00
|
|
|
Res = MCBinaryExpr::create(Kind, Res, RHS, getContext());
|
2009-06-23 13:57:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-22 04:54:55 +08:00
|
|
|
/// ParseStatement:
|
|
|
|
/// ::= EndOfStatement
|
2009-06-22 09:29:09 +08:00
|
|
|
/// ::= Label* Directive ...Operands... EndOfStatement
|
|
|
|
/// ::= Label* Identifier OperandList* EndOfStatement
|
2014-09-22 10:21:35 +08:00
|
|
|
bool AsmParser::parseStatement(ParseStatementInfo &Info,
|
|
|
|
MCAsmParserSemaCallback *SI) {
|
2016-09-17 02:30:20 +08:00
|
|
|
assert(!hasPendingError() && "parseStatement started with pending error");
|
2016-06-18 00:06:17 +08:00
|
|
|
// Eat initial spaces and comments
|
|
|
|
while (Lexer.is(AsmToken::Space))
|
|
|
|
Lex();
|
2009-08-01 08:48:30 +08:00
|
|
|
if (Lexer.is(AsmToken::EndOfStatement)) {
|
2016-06-18 00:06:17 +08:00
|
|
|
// if this is a line comment we can drop it safely
|
|
|
|
if (getTok().getString().front() == '\r' ||
|
|
|
|
getTok().getString().front() == '\n')
|
|
|
|
Out.AddBlankLine();
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex();
|
2009-06-22 04:54:55 +08:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-03 03:17:54 +08:00
|
|
|
if (Lexer.is(AsmToken::Hash)) {
|
|
|
|
// Seeing a hash here means that it was an end-of-line comment in
|
|
|
|
// an asm syntax where hash's are not comment and the previous
|
|
|
|
// statement parser did not check the end of statement. Relex as
|
|
|
|
// EndOfStatement.
|
|
|
|
StringRef CommentStr = parseStringToEndOfStatement();
|
|
|
|
Lexer.Lex();
|
|
|
|
Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr));
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-18 00:06:17 +08:00
|
|
|
// Statements always start with an identifier.
|
2010-01-20 05:44:56 +08:00
|
|
|
AsmToken ID = getTok();
|
2009-07-29 00:38:40 +08:00
|
|
|
SMLoc IDLoc = ID.getLoc();
|
2009-08-01 08:48:30 +08:00
|
|
|
StringRef IDVal;
|
2010-05-18 07:08:19 +08:00
|
|
|
int64_t LocalLabelVal = -1;
|
2016-06-18 00:06:17 +08:00
|
|
|
if (Lexer.is(AsmToken::HashDirective))
|
2013-09-21 07:08:21 +08:00
|
|
|
return parseCppHashLineFilenameComment(IDLoc);
|
2010-12-24 08:12:02 +08:00
|
|
|
// Allow an integer followed by a ':' as a directional local label.
|
2010-05-18 07:08:19 +08:00
|
|
|
if (Lexer.is(AsmToken::Integer)) {
|
|
|
|
LocalLabelVal = getTok().getIntVal();
|
|
|
|
if (LocalLabelVal < 0) {
|
2016-09-17 02:30:20 +08:00
|
|
|
if (!TheCondState.Ignore) {
|
|
|
|
Lex(); // always eat a token
|
|
|
|
return Error(IDLoc, "unexpected token at start of statement");
|
|
|
|
}
|
2010-05-18 07:08:19 +08:00
|
|
|
IDVal = "";
|
2013-01-17 03:32:36 +08:00
|
|
|
} else {
|
2010-05-18 07:08:19 +08:00
|
|
|
IDVal = getTok().getString();
|
|
|
|
Lex(); // Consume the integer token to be used as an identifier token.
|
|
|
|
if (Lexer.getKind() != AsmToken::Colon) {
|
2016-09-17 02:30:20 +08:00
|
|
|
if (!TheCondState.Ignore) {
|
|
|
|
Lex(); // always eat a token
|
|
|
|
return Error(IDLoc, "unexpected token at start of statement");
|
|
|
|
}
|
2010-05-18 07:08:19 +08:00
|
|
|
}
|
|
|
|
}
|
2011-03-26 01:47:17 +08:00
|
|
|
} else if (Lexer.is(AsmToken::Dot)) {
|
|
|
|
// Treat '.' as a valid identifier in this context.
|
|
|
|
Lex();
|
|
|
|
IDVal = ".";
|
2015-11-09 08:31:07 +08:00
|
|
|
} else if (Lexer.is(AsmToken::LCurly)) {
|
|
|
|
// Treat '{' as a valid identifier in this context.
|
|
|
|
Lex();
|
|
|
|
IDVal = "{";
|
|
|
|
|
|
|
|
} else if (Lexer.is(AsmToken::RCurly)) {
|
|
|
|
// Treat '}' as a valid identifier in this context.
|
|
|
|
Lex();
|
|
|
|
IDVal = "}";
|
2013-02-21 06:21:35 +08:00
|
|
|
} else if (parseIdentifier(IDVal)) {
|
2016-09-17 02:30:20 +08:00
|
|
|
if (!TheCondState.Ignore) {
|
|
|
|
Lex(); // always eat a token
|
|
|
|
return Error(IDLoc, "unexpected token at start of statement");
|
|
|
|
}
|
2010-04-18 02:14:27 +08:00
|
|
|
IDVal = "";
|
|
|
|
}
|
2009-08-01 08:48:30 +08:00
|
|
|
|
2010-04-18 02:14:27 +08:00
|
|
|
// Handle conditional assembly here before checking for skipping. We
|
|
|
|
// have to do this so that .endif isn't skipped in a ".if 0" block for
|
|
|
|
// example.
|
2013-01-11 06:44:57 +08:00
|
|
|
StringMap<DirectiveKind>::const_iterator DirKindIt =
|
2013-09-21 07:08:21 +08:00
|
|
|
DirectiveKindMap.find(IDVal);
|
|
|
|
DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end())
|
|
|
|
? DK_NO_DIRECTIVE
|
|
|
|
: DirKindIt->getValue();
|
2013-01-11 06:44:57 +08:00
|
|
|
switch (DirKind) {
|
2013-09-21 07:08:21 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case DK_IF:
|
2014-06-19 04:57:28 +08:00
|
|
|
case DK_IFEQ:
|
|
|
|
case DK_IFGE:
|
|
|
|
case DK_IFGT:
|
|
|
|
case DK_IFLE:
|
|
|
|
case DK_IFLT:
|
2014-02-23 23:53:41 +08:00
|
|
|
case DK_IFNE:
|
2014-06-19 04:57:28 +08:00
|
|
|
return parseDirectiveIf(IDLoc, DirKind);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_IFB:
|
|
|
|
return parseDirectiveIfb(IDLoc, true);
|
|
|
|
case DK_IFNB:
|
|
|
|
return parseDirectiveIfb(IDLoc, false);
|
|
|
|
case DK_IFC:
|
|
|
|
return parseDirectiveIfc(IDLoc, true);
|
2014-02-24 07:02:18 +08:00
|
|
|
case DK_IFEQS:
|
2015-03-18 22:20:54 +08:00
|
|
|
return parseDirectiveIfeqs(IDLoc, true);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_IFNC:
|
|
|
|
return parseDirectiveIfc(IDLoc, false);
|
2015-03-18 22:20:54 +08:00
|
|
|
case DK_IFNES:
|
|
|
|
return parseDirectiveIfeqs(IDLoc, false);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_IFDEF:
|
|
|
|
return parseDirectiveIfdef(IDLoc, true);
|
|
|
|
case DK_IFNDEF:
|
|
|
|
case DK_IFNOTDEF:
|
|
|
|
return parseDirectiveIfdef(IDLoc, false);
|
|
|
|
case DK_ELSEIF:
|
|
|
|
return parseDirectiveElseIf(IDLoc);
|
|
|
|
case DK_ELSE:
|
|
|
|
return parseDirectiveElse(IDLoc);
|
|
|
|
case DK_ENDIF:
|
|
|
|
return parseDirectiveEndIf(IDLoc);
|
2013-01-11 06:44:57 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2013-01-17 03:32:36 +08:00
|
|
|
// Ignore the statement if in the middle of inactive conditional
|
|
|
|
// (e.g. ".if 0").
|
2012-10-20 08:47:08 +08:00
|
|
|
if (TheCondState.Ignore) {
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2010-04-18 02:14:27 +08:00
|
|
|
return false;
|
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2009-08-01 08:48:30 +08:00
|
|
|
// FIXME: Recurse on local labels?
|
|
|
|
|
|
|
|
// See what kind of statement we have.
|
|
|
|
switch (Lexer.getKind()) {
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Colon: {
|
2015-11-09 08:15:45 +08:00
|
|
|
if (!getTargetParser().isLabel(ID))
|
|
|
|
break;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection())
|
|
|
|
return true;
|
2010-09-10 06:42:59 +08:00
|
|
|
|
2009-06-22 04:54:55 +08:00
|
|
|
// identifier ':' -> Label.
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex();
|
2009-06-30 07:43:14 +08:00
|
|
|
|
2011-03-26 01:47:17 +08:00
|
|
|
// Diagnose attempt to use '.' as a label.
|
|
|
|
if (IDVal == ".")
|
|
|
|
return Error(IDLoc, "invalid use of pseudo-symbol '.' as a label");
|
|
|
|
|
2009-06-30 07:43:14 +08:00
|
|
|
// Diagnose attempt to use a variable as a label.
|
|
|
|
//
|
|
|
|
// FIXME: Diagnostics. Note the location of the definition as a label.
|
|
|
|
// FIXME: This doesn't diagnose assignment to a symbol which has been
|
|
|
|
// implicitly marked as external.
|
2010-05-18 07:08:19 +08:00
|
|
|
MCSymbol *Sym;
|
2014-09-22 10:21:35 +08:00
|
|
|
if (LocalLabelVal == -1) {
|
|
|
|
if (ParsingInlineAsm && SI) {
|
2015-06-20 07:43:47 +08:00
|
|
|
StringRef RewrittenLabel =
|
|
|
|
SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);
|
|
|
|
assert(RewrittenLabel.size() &&
|
|
|
|
"We should have an internal name here.");
|
2015-10-10 13:25:02 +08:00
|
|
|
Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),
|
|
|
|
RewrittenLabel);
|
2014-09-22 10:21:35 +08:00
|
|
|
IDVal = RewrittenLabel;
|
|
|
|
}
|
2015-05-19 02:43:14 +08:00
|
|
|
Sym = getContext().getOrCreateSymbol(IDVal);
|
2014-09-22 10:21:35 +08:00
|
|
|
} else
|
2015-05-19 02:43:14 +08:00
|
|
|
Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal);
|
2014-12-24 18:27:50 +08:00
|
|
|
|
|
|
|
Sym->redefineIfPossible();
|
|
|
|
|
2010-05-06 03:01:00 +08:00
|
|
|
if (!Sym->isUndefined() || Sym->isVariable())
|
2009-06-30 07:43:14 +08:00
|
|
|
return Error(IDLoc, "invalid symbol redefinition");
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2016-08-03 03:17:54 +08:00
|
|
|
// 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
|
|
|
|
// here instead of a preprocessor line comment.
|
|
|
|
if (getTok().is(AsmToken::Hash)) {
|
|
|
|
StringRef CommentStr = parseStringToEndOfStatement();
|
|
|
|
Lexer.Lex();
|
|
|
|
Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr));
|
|
|
|
}
|
|
|
|
|
2016-07-13 22:03:12 +08:00
|
|
|
// Consume any end of statement token, if present, to avoid spurious
|
|
|
|
// AddBlankLine calls().
|
|
|
|
if (getTok().is(AsmToken::EndOfStatement)) {
|
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
2009-08-27 06:13:22 +08:00
|
|
|
// Emit the label.
|
2013-01-08 04:34:12 +08:00
|
|
|
if (!ParsingInlineAsm)
|
|
|
|
Out.EmitLabel(Sym);
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2011-12-10 02:09:40 +08:00
|
|
|
// If we are generating dwarf for assembly source files then gather the
|
2012-01-11 05:12:34 +08:00
|
|
|
// info to make a dwarf label entry for this label if needed.
|
2011-12-10 02:09:40 +08:00
|
|
|
if (getContext().getGenDwarfForAssembly())
|
2012-01-11 05:12:34 +08:00
|
|
|
MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(),
|
|
|
|
IDLoc);
|
2011-12-10 02:09:40 +08:00
|
|
|
|
2013-10-25 20:49:50 +08:00
|
|
|
getTargetParser().onLabelParsed(Sym);
|
|
|
|
|
2012-10-23 07:58:19 +08:00
|
|
|
return false;
|
2009-06-30 07:43:14 +08:00
|
|
|
}
|
2009-06-26 05:56:11 +08:00
|
|
|
|
2009-07-29 00:08:33 +08:00
|
|
|
case AsmToken::Equal:
|
2015-11-09 08:15:45 +08:00
|
|
|
if (!getTargetParser().equalIsAsmAssignment())
|
|
|
|
break;
|
2009-06-26 05:56:11 +08:00
|
|
|
// identifier '=' ... -> assignment statement
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex();
|
2009-06-26 05:56:11 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
return parseAssignment(IDVal, true);
|
2009-06-26 05:56:11 +08:00
|
|
|
|
|
|
|
default: // Normal instruction or directive.
|
|
|
|
break;
|
2009-06-22 04:54:55 +08:00
|
|
|
}
|
2010-07-19 02:54:11 +08:00
|
|
|
|
|
|
|
// If macros are enabled, check to see if this is a macro instantiation.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (areMacrosEnabled())
|
|
|
|
if (const MCAsmMacro *M = lookupMacro(IDVal)) {
|
|
|
|
return handleMacroEntry(M, IDLoc);
|
2013-01-15 07:22:36 +08:00
|
|
|
}
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2010-10-09 19:00:50 +08:00
|
|
|
// Otherwise, we have a normal instruction or directive.
|
2013-08-20 21:33:18 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Directives start with "."
|
2011-03-26 01:47:17 +08:00
|
|
|
if (IDVal[0] == '.' && IDVal != ".") {
|
2013-01-16 06:59:42 +08:00
|
|
|
// There are several entities interested in parsing directives:
|
2013-08-20 21:33:18 +08:00
|
|
|
//
|
2013-01-16 06:59:42 +08:00
|
|
|
// 1. The target-specific assembly parser. Some directives are target
|
|
|
|
// specific or may potentially behave differently on certain targets.
|
|
|
|
// 2. Asm parser extensions. For example, platform-specific parsers
|
|
|
|
// (like the ELF parser) register themselves as extensions.
|
|
|
|
// 3. The generic directive parser implemented by this class. These are
|
|
|
|
// all the directives that behave in a target and platform independent
|
|
|
|
// manner, or at least have a default behavior that's shared between
|
|
|
|
// all targets and platforms.
|
|
|
|
|
[ARM] Implement -mimplicit-it assembler option
This option, compatible with gas's -mimplicit-it, controls the
generation/checking of implicit IT blocks in ARM/Thumb assembly.
This option allows two behaviours that were not possible before:
- When in ARM mode, emit a warning when assembling a conditional
instruction that is not in an IT block. This is enabled with
-mimplicit-it=never and -mimplicit-it=thumb.
- When in Thumb mode, automatically generate IT instructions when an
instruction with a condition code appears outside of an IT block. This
is enabled with -mimplicit-it=thumb and -mimplicit-it=always.
The default option is -mimplicit-it=arm, which matches the existing
behaviour (allow conditional ARM instructions outside IT blocks without
warning, and error if a conditional Thumb instruction is outside an IT
block).
The general strategy for generating IT blocks in Thumb mode is to keep a
small list of instructions which should be in the IT block, and only
emit them when we encounter something in the input which means we cannot
continue the block. This could be caused by:
- A non-predicable instruction
- An instruction with a condition not compatible with the IT block
- The IT block already contains 4 instructions
- A branch-like instruction (including ALU instructions with the PC as
the destination), which cannot appear in the middle of an IT block
- A label (branching into an IT block is not legal)
- A change of section, architecture, ISA, etc
- The end of the assembly file.
Some of these, such as change of section and end of file, are parsed
outside of the ARM asm parser, so I've added a new virtual function to
AsmParser to ensure any previously-parsed instructions have been
emitted. The ARM implementation of this flushes the currently pending IT
block.
We now have to try instruction matching up to 3 times, because we cannot
know if the current IT block is valid before matching, and instruction
matching changes depending on the IT block state (due to the 16-bit ALU
instructions, which set the flags iff not in an IT block). In the common
case of not having an open implicit IT block and the instruction being
matched not needing one, we still only have to run the matcher once.
I've removed the ITState.FirstCond variable, because it does not store
any information that isn't already represented by CurPosition. I've also
updated the comment on CurPosition to accurately describe it's meaning
(which this patch doesn't change).
Differential Revision: https://reviews.llvm.org/D22760
llvm-svn: 276747
2016-07-26 22:19:47 +08:00
|
|
|
getTargetParser().flushPendingInstructions(getStreamer());
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
SMLoc StartTokLoc = getTok().getLoc();
|
|
|
|
bool TPDirectiveReturn = getTargetParser().ParseDirective(ID);
|
|
|
|
|
|
|
|
if (hasPendingError())
|
|
|
|
return true;
|
|
|
|
// Currently the return value should be true if we are
|
|
|
|
// uninterested but as this is at odds with the standard parsing
|
|
|
|
// convention (return true = error) we have instances of a parsed
|
|
|
|
// directive that fails returning true as an error. Catch these
|
|
|
|
// cases as best as possible errors here.
|
|
|
|
if (TPDirectiveReturn && StartTokLoc != getTok().getLoc())
|
|
|
|
return true;
|
|
|
|
// Return if we did some parsing or believe we succeeded.
|
|
|
|
if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc())
|
2012-07-06 03:09:33 +08:00
|
|
|
return false;
|
|
|
|
|
2014-01-25 01:20:08 +08:00
|
|
|
// Next, check the extension directive map to see if any extension has
|
2013-01-16 06:59:42 +08:00
|
|
|
// registered itself to parse this directive.
|
2013-09-21 07:08:21 +08:00
|
|
|
std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =
|
|
|
|
ExtensionDirectiveMap.lookup(IDVal);
|
2013-01-16 06:59:42 +08:00
|
|
|
if (Handler.first)
|
|
|
|
return (*Handler.second)(Handler.first, IDVal, IDLoc);
|
|
|
|
|
|
|
|
// Finally, if no one else is interested in this directive, it must be
|
|
|
|
// generic and familiar to this class.
|
2013-01-11 06:44:57 +08:00
|
|
|
switch (DirKind) {
|
2013-09-21 07:08:21 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case DK_SET:
|
|
|
|
case DK_EQU:
|
|
|
|
return parseDirectiveSet(IDVal, true);
|
|
|
|
case DK_EQUIV:
|
|
|
|
return parseDirectiveSet(IDVal, false);
|
|
|
|
case DK_ASCII:
|
|
|
|
return parseDirectiveAscii(IDVal, false);
|
|
|
|
case DK_ASCIZ:
|
|
|
|
case DK_STRING:
|
|
|
|
return parseDirectiveAscii(IDVal, true);
|
|
|
|
case DK_BYTE:
|
2016-10-24 22:35:29 +08:00
|
|
|
case DK_DC_B:
|
|
|
|
return parseDirectiveValue(IDVal, 1);
|
|
|
|
case DK_DC:
|
|
|
|
case DK_DC_W:
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_SHORT:
|
|
|
|
case DK_VALUE:
|
|
|
|
case DK_2BYTE:
|
2016-10-24 22:35:29 +08:00
|
|
|
return parseDirectiveValue(IDVal, 2);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_LONG:
|
|
|
|
case DK_INT:
|
|
|
|
case DK_4BYTE:
|
2016-10-24 22:35:29 +08:00
|
|
|
case DK_DC_L:
|
|
|
|
return parseDirectiveValue(IDVal, 4);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_QUAD:
|
|
|
|
case DK_8BYTE:
|
2016-10-24 22:35:29 +08:00
|
|
|
return parseDirectiveValue(IDVal, 8);
|
|
|
|
case DK_DC_A:
|
|
|
|
return parseDirectiveValue(IDVal,
|
|
|
|
getContext().getAsmInfo()->getPointerSize());
|
2014-02-02 00:20:59 +08:00
|
|
|
case DK_OCTA:
|
2016-10-24 22:35:29 +08:00
|
|
|
return parseDirectiveOctaValue(IDVal);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_SINGLE:
|
|
|
|
case DK_FLOAT:
|
2016-10-24 22:35:29 +08:00
|
|
|
case DK_DC_S:
|
|
|
|
return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_DOUBLE:
|
2016-10-24 22:35:29 +08:00
|
|
|
case DK_DC_D:
|
|
|
|
return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_ALIGN: {
|
|
|
|
bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes();
|
|
|
|
return parseDirectiveAlign(IsPow2, /*ExprSize=*/1);
|
|
|
|
}
|
|
|
|
case DK_ALIGN32: {
|
|
|
|
bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes();
|
|
|
|
return parseDirectiveAlign(IsPow2, /*ExprSize=*/4);
|
|
|
|
}
|
|
|
|
case DK_BALIGN:
|
|
|
|
return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1);
|
|
|
|
case DK_BALIGNW:
|
|
|
|
return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2);
|
|
|
|
case DK_BALIGNL:
|
|
|
|
return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4);
|
|
|
|
case DK_P2ALIGN:
|
|
|
|
return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1);
|
|
|
|
case DK_P2ALIGNW:
|
|
|
|
return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2);
|
|
|
|
case DK_P2ALIGNL:
|
|
|
|
return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4);
|
|
|
|
case DK_ORG:
|
|
|
|
return parseDirectiveOrg();
|
|
|
|
case DK_FILL:
|
|
|
|
return parseDirectiveFill();
|
|
|
|
case DK_ZERO:
|
|
|
|
return parseDirectiveZero();
|
|
|
|
case DK_EXTERN:
|
|
|
|
eatToEndOfStatement(); // .extern is the default, ignore it.
|
|
|
|
return false;
|
|
|
|
case DK_GLOBL:
|
|
|
|
case DK_GLOBAL:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_Global);
|
|
|
|
case DK_LAZY_REFERENCE:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_LazyReference);
|
|
|
|
case DK_NO_DEAD_STRIP:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip);
|
|
|
|
case DK_SYMBOL_RESOLVER:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_SymbolResolver);
|
|
|
|
case DK_PRIVATE_EXTERN:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_PrivateExtern);
|
|
|
|
case DK_REFERENCE:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_Reference);
|
|
|
|
case DK_WEAK_DEFINITION:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_WeakDefinition);
|
|
|
|
case DK_WEAK_REFERENCE:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_WeakReference);
|
|
|
|
case DK_WEAK_DEF_CAN_BE_HIDDEN:
|
|
|
|
return parseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate);
|
|
|
|
case DK_COMM:
|
|
|
|
case DK_COMMON:
|
|
|
|
return parseDirectiveComm(/*IsLocal=*/false);
|
|
|
|
case DK_LCOMM:
|
|
|
|
return parseDirectiveComm(/*IsLocal=*/true);
|
|
|
|
case DK_ABORT:
|
|
|
|
return parseDirectiveAbort();
|
|
|
|
case DK_INCLUDE:
|
|
|
|
return parseDirectiveInclude();
|
|
|
|
case DK_INCBIN:
|
|
|
|
return parseDirectiveIncbin();
|
|
|
|
case DK_CODE16:
|
|
|
|
case DK_CODE16GCC:
|
2016-06-18 00:06:17 +08:00
|
|
|
return TokError(Twine(IDVal) +
|
|
|
|
" not currently supported for this target");
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_REPT:
|
2013-12-28 13:54:33 +08:00
|
|
|
return parseDirectiveRept(IDLoc, IDVal);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_IRP:
|
|
|
|
return parseDirectiveIrp(IDLoc);
|
|
|
|
case DK_IRPC:
|
|
|
|
return parseDirectiveIrpc(IDLoc);
|
|
|
|
case DK_ENDR:
|
|
|
|
return parseDirectiveEndr(IDLoc);
|
|
|
|
case DK_BUNDLE_ALIGN_MODE:
|
|
|
|
return parseDirectiveBundleAlignMode();
|
|
|
|
case DK_BUNDLE_LOCK:
|
|
|
|
return parseDirectiveBundleLock();
|
|
|
|
case DK_BUNDLE_UNLOCK:
|
|
|
|
return parseDirectiveBundleUnlock();
|
|
|
|
case DK_SLEB128:
|
|
|
|
return parseDirectiveLEB128(true);
|
|
|
|
case DK_ULEB128:
|
|
|
|
return parseDirectiveLEB128(false);
|
|
|
|
case DK_SPACE:
|
|
|
|
case DK_SKIP:
|
|
|
|
return parseDirectiveSpace(IDVal);
|
|
|
|
case DK_FILE:
|
|
|
|
return parseDirectiveFile(IDLoc);
|
|
|
|
case DK_LINE:
|
|
|
|
return parseDirectiveLine();
|
|
|
|
case DK_LOC:
|
|
|
|
return parseDirectiveLoc();
|
|
|
|
case DK_STABS:
|
|
|
|
return parseDirectiveStabs();
|
2016-01-29 08:49:42 +08:00
|
|
|
case DK_CV_FILE:
|
|
|
|
return parseDirectiveCVFile();
|
2016-09-08 00:15:31 +08:00
|
|
|
case DK_CV_FUNC_ID:
|
|
|
|
return parseDirectiveCVFuncId();
|
|
|
|
case DK_CV_INLINE_SITE_ID:
|
|
|
|
return parseDirectiveCVInlineSiteId();
|
2016-01-29 08:49:42 +08:00
|
|
|
case DK_CV_LOC:
|
|
|
|
return parseDirectiveCVLoc();
|
|
|
|
case DK_CV_LINETABLE:
|
|
|
|
return parseDirectiveCVLinetable();
|
2016-01-30 03:24:12 +08:00
|
|
|
case DK_CV_INLINE_LINETABLE:
|
|
|
|
return parseDirectiveCVInlineLinetable();
|
2016-02-05 09:55:49 +08:00
|
|
|
case DK_CV_DEF_RANGE:
|
|
|
|
return parseDirectiveCVDefRange();
|
2016-01-29 08:49:42 +08:00
|
|
|
case DK_CV_STRINGTABLE:
|
|
|
|
return parseDirectiveCVStringTable();
|
|
|
|
case DK_CV_FILECHECKSUMS:
|
|
|
|
return parseDirectiveCVFileChecksums();
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_CFI_SECTIONS:
|
|
|
|
return parseDirectiveCFISections();
|
|
|
|
case DK_CFI_STARTPROC:
|
|
|
|
return parseDirectiveCFIStartProc();
|
|
|
|
case DK_CFI_ENDPROC:
|
|
|
|
return parseDirectiveCFIEndProc();
|
|
|
|
case DK_CFI_DEF_CFA:
|
|
|
|
return parseDirectiveCFIDefCfa(IDLoc);
|
|
|
|
case DK_CFI_DEF_CFA_OFFSET:
|
|
|
|
return parseDirectiveCFIDefCfaOffset();
|
|
|
|
case DK_CFI_ADJUST_CFA_OFFSET:
|
|
|
|
return parseDirectiveCFIAdjustCfaOffset();
|
|
|
|
case DK_CFI_DEF_CFA_REGISTER:
|
|
|
|
return parseDirectiveCFIDefCfaRegister(IDLoc);
|
|
|
|
case DK_CFI_OFFSET:
|
|
|
|
return parseDirectiveCFIOffset(IDLoc);
|
|
|
|
case DK_CFI_REL_OFFSET:
|
|
|
|
return parseDirectiveCFIRelOffset(IDLoc);
|
|
|
|
case DK_CFI_PERSONALITY:
|
|
|
|
return parseDirectiveCFIPersonalityOrLsda(true);
|
|
|
|
case DK_CFI_LSDA:
|
|
|
|
return parseDirectiveCFIPersonalityOrLsda(false);
|
|
|
|
case DK_CFI_REMEMBER_STATE:
|
|
|
|
return parseDirectiveCFIRememberState();
|
|
|
|
case DK_CFI_RESTORE_STATE:
|
|
|
|
return parseDirectiveCFIRestoreState();
|
|
|
|
case DK_CFI_SAME_VALUE:
|
|
|
|
return parseDirectiveCFISameValue(IDLoc);
|
|
|
|
case DK_CFI_RESTORE:
|
|
|
|
return parseDirectiveCFIRestore(IDLoc);
|
|
|
|
case DK_CFI_ESCAPE:
|
|
|
|
return parseDirectiveCFIEscape();
|
|
|
|
case DK_CFI_SIGNAL_FRAME:
|
|
|
|
return parseDirectiveCFISignalFrame();
|
|
|
|
case DK_CFI_UNDEFINED:
|
|
|
|
return parseDirectiveCFIUndefined(IDLoc);
|
|
|
|
case DK_CFI_REGISTER:
|
|
|
|
return parseDirectiveCFIRegister(IDLoc);
|
2013-09-26 22:49:40 +08:00
|
|
|
case DK_CFI_WINDOW_SAVE:
|
|
|
|
return parseDirectiveCFIWindowSave();
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_MACROS_ON:
|
|
|
|
case DK_MACROS_OFF:
|
|
|
|
return parseDirectiveMacrosOnOff(IDVal);
|
|
|
|
case DK_MACRO:
|
|
|
|
return parseDirectiveMacro(IDLoc);
|
2014-07-25 01:08:39 +08:00
|
|
|
case DK_EXITM:
|
|
|
|
return parseDirectiveExitMacro(IDVal);
|
2013-09-21 07:08:21 +08:00
|
|
|
case DK_ENDM:
|
|
|
|
case DK_ENDMACRO:
|
|
|
|
return parseDirectiveEndMacro(IDVal);
|
|
|
|
case DK_PURGEM:
|
|
|
|
return parseDirectivePurgeMacro(IDLoc);
|
2013-12-18 10:53:03 +08:00
|
|
|
case DK_END:
|
|
|
|
return parseDirectiveEnd(IDLoc);
|
2014-02-23 23:53:30 +08:00
|
|
|
case DK_ERR:
|
2014-02-24 07:02:23 +08:00
|
|
|
return parseDirectiveError(IDLoc, false);
|
|
|
|
case DK_ERROR:
|
|
|
|
return parseDirectiveError(IDLoc, true);
|
2014-07-25 00:26:06 +08:00
|
|
|
case DK_WARNING:
|
|
|
|
return parseDirectiveWarning(IDLoc);
|
2015-11-12 21:33:00 +08:00
|
|
|
case DK_RELOC:
|
|
|
|
return parseDirectiveReloc(IDLoc);
|
2016-09-24 03:25:15 +08:00
|
|
|
case DK_DCB:
|
|
|
|
case DK_DCB_W:
|
|
|
|
return parseDirectiveDCB(IDVal, 2);
|
|
|
|
case DK_DCB_B:
|
|
|
|
return parseDirectiveDCB(IDVal, 1);
|
|
|
|
case DK_DCB_D:
|
|
|
|
return parseDirectiveRealDCB(IDVal, APFloat::IEEEdouble);
|
|
|
|
case DK_DCB_L:
|
|
|
|
return parseDirectiveDCB(IDVal, 4);
|
|
|
|
case DK_DCB_S:
|
|
|
|
return parseDirectiveRealDCB(IDVal, APFloat::IEEEsingle);
|
2016-08-24 05:34:53 +08:00
|
|
|
case DK_DC_X:
|
2016-09-24 03:25:15 +08:00
|
|
|
case DK_DCB_X:
|
2016-08-24 05:34:53 +08:00
|
|
|
return TokError(Twine(IDVal) +
|
|
|
|
" not currently supported for this target");
|
2016-09-24 05:53:36 +08:00
|
|
|
case DK_DS:
|
|
|
|
case DK_DS_W:
|
|
|
|
return parseDirectiveDS(IDVal, 2);
|
|
|
|
case DK_DS_B:
|
|
|
|
return parseDirectiveDS(IDVal, 1);
|
|
|
|
case DK_DS_D:
|
|
|
|
return parseDirectiveDS(IDVal, 8);
|
|
|
|
case DK_DS_L:
|
|
|
|
case DK_DS_S:
|
|
|
|
return parseDirectiveDS(IDVal, 4);
|
|
|
|
case DK_DS_P:
|
|
|
|
case DK_DS_X:
|
|
|
|
return parseDirectiveDS(IDVal, 12);
|
2012-05-12 19:18:59 +08:00
|
|
|
}
|
2013-01-11 06:44:57 +08:00
|
|
|
|
2012-05-02 02:38:27 +08:00
|
|
|
return Error(IDLoc, "unknown directive");
|
2009-06-22 09:29:09 +08:00
|
|
|
}
|
2009-06-22 04:54:55 +08:00
|
|
|
|
2013-02-13 05:33:51 +08:00
|
|
|
// __asm _emit or __asm __emit
|
|
|
|
if (ParsingInlineAsm && (IDVal == "_emit" || IDVal == "__emit" ||
|
|
|
|
IDVal == "_EMIT" || IDVal == "__EMIT"))
|
2013-09-21 07:08:21 +08:00
|
|
|
return parseDirectiveMSEmit(IDLoc, Info, IDVal.size());
|
2013-02-13 05:33:51 +08:00
|
|
|
|
|
|
|
// __asm align
|
|
|
|
if (ParsingInlineAsm && (IDVal == "align" || IDVal == "ALIGN"))
|
2013-09-21 07:08:21 +08:00
|
|
|
return parseDirectiveMSAlign(IDLoc, Info);
|
2012-10-23 07:58:19 +08:00
|
|
|
|
2015-12-14 01:07:23 +08:00
|
|
|
if (ParsingInlineAsm && (IDVal == "even"))
|
|
|
|
Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4);
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection())
|
|
|
|
return true;
|
2010-09-10 06:42:59 +08:00
|
|
|
|
2010-05-20 07:34:33 +08:00
|
|
|
// Canonicalize the opcode to lower case.
|
2013-01-17 03:32:36 +08:00
|
|
|
std::string OpcodeStr = IDVal.lower();
|
2012-10-26 04:41:34 +08:00
|
|
|
ParseInstructionInfo IInfo(Info.AsmRewrites);
|
2016-09-17 02:30:20 +08:00
|
|
|
bool ParseHadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID,
|
|
|
|
Info.ParsedOperands);
|
|
|
|
Info.ParseError = ParseHadError;
|
2010-05-04 08:33:07 +08:00
|
|
|
|
2010-08-11 14:37:09 +08:00
|
|
|
// Dump the parsed representation, if requested.
|
|
|
|
if (getShowParsedOperands()) {
|
|
|
|
SmallString<256> Str;
|
|
|
|
raw_svector_ostream OS(Str);
|
|
|
|
OS << "parsed instruction: [";
|
2012-10-23 07:58:19 +08:00
|
|
|
for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) {
|
2010-08-11 14:37:09 +08:00
|
|
|
if (i != 0)
|
|
|
|
OS << ", ";
|
2012-10-23 07:58:19 +08:00
|
|
|
Info.ParsedOperands[i]->print(OS);
|
2010-08-11 14:37:09 +08:00
|
|
|
}
|
|
|
|
OS << "]";
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
printMessage(IDLoc, SourceMgr::DK_Note, OS.str());
|
2010-08-11 14:37:09 +08:00
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
// Fail even if ParseInstruction erroneously returns false.
|
|
|
|
if (hasPendingError() || ParseHadError)
|
|
|
|
return true;
|
|
|
|
|
2014-06-19 23:52:37 +08:00
|
|
|
// If we are generating dwarf for the current section then generate a .loc
|
|
|
|
// directive for the instruction.
|
2016-09-17 02:30:20 +08:00
|
|
|
if (!ParseHadError && getContext().getGenDwarfForAssembly() &&
|
2014-06-19 23:52:37 +08:00
|
|
|
getContext().getGenDwarfSectionSyms().count(
|
2016-10-14 13:47:37 +08:00
|
|
|
getStreamer().getCurrentSectionOnly())) {
|
2014-12-24 14:32:43 +08:00
|
|
|
unsigned Line;
|
|
|
|
if (ActiveMacros.empty())
|
|
|
|
Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer);
|
|
|
|
else
|
2015-06-26 05:57:33 +08:00
|
|
|
Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc,
|
|
|
|
ActiveMacros.front()->ExitBuffer);
|
2012-11-02 01:31:35 +08:00
|
|
|
|
2013-01-17 03:32:36 +08:00
|
|
|
// If we previously parsed a cpp hash file line comment then make sure the
|
|
|
|
// current Dwarf File is for the CppHashFilename if not then emit the
|
|
|
|
// Dwarf File table for it and adjust the line number for the .loc.
|
2016-04-14 03:46:54 +08:00
|
|
|
if (CppHashInfo.Filename.size()) {
|
2014-03-17 09:52:11 +08:00
|
|
|
unsigned FileNumber = getStreamer().EmitDwarfFileDirective(
|
2016-04-14 03:46:54 +08:00
|
|
|
0, StringRef(), CppHashInfo.Filename);
|
2014-03-17 09:52:11 +08:00
|
|
|
getContext().setGenDwarfFileNumber(FileNumber);
|
2013-09-21 07:08:21 +08:00
|
|
|
|
|
|
|
// Since SrcMgr.FindLineNumber() is slow and messes up the SourceMgr's
|
|
|
|
// cache with the different Loc from the call above we save the last
|
|
|
|
// info we queried here with SrcMgr.FindLineNumber().
|
|
|
|
unsigned CppHashLocLineNo;
|
2016-04-14 03:46:54 +08:00
|
|
|
if (LastQueryIDLoc == CppHashInfo.Loc &&
|
|
|
|
LastQueryBuffer == CppHashInfo.Buf)
|
2013-09-21 07:08:21 +08:00
|
|
|
CppHashLocLineNo = LastQueryLine;
|
|
|
|
else {
|
2016-04-14 03:46:54 +08:00
|
|
|
CppHashLocLineNo =
|
|
|
|
SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf);
|
2013-09-21 07:08:21 +08:00
|
|
|
LastQueryLine = CppHashLocLineNo;
|
2016-04-14 03:46:54 +08:00
|
|
|
LastQueryIDLoc = CppHashInfo.Loc;
|
|
|
|
LastQueryBuffer = CppHashInfo.Buf;
|
2013-09-21 07:08:21 +08:00
|
|
|
}
|
2016-04-14 03:46:54 +08:00
|
|
|
Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo);
|
2013-01-17 03:32:36 +08:00
|
|
|
}
|
2012-11-02 01:31:35 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
getStreamer().EmitDwarfLocDirective(
|
|
|
|
getContext().getGenDwarfFileNumber(), Line, 0,
|
|
|
|
DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0,
|
|
|
|
StringRef());
|
2011-11-02 06:27:22 +08:00
|
|
|
}
|
|
|
|
|
2010-05-04 08:33:07 +08:00
|
|
|
// If parsing succeeded, match the instruction.
|
2016-09-17 02:30:20 +08:00
|
|
|
if (!ParseHadError) {
|
2014-08-18 19:49:42 +08:00
|
|
|
uint64_t ErrorInfo;
|
2016-09-17 02:30:20 +08:00
|
|
|
if (getTargetParser().MatchAndEmitInstruction(IDLoc, Info.Opcode,
|
|
|
|
Info.ParsedOperands, Out,
|
|
|
|
ErrorInfo, ParsingInlineAsm))
|
|
|
|
return true;
|
2012-10-13 08:26:04 +08:00
|
|
|
}
|
2010-09-12 00:18:25 +08:00
|
|
|
return false;
|
2009-06-22 04:16:42 +08:00
|
|
|
}
|
2009-06-24 12:43:34 +08:00
|
|
|
|
2016-03-08 02:11:16 +08:00
|
|
|
// Parse and erase curly braces marking block start/end
|
|
|
|
bool
|
|
|
|
AsmParser::parseCurlyBlockScope(SmallVectorImpl<AsmRewrite> &AsmStrRewrites) {
|
|
|
|
// Identify curly brace marking block start/end
|
|
|
|
if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SMLoc StartLoc = Lexer.getLoc();
|
|
|
|
Lex(); // Eat the brace
|
|
|
|
if (Lexer.is(AsmToken::EndOfStatement))
|
|
|
|
Lex(); // Eat EndOfStatement following the brace
|
|
|
|
|
|
|
|
// Erase the block start/end brace from the output asm string
|
|
|
|
AsmStrRewrites.emplace_back(AOK_Skip, StartLoc, Lexer.getLoc().getPointer() -
|
|
|
|
StartLoc.getPointer());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseCppHashLineFilenameComment as this:
|
2011-09-14 07:45:18 +08:00
|
|
|
/// ::= # number "filename"
|
2015-09-21 07:35:59 +08:00
|
|
|
bool AsmParser::parseCppHashLineFilenameComment(SMLoc L) {
|
2011-09-14 07:45:18 +08:00
|
|
|
Lex(); // Eat the hash token.
|
2016-06-18 00:06:17 +08:00
|
|
|
// Lexer only ever emits HashDirective if it fully formed if it's
|
|
|
|
// done the checking already so this is an internal error.
|
|
|
|
assert(getTok().is(AsmToken::Integer) &&
|
|
|
|
"Lexing Cpp line comment: Expected Integer");
|
2011-09-14 07:45:18 +08:00
|
|
|
int64_t LineNumber = getTok().getIntVal();
|
|
|
|
Lex();
|
2016-06-18 00:06:17 +08:00
|
|
|
assert(getTok().is(AsmToken::String) &&
|
|
|
|
"Lexing Cpp line comment: Expected String");
|
2011-09-14 07:45:18 +08:00
|
|
|
StringRef Filename = getTok().getString();
|
2016-06-18 00:06:17 +08:00
|
|
|
Lex();
|
2016-09-17 02:30:20 +08:00
|
|
|
|
2011-09-14 07:45:18 +08:00
|
|
|
// Get rid of the enclosing quotes.
|
2013-09-21 07:08:21 +08:00
|
|
|
Filename = Filename.substr(1, Filename.size() - 2);
|
2011-09-14 07:45:18 +08:00
|
|
|
|
2011-10-13 05:38:39 +08:00
|
|
|
// Save the SMLoc, Filename and LineNumber for later use by diagnostics.
|
2016-04-14 03:46:54 +08:00
|
|
|
CppHashInfo.Loc = L;
|
|
|
|
CppHashInfo.Filename = Filename;
|
|
|
|
CppHashInfo.LineNumber = LineNumber;
|
|
|
|
CppHashInfo.Buf = CurBuffer;
|
2011-09-14 07:45:18 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief will use the last parsed cpp hash line filename comment
|
2011-10-13 05:38:39 +08:00
|
|
|
/// for the Filename and LineNo if any in the diagnostic.
|
|
|
|
void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
|
2013-09-21 07:08:21 +08:00
|
|
|
const AsmParser *Parser = static_cast<const AsmParser *>(Context);
|
2011-10-13 05:38:39 +08:00
|
|
|
raw_ostream &OS = errs();
|
|
|
|
|
|
|
|
const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr();
|
2015-09-21 07:35:59 +08:00
|
|
|
SMLoc DiagLoc = Diag.getLoc();
|
2014-07-06 18:33:31 +08:00
|
|
|
unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);
|
|
|
|
unsigned CppHashBuf =
|
2016-04-14 03:46:54 +08:00
|
|
|
Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashInfo.Loc);
|
2011-10-13 05:38:39 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// Like SourceMgr::printMessage() we need to print the include stack if any
|
2011-10-13 05:38:39 +08:00
|
|
|
// before printing the message.
|
2014-07-06 18:33:31 +08:00
|
|
|
unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);
|
|
|
|
if (!Parser->SavedDiagHandler && DiagCurBuffer &&
|
|
|
|
DiagCurBuffer != DiagSrcMgr.getMainFileID()) {
|
2013-09-21 07:08:21 +08:00
|
|
|
SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);
|
|
|
|
DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);
|
2011-10-13 05:38:39 +08:00
|
|
|
}
|
|
|
|
|
2012-12-18 08:30:54 +08:00
|
|
|
// If we have not parsed a cpp hash line filename comment or the source
|
2011-10-13 05:38:39 +08:00
|
|
|
// manager changed or buffer changed (like in a nested include) then just
|
|
|
|
// print the normal diagnostic using its Filename and LineNo.
|
2016-04-14 03:46:54 +08:00
|
|
|
if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr ||
|
2011-10-13 05:38:39 +08:00
|
|
|
DiagBuf != CppHashBuf) {
|
2011-10-16 18:48:29 +08:00
|
|
|
if (Parser->SavedDiagHandler)
|
|
|
|
Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);
|
|
|
|
else
|
2014-04-24 14:44:33 +08:00
|
|
|
Diag.print(nullptr, OS);
|
2011-10-13 05:38:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-12-18 08:30:54 +08:00
|
|
|
// Use the CppHashFilename and calculate a line number based on the
|
2016-04-14 03:46:54 +08:00
|
|
|
// CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc
|
|
|
|
// for the diagnostic.
|
|
|
|
const std::string &Filename = Parser->CppHashInfo.Filename;
|
2011-10-13 05:38:39 +08:00
|
|
|
|
|
|
|
int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf);
|
|
|
|
int CppHashLocLineNo =
|
2016-04-14 03:46:54 +08:00
|
|
|
Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc, CppHashBuf);
|
2013-09-21 07:08:21 +08:00
|
|
|
int LineNo =
|
2016-04-14 03:46:54 +08:00
|
|
|
Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo);
|
2011-10-13 05:38:39 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo,
|
|
|
|
Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),
|
2011-10-16 13:47:55 +08:00
|
|
|
Diag.getLineContents(), Diag.getRanges());
|
2011-10-13 05:38:39 +08:00
|
|
|
|
2011-10-16 18:48:29 +08:00
|
|
|
if (Parser->SavedDiagHandler)
|
|
|
|
Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);
|
|
|
|
else
|
2014-04-24 14:44:33 +08:00
|
|
|
NewDiag.print(nullptr, OS);
|
2011-10-13 05:38:39 +08:00
|
|
|
}
|
|
|
|
|
2012-08-22 02:29:30 +08:00
|
|
|
// FIXME: This is mostly duplicated from the function in AsmLexer.cpp. The
|
|
|
|
// difference being that that function accepts '@' as part of identifiers and
|
|
|
|
// we can't do that. AsmLexer.cpp should probably be changed to handle
|
|
|
|
// '@' as a special case when needed.
|
|
|
|
static bool isIdentifierChar(char c) {
|
2013-02-13 05:21:59 +08:00
|
|
|
return isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '$' ||
|
|
|
|
c == '.';
|
2012-08-22 02:29:30 +08:00
|
|
|
}
|
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
|
2014-02-10 01:13:11 +08:00
|
|
|
ArrayRef<MCAsmMacroParameter> Parameters,
|
2015-04-27 18:50:29 +08:00
|
|
|
ArrayRef<MCAsmMacroArgument> A,
|
2015-09-21 07:35:59 +08:00
|
|
|
bool EnableAtPseudoVariable, SMLoc L) {
|
2011-06-05 10:43:45 +08:00
|
|
|
unsigned NParameters = Parameters.size();
|
2014-04-23 14:56:28 +08:00
|
|
|
bool HasVararg = NParameters ? Parameters.back().Vararg : false;
|
2014-02-20 21:36:32 +08:00
|
|
|
if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
|
2011-06-05 10:43:45 +08:00
|
|
|
return Error(L, "Wrong number of arguments");
|
2010-07-19 03:00:10 +08:00
|
|
|
|
2012-09-20 04:36:12 +08:00
|
|
|
// A macro without parameters is handled differently on Darwin:
|
|
|
|
// gas accepts no arguments and does no substitutions
|
2010-07-19 03:00:10 +08:00
|
|
|
while (!Body.empty()) {
|
|
|
|
// Scan for the next substitution.
|
|
|
|
std::size_t End = Body.size(), Pos = 0;
|
|
|
|
for (; Pos != End; ++Pos) {
|
|
|
|
// Check for a substitution or escape.
|
2014-02-20 21:36:32 +08:00
|
|
|
if (IsDarwin && !NParameters) {
|
2011-06-05 10:43:45 +08:00
|
|
|
// This macro has no parameters, look for $0, $1, etc.
|
|
|
|
if (Body[Pos] != '$' || Pos + 1 == End)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
char Next = Body[Pos + 1];
|
2013-02-13 05:21:59 +08:00
|
|
|
if (Next == '$' || Next == 'n' ||
|
|
|
|
isdigit(static_cast<unsigned char>(Next)))
|
2011-06-05 10:43:45 +08:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// This macro has parameters, look for \foo, \bar, etc.
|
|
|
|
if (Body[Pos] == '\\' && Pos + 1 != End)
|
|
|
|
break;
|
|
|
|
}
|
2010-07-19 03:00:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add the prefix.
|
|
|
|
OS << Body.slice(0, Pos);
|
|
|
|
|
|
|
|
// Check if we reached the end.
|
|
|
|
if (Pos == End)
|
|
|
|
break;
|
|
|
|
|
2014-02-20 21:36:32 +08:00
|
|
|
if (IsDarwin && !NParameters) {
|
2013-09-21 07:08:21 +08:00
|
|
|
switch (Body[Pos + 1]) {
|
|
|
|
// $$ => $
|
2011-06-05 10:43:45 +08:00
|
|
|
case '$':
|
|
|
|
OS << '$';
|
|
|
|
break;
|
2010-07-19 03:00:10 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// $n => number of arguments
|
2011-06-05 10:43:45 +08:00
|
|
|
case 'n':
|
|
|
|
OS << A.size();
|
|
|
|
break;
|
2010-07-19 03:00:10 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// $[0-9] => argument
|
2011-06-05 10:43:45 +08:00
|
|
|
default: {
|
|
|
|
// Missing arguments are ignored.
|
2013-09-21 07:08:21 +08:00
|
|
|
unsigned Index = Body[Pos + 1] - '0';
|
2011-06-05 10:43:45 +08:00
|
|
|
if (Index >= A.size())
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Otherwise substitute with the token values, with spaces eliminated.
|
2015-10-10 13:38:14 +08:00
|
|
|
for (const AsmToken &Token : A[Index])
|
|
|
|
OS << Token.getString();
|
2010-07-19 03:00:10 +08:00
|
|
|
break;
|
2011-06-05 10:43:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Pos += 2;
|
|
|
|
} else {
|
|
|
|
unsigned I = Pos + 1;
|
2015-04-27 18:50:29 +08:00
|
|
|
|
|
|
|
// Check for the \@ pseudo-variable.
|
|
|
|
if (EnableAtPseudoVariable && Body[I] == '@' && I + 1 != End)
|
2011-06-05 10:43:45 +08:00
|
|
|
++I;
|
2015-04-27 18:50:29 +08:00
|
|
|
else
|
|
|
|
while (isIdentifierChar(Body[I]) && I + 1 != End)
|
|
|
|
++I;
|
2011-06-05 10:43:45 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
const char *Begin = Body.data() + Pos + 1;
|
|
|
|
StringRef Argument(Begin, I - (Pos + 1));
|
2011-06-05 10:43:45 +08:00
|
|
|
unsigned Index = 0;
|
|
|
|
|
2015-04-27 18:50:29 +08:00
|
|
|
if (Argument == "@") {
|
|
|
|
OS << NumOfMacroInstantiations;
|
|
|
|
Pos += 2;
|
2012-09-20 04:36:12 +08:00
|
|
|
} else {
|
2015-04-27 18:50:29 +08:00
|
|
|
for (; Index < NParameters; ++Index)
|
|
|
|
if (Parameters[Index].Name == Argument)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (Index == NParameters) {
|
|
|
|
if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')')
|
|
|
|
Pos += 3;
|
|
|
|
else {
|
|
|
|
OS << '\\' << Argument;
|
|
|
|
Pos = I;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool VarargParameter = HasVararg && Index == (NParameters - 1);
|
2015-10-10 13:38:14 +08:00
|
|
|
for (const AsmToken &Token : A[Index])
|
2015-04-27 18:50:29 +08:00
|
|
|
// We expect no quotes around the string's contents when
|
|
|
|
// parsing for varargs.
|
2015-10-10 13:38:14 +08:00
|
|
|
if (Token.getKind() != AsmToken::String || VarargParameter)
|
|
|
|
OS << Token.getString();
|
2015-04-27 18:50:29 +08:00
|
|
|
else
|
2015-10-10 13:38:14 +08:00
|
|
|
OS << Token.getStringContents();
|
2015-04-27 18:50:29 +08:00
|
|
|
|
|
|
|
Pos += 1 + Argument.size();
|
|
|
|
}
|
2012-09-20 04:36:12 +08:00
|
|
|
}
|
2011-06-05 10:43:45 +08:00
|
|
|
}
|
2010-07-19 03:00:10 +08:00
|
|
|
// Update the scan point.
|
2011-06-05 10:43:45 +08:00
|
|
|
Body = Body.substr(Pos);
|
2010-07-19 03:00:10 +08:00
|
|
|
}
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2011-06-05 10:43:45 +08:00
|
|
|
return false;
|
|
|
|
}
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2014-07-25 00:29:04 +08:00
|
|
|
MacroInstantiation::MacroInstantiation(SMLoc IL, int EB, SMLoc EL,
|
2014-08-28 03:49:03 +08:00
|
|
|
size_t CondStackDepth)
|
2014-08-18 06:48:55 +08:00
|
|
|
: InstantiationLoc(IL), ExitBuffer(EB), ExitLoc(EL),
|
2014-07-25 01:08:39 +08:00
|
|
|
CondStackDepth(CondStackDepth) {}
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
static bool isOperator(AsmToken::TokenKind kind) {
|
|
|
|
switch (kind) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case AsmToken::Plus:
|
|
|
|
case AsmToken::Minus:
|
|
|
|
case AsmToken::Tilde:
|
|
|
|
case AsmToken::Slash:
|
|
|
|
case AsmToken::Star:
|
|
|
|
case AsmToken::Dot:
|
|
|
|
case AsmToken::Equal:
|
|
|
|
case AsmToken::EqualEqual:
|
|
|
|
case AsmToken::Pipe:
|
|
|
|
case AsmToken::PipePipe:
|
|
|
|
case AsmToken::Caret:
|
|
|
|
case AsmToken::Amp:
|
|
|
|
case AsmToken::AmpAmp:
|
|
|
|
case AsmToken::Exclaim:
|
|
|
|
case AsmToken::ExclaimEqual:
|
|
|
|
case AsmToken::Less:
|
|
|
|
case AsmToken::LessEqual:
|
|
|
|
case AsmToken::LessLess:
|
|
|
|
case AsmToken::LessGreater:
|
|
|
|
case AsmToken::Greater:
|
|
|
|
case AsmToken::GreaterEqual:
|
|
|
|
case AsmToken::GreaterGreater:
|
|
|
|
return true;
|
2012-09-20 04:36:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-29 08:07:39 +08:00
|
|
|
namespace {
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2014-01-29 08:07:39 +08:00
|
|
|
class AsmLexerSkipSpaceRAII {
|
|
|
|
public:
|
|
|
|
AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) : Lexer(Lexer) {
|
|
|
|
Lexer.setSkipSpace(SkipSpace);
|
|
|
|
}
|
|
|
|
|
|
|
|
~AsmLexerSkipSpaceRAII() {
|
|
|
|
Lexer.setSkipSpace(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
AsmLexer &Lexer;
|
|
|
|
};
|
2016-08-24 01:14:32 +08:00
|
|
|
|
|
|
|
} // end anonymous namespace
|
2014-01-29 08:07:39 +08:00
|
|
|
|
2014-04-23 14:56:28 +08:00
|
|
|
bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) {
|
|
|
|
|
|
|
|
if (Vararg) {
|
|
|
|
if (Lexer.isNot(AsmToken::EndOfStatement)) {
|
|
|
|
StringRef Str = parseStringToEndOfStatement();
|
2015-05-30 03:43:39 +08:00
|
|
|
MA.emplace_back(AsmToken::String, Str);
|
2014-04-23 14:56:28 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-07-19 03:00:10 +08:00
|
|
|
unsigned ParenLevel = 0;
|
2012-09-20 04:36:12 +08:00
|
|
|
|
2014-01-29 08:07:39 +08:00
|
|
|
// Darwin doesn't use spaces to delmit arguments.
|
|
|
|
AsmLexerSkipSpaceRAII ScopedSkipSpace(Lexer, IsDarwin);
|
2012-06-15 22:02:34 +08:00
|
|
|
|
2016-02-11 21:48:49 +08:00
|
|
|
bool SpaceEaten;
|
|
|
|
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2016-02-11 21:48:49 +08:00
|
|
|
SpaceEaten = false;
|
2014-01-29 08:07:39 +08:00
|
|
|
if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))
|
2010-07-19 03:00:10 +08:00
|
|
|
return TokError("unexpected token in macro instantiation");
|
2012-09-20 04:36:12 +08:00
|
|
|
|
2016-02-11 21:48:49 +08:00
|
|
|
if (ParenLevel == 0) {
|
2012-09-20 04:36:12 +08:00
|
|
|
|
2016-02-11 21:48:49 +08:00
|
|
|
if (Lexer.is(AsmToken::Comma))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (Lexer.is(AsmToken::Space)) {
|
|
|
|
SpaceEaten = true;
|
2016-06-03 01:15:05 +08:00
|
|
|
Lexer.Lex(); // Eat spaces
|
2016-02-11 21:48:49 +08:00
|
|
|
}
|
2012-09-20 04:36:12 +08:00
|
|
|
|
|
|
|
// 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
|
2014-01-30 02:57:46 +08:00
|
|
|
if (!IsDarwin) {
|
2013-09-21 07:08:21 +08:00
|
|
|
if (isOperator(Lexer.getKind())) {
|
2016-02-11 21:48:49 +08:00
|
|
|
MA.push_back(getTok());
|
2016-06-03 01:15:05 +08:00
|
|
|
Lexer.Lex();
|
2012-09-20 04:36:12 +08:00
|
|
|
|
2016-02-11 21:48:49 +08:00
|
|
|
// Whitespace after an operator can be ignored.
|
|
|
|
if (Lexer.is(AsmToken::Space))
|
2016-06-03 01:15:05 +08:00
|
|
|
Lexer.Lex();
|
2016-02-11 21:48:49 +08:00
|
|
|
|
|
|
|
continue;
|
2012-09-20 04:36:12 +08:00
|
|
|
}
|
|
|
|
}
|
2016-02-11 21:48:49 +08:00
|
|
|
if (SpaceEaten)
|
|
|
|
break;
|
2012-09-20 04:36:12 +08:00
|
|
|
}
|
2012-06-15 22:02:34 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// handleMacroEntry relies on not advancing the lexer here
|
2012-06-15 22:02:34 +08:00
|
|
|
// to be able to fill in the remaining default parameter values
|
2010-07-19 03:00:10 +08:00
|
|
|
if (Lexer.is(AsmToken::EndOfStatement))
|
|
|
|
break;
|
|
|
|
|
2012-06-15 22:02:34 +08:00
|
|
|
// Adjust the current parentheses level.
|
|
|
|
if (Lexer.is(AsmToken::LParen))
|
|
|
|
++ParenLevel;
|
|
|
|
else if (Lexer.is(AsmToken::RParen) && ParenLevel)
|
|
|
|
--ParenLevel;
|
|
|
|
|
|
|
|
// Append the token to the current argument list.
|
|
|
|
MA.push_back(getTok());
|
2016-06-03 01:15:05 +08:00
|
|
|
Lexer.Lex();
|
2010-07-19 03:00:10 +08:00
|
|
|
}
|
2012-09-20 04:36:12 +08:00
|
|
|
|
2012-06-15 22:02:34 +08:00
|
|
|
if (ParenLevel != 0)
|
2012-08-21 23:55:04 +08:00
|
|
|
return TokError("unbalanced parentheses in macro argument");
|
2012-06-15 22:02:34 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the macro instantiation arguments.
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
|
2013-08-20 21:33:18 +08:00
|
|
|
MCAsmMacroArguments &A) {
|
2012-06-15 22:02:34 +08:00
|
|
|
const unsigned NParameters = M ? M->Parameters.size() : 0;
|
2014-02-19 11:00:29 +08:00
|
|
|
bool NamedParametersFound = false;
|
|
|
|
SmallVector<SMLoc, 4> FALocs;
|
2012-06-15 22:02:34 +08:00
|
|
|
|
2014-02-17 08:40:17 +08:00
|
|
|
A.resize(NParameters);
|
2014-02-19 11:00:29 +08:00
|
|
|
FALocs.resize(NParameters);
|
2014-02-17 08:40:17 +08:00
|
|
|
|
2012-06-15 22:02:34 +08:00
|
|
|
// 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
|
2014-04-23 14:56:28 +08:00
|
|
|
bool HasVararg = NParameters ? M->Parameters.back().Vararg : false;
|
2012-06-15 22:02:34 +08:00
|
|
|
for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;
|
|
|
|
++Parameter) {
|
2014-02-19 11:00:29 +08:00
|
|
|
SMLoc IDLoc = Lexer.getLoc();
|
2014-02-17 08:40:17 +08:00
|
|
|
MCAsmMacroParameter FA;
|
|
|
|
|
|
|
|
if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) {
|
2016-09-17 02:30:20 +08:00
|
|
|
if (parseIdentifier(FA.Name))
|
|
|
|
return Error(IDLoc, "invalid argument identifier for formal argument");
|
|
|
|
|
|
|
|
if (Lexer.isNot(AsmToken::Equal))
|
|
|
|
return TokError("expected '=' after formal parameter identifier");
|
2014-02-17 08:40:17 +08:00
|
|
|
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
NamedParametersFound = true;
|
|
|
|
}
|
2012-06-15 22:02:34 +08:00
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
if (NamedParametersFound && FA.Name.empty())
|
|
|
|
return Error(IDLoc, "cannot mix positional and keyword arguments");
|
2012-06-15 22:02:34 +08:00
|
|
|
|
2014-04-23 14:56:28 +08:00
|
|
|
bool Vararg = HasVararg && Parameter == (NParameters - 1);
|
|
|
|
if (parseMacroArgument(FA.Value, Vararg))
|
2014-02-17 08:40:17 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
unsigned PI = Parameter;
|
2014-02-19 11:00:23 +08:00
|
|
|
if (!FA.Name.empty()) {
|
2014-02-17 08:40:17 +08:00
|
|
|
unsigned FAI = 0;
|
|
|
|
for (FAI = 0; FAI < NParameters; ++FAI)
|
2014-02-19 11:00:23 +08:00
|
|
|
if (M->Parameters[FAI].Name == FA.Name)
|
2014-02-17 08:40:17 +08:00
|
|
|
break;
|
2014-02-19 11:00:29 +08:00
|
|
|
|
2014-02-17 08:40:17 +08:00
|
|
|
if (FAI >= NParameters) {
|
2016-06-18 00:06:17 +08:00
|
|
|
assert(M && "expected macro to be defined");
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(IDLoc, "parameter named '" + FA.Name +
|
|
|
|
"' does not exist for macro '" + M->Name + "'");
|
2014-02-17 08:40:17 +08:00
|
|
|
}
|
|
|
|
PI = FAI;
|
|
|
|
}
|
|
|
|
|
2014-02-19 11:00:23 +08:00
|
|
|
if (!FA.Value.empty()) {
|
2014-02-17 08:40:17 +08:00
|
|
|
if (A.size() <= PI)
|
|
|
|
A.resize(PI + 1);
|
2014-02-19 11:00:23 +08:00
|
|
|
A[PI] = FA.Value;
|
2014-02-19 11:00:29 +08:00
|
|
|
|
|
|
|
if (FALocs.size() <= PI)
|
|
|
|
FALocs.resize(PI + 1);
|
|
|
|
|
|
|
|
FALocs[PI] = Lexer.getLoc();
|
2012-09-20 04:29:04 +08:00
|
|
|
}
|
2012-07-31 06:44:17 +08:00
|
|
|
|
2012-09-20 04:29:04 +08:00
|
|
|
// 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
|
2014-02-19 11:00:29 +08:00
|
|
|
if (Lexer.is(AsmToken::EndOfStatement)) {
|
|
|
|
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 Failure;
|
|
|
|
}
|
2012-06-15 22:02:34 +08:00
|
|
|
|
|
|
|
if (Lexer.is(AsmToken::Comma))
|
|
|
|
Lex();
|
|
|
|
}
|
2014-02-17 08:40:17 +08:00
|
|
|
|
|
|
|
return TokError("too many positional arguments");
|
2012-06-15 22:02:34 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
const MCAsmMacro *AsmParser::lookupMacro(StringRef Name) {
|
2014-10-04 02:32:55 +08:00
|
|
|
StringMap<MCAsmMacro>::iterator I = MacroMap.find(Name);
|
|
|
|
return (I == MacroMap.end()) ? nullptr : &I->getValue();
|
2013-01-15 07:22:36 +08:00
|
|
|
}
|
|
|
|
|
2014-10-04 02:32:55 +08:00
|
|
|
void AsmParser::defineMacro(StringRef Name, MCAsmMacro Macro) {
|
|
|
|
MacroMap.insert(std::make_pair(Name, std::move(Macro)));
|
2013-01-15 07:22:36 +08:00
|
|
|
}
|
|
|
|
|
2014-10-04 02:32:55 +08:00
|
|
|
void AsmParser::undefineMacro(StringRef Name) { MacroMap.erase(Name); }
|
2013-01-15 07:22:36 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) {
|
2016-07-27 13:51:56 +08:00
|
|
|
// Arbitrarily limit macro nesting depth (default matches 'as'). We can
|
|
|
|
// eliminate this, although we should protect against infinite loops.
|
|
|
|
unsigned MaxNestingDepth = AsmMacroMaxNestingDepth;
|
|
|
|
if (ActiveMacros.size() == MaxNestingDepth) {
|
|
|
|
std::ostringstream MaxNestingDepthError;
|
|
|
|
MaxNestingDepthError << "macros cannot be nested more than "
|
|
|
|
<< MaxNestingDepth << " levels deep."
|
|
|
|
<< " Use -asm-macro-max-nesting-depth to increase "
|
|
|
|
"this limit.";
|
|
|
|
return TokError(MaxNestingDepthError.str());
|
|
|
|
}
|
2012-06-15 22:02:34 +08:00
|
|
|
|
2013-01-15 07:22:36 +08:00
|
|
|
MCAsmMacroArguments A;
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parseMacroArguments(M, A))
|
2012-06-15 22:02:34 +08:00
|
|
|
return true;
|
2010-07-19 02:54:11 +08:00
|
|
|
|
2011-06-05 10:43:45 +08:00
|
|
|
// Macro instantiation is lexical, unfortunately. We construct a new buffer
|
|
|
|
// to hold the macro body with substitutions.
|
|
|
|
SmallString<256> Buf;
|
|
|
|
StringRef Body = M->Body;
|
2012-06-04 07:57:14 +08:00
|
|
|
raw_svector_ostream OS(Buf);
|
2011-06-05 10:43:45 +08:00
|
|
|
|
2015-04-27 18:50:29 +08:00
|
|
|
if (expandMacro(OS, Body, M->Parameters, A, true, getTok().getLoc()))
|
2011-06-05 10:43:45 +08:00
|
|
|
return true;
|
|
|
|
|
2013-01-15 07:22:36 +08:00
|
|
|
// We include the .endmacro in the buffer as our cue to exit the macro
|
2012-06-04 07:57:14 +08:00
|
|
|
// instantiation.
|
|
|
|
OS << ".endmacro\n";
|
|
|
|
|
2014-08-28 04:03:13 +08:00
|
|
|
std::unique_ptr<MemoryBuffer> Instantiation =
|
|
|
|
MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
|
2011-06-05 10:43:45 +08:00
|
|
|
|
2010-07-19 02:54:11 +08:00
|
|
|
// Create the macro instantiation object and add to the current macro
|
|
|
|
// instantiation stack.
|
2014-08-28 03:49:03 +08:00
|
|
|
MacroInstantiation *MI = new MacroInstantiation(
|
|
|
|
NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size());
|
2010-07-19 02:54:11 +08:00
|
|
|
ActiveMacros.push_back(MI);
|
|
|
|
|
2015-04-27 18:50:29 +08:00
|
|
|
++NumOfMacroInstantiations;
|
|
|
|
|
2010-07-19 02:54:11 +08:00
|
|
|
// Jump to the macro instantiation and prime the lexer.
|
2014-08-22 04:44:56 +08:00
|
|
|
CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
|
2014-07-06 22:17:29 +08:00
|
|
|
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
|
2010-07-19 02:54:11 +08:00
|
|
|
Lex();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
void AsmParser::handleMacroExit() {
|
2010-07-19 02:54:11 +08:00
|
|
|
// Jump to the EndOfStatement we should return to, and consume it.
|
2013-09-21 07:08:21 +08:00
|
|
|
jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer);
|
2010-07-19 02:54:11 +08:00
|
|
|
Lex();
|
|
|
|
|
|
|
|
// Pop the instantiation entry.
|
|
|
|
delete ActiveMacros.back();
|
|
|
|
ActiveMacros.pop_back();
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseAssignment(StringRef Name, bool allow_redef,
|
2012-09-14 07:11:31 +08:00
|
|
|
bool NoDeadStrip) {
|
2015-06-23 03:35:57 +08:00
|
|
|
MCSymbol *Sym;
|
2009-08-31 16:09:28 +08:00
|
|
|
const MCExpr *Value;
|
2015-06-23 03:35:57 +08:00
|
|
|
if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym,
|
|
|
|
Value))
|
2009-06-26 05:56:11 +08:00
|
|
|
return true;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2015-06-23 03:35:57 +08:00
|
|
|
if (!Sym) {
|
|
|
|
// In the case where we parse an expression starting with a '.', we will
|
|
|
|
// not generate an error, nor will we create a symbol. In this case we
|
|
|
|
// should just return out.
|
2014-02-18 04:48:32 +08:00
|
|
|
return false;
|
2015-06-23 03:35:57 +08:00
|
|
|
}
|
2014-12-24 18:27:50 +08:00
|
|
|
|
2009-06-30 07:43:14 +08:00
|
|
|
// Do the assignment.
|
2009-08-31 16:09:09 +08:00
|
|
|
Out.EmitAssignment(Sym, Value);
|
2012-09-14 07:11:31 +08:00
|
|
|
if (NoDeadStrip)
|
|
|
|
Out.EmitSymbolAttribute(Sym, MCSA_NoDeadStrip);
|
|
|
|
|
2009-06-26 05:56:11 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
/// parseIdentifier:
|
2009-08-01 08:48:30 +08:00
|
|
|
/// ::= identifier
|
|
|
|
/// ::= string
|
2013-02-21 06:21:35 +08:00
|
|
|
bool AsmParser::parseIdentifier(StringRef &Res) {
|
2010-08-25 02:12:12 +08:00
|
|
|
// The assembler has relaxed rules for accepting identifiers, in particular we
|
2013-10-19 04:46:28 +08:00
|
|
|
// 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)
|
2010-08-25 02:12:12 +08:00
|
|
|
// handle this as a context dependent token, instead we detect adjacent tokens
|
|
|
|
// and return the combined identifier.
|
2013-10-19 04:46:28 +08:00
|
|
|
if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {
|
|
|
|
SMLoc PrefixLoc = getLexer().getLoc();
|
2010-08-25 02:12:12 +08:00
|
|
|
|
2013-10-19 04:46:28 +08:00
|
|
|
// Consume the prefix character, and check for a following identifier.
|
2016-10-12 21:58:07 +08:00
|
|
|
|
|
|
|
AsmToken Buf[1];
|
|
|
|
Lexer.peekTokens(Buf, false);
|
|
|
|
|
|
|
|
if (Buf[0].isNot(AsmToken::Identifier))
|
2010-08-25 02:12:12 +08:00
|
|
|
return true;
|
|
|
|
|
2013-10-19 04:46:28 +08:00
|
|
|
// We have a '$' or '@' followed by an identifier, make sure they are adjacent.
|
2016-10-12 21:58:07 +08:00
|
|
|
if (PrefixLoc.getPointer() + 1 != Buf[0].getLoc().getPointer())
|
2010-08-25 02:12:12 +08:00
|
|
|
return true;
|
|
|
|
|
2016-10-12 21:58:07 +08:00
|
|
|
// eat $ or @
|
|
|
|
Lexer.Lex(); // Lexer's Lex guarantees consecutive token.
|
2010-08-25 02:12:12 +08:00
|
|
|
// Construct the joined identifier and consume the token.
|
2013-09-21 07:08:21 +08:00
|
|
|
Res =
|
2013-10-19 04:46:28 +08:00
|
|
|
StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1);
|
2016-06-18 00:06:17 +08:00
|
|
|
Lex(); // Parser Lex to maintain invariants.
|
2010-08-25 02:12:12 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String))
|
2009-08-01 08:48:30 +08:00
|
|
|
return true;
|
|
|
|
|
2010-01-20 05:44:56 +08:00
|
|
|
Res = getTok().getIdentifier();
|
2009-08-01 08:48:30 +08:00
|
|
|
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex(); // Consume the identifier token.
|
2009-08-01 08:48:30 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveSet:
|
2011-01-28 11:04:41 +08:00
|
|
|
/// ::= .equ identifier ',' expression
|
|
|
|
/// ::= .equiv identifier ',' expression
|
2009-06-26 05:56:11 +08:00
|
|
|
/// ::= .set identifier ',' expression
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveSet(StringRef IDVal, bool allow_redef) {
|
2009-08-01 08:48:30 +08:00
|
|
|
StringRef Name;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (check(parseIdentifier(Name), "expected identifier") ||
|
|
|
|
parseToken(AsmToken::Comma) || parseAssignment(Name, allow_redef, true))
|
|
|
|
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
|
|
|
|
return false;
|
2009-06-26 05:56:11 +08:00
|
|
|
}
|
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
bool AsmParser::parseEscapedString(std::string &Data) {
|
2016-10-24 22:35:29 +08:00
|
|
|
if (check(getTok().isNot(AsmToken::String), "expected string"))
|
|
|
|
return true;
|
2009-08-15 02:19:52 +08:00
|
|
|
|
|
|
|
Data = "";
|
2010-01-20 05:44:56 +08:00
|
|
|
StringRef Str = getTok().getStringContents();
|
2009-08-15 02:19:52 +08:00
|
|
|
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
|
|
|
|
if (Str[i] != '\\') {
|
|
|
|
Data += Str[i];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recognize escaped characters. Note that this escape semantics currently
|
|
|
|
// loosely follows Darwin 'as'. Notably, it doesn't support hex escapes.
|
|
|
|
++i;
|
|
|
|
if (i == e)
|
|
|
|
return TokError("unexpected backslash at end of string");
|
|
|
|
|
|
|
|
// Recognize octal sequences.
|
2013-09-21 07:08:21 +08:00
|
|
|
if ((unsigned)(Str[i] - '0') <= 7) {
|
2009-08-15 02:19:52 +08:00
|
|
|
// Consume up to three octal characters.
|
|
|
|
unsigned Value = Str[i] - '0';
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {
|
2009-08-15 02:19:52 +08:00
|
|
|
++i;
|
|
|
|
Value = Value * 8 + (Str[i] - '0');
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {
|
2009-08-15 02:19:52 +08:00
|
|
|
++i;
|
|
|
|
Value = Value * 8 + (Str[i] - '0');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Value > 255)
|
|
|
|
return TokError("invalid octal escape sequence (out of range)");
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
Data += (unsigned char)Value;
|
2009-08-15 02:19:52 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise recognize individual escapes.
|
|
|
|
switch (Str[i]) {
|
|
|
|
default:
|
|
|
|
// Just reject invalid escape sequences for now.
|
|
|
|
return TokError("invalid escape sequence (unrecognized character)");
|
|
|
|
|
|
|
|
case 'b': Data += '\b'; break;
|
|
|
|
case 'f': Data += '\f'; break;
|
|
|
|
case 'n': Data += '\n'; break;
|
|
|
|
case 'r': Data += '\r'; break;
|
|
|
|
case 't': Data += '\t'; break;
|
|
|
|
case '"': Data += '"'; break;
|
|
|
|
case '\\': Data += '\\'; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
Lex();
|
2009-08-15 02:19:52 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveAscii:
|
2010-10-29 04:02:27 +08:00
|
|
|
/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {
|
2016-10-24 22:35:29 +08:00
|
|
|
auto parseOp = [&]() -> bool {
|
|
|
|
std::string Data;
|
|
|
|
if (checkForValidSection() || parseEscapedString(Data))
|
2016-10-10 23:24:54 +08:00
|
|
|
return true;
|
2016-10-24 22:35:29 +08:00
|
|
|
getStreamer().EmitBytes(Data);
|
|
|
|
if (ZeroTerminated)
|
|
|
|
getStreamer().EmitBytes(StringRef("\0", 1));
|
|
|
|
return false;
|
|
|
|
};
|
2010-09-10 06:42:59 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseMany(parseOp))
|
|
|
|
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
|
2009-06-25 07:30:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-12 21:33:00 +08:00
|
|
|
/// parseDirectiveReloc
|
|
|
|
/// ::= .reloc expression , identifier [ , expression ]
|
|
|
|
bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) {
|
|
|
|
const MCExpr *Offset;
|
|
|
|
const MCExpr *Expr = nullptr;
|
|
|
|
|
|
|
|
SMLoc OffsetLoc = Lexer.getTok().getLoc();
|
2016-10-24 22:35:29 +08:00
|
|
|
int64_t OffsetValue;
|
|
|
|
// We can only deal with constant expressions at the moment.
|
|
|
|
|
2015-11-12 21:33:00 +08:00
|
|
|
if (parseExpression(Offset))
|
|
|
|
return true;
|
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(!Offset->evaluateAsAbsolute(OffsetValue), OffsetLoc,
|
|
|
|
"expression is not a constant value") ||
|
|
|
|
check(OffsetValue < 0, OffsetLoc, "expression is negative") ||
|
|
|
|
parseToken(AsmToken::Comma, "expected comma") ||
|
|
|
|
check(getTok().isNot(AsmToken::Identifier), "expected relocation name"))
|
|
|
|
return true;
|
2015-11-12 21:33:00 +08:00
|
|
|
|
|
|
|
SMLoc NameLoc = Lexer.getTok().getLoc();
|
|
|
|
StringRef Name = Lexer.getTok().getIdentifier();
|
2016-06-18 00:06:17 +08:00
|
|
|
Lex();
|
2015-11-12 21:33:00 +08:00
|
|
|
|
|
|
|
if (Lexer.is(AsmToken::Comma)) {
|
2016-06-18 00:06:17 +08:00
|
|
|
Lex();
|
2015-11-12 21:33:00 +08:00
|
|
|
SMLoc ExprLoc = Lexer.getLoc();
|
|
|
|
if (parseExpression(Expr))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
MCValue Value;
|
|
|
|
if (!Expr->evaluateAsRelocatable(Value, nullptr, nullptr))
|
|
|
|
return Error(ExprLoc, "expression must be relocatable");
|
|
|
|
}
|
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
2016-07-19 03:35:21 +08:00
|
|
|
"unexpected token in .reloc directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc))
|
|
|
|
return Error(NameLoc, "unknown relocation name");
|
|
|
|
|
2015-11-12 21:33:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveValue
|
2009-06-25 07:30:00 +08:00
|
|
|
/// ::= (.byte | .short | ... ) [ expression (, expression)* ]
|
2016-10-24 22:35:29 +08:00
|
|
|
bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) {
|
|
|
|
auto parseOp = [&]() -> bool {
|
|
|
|
const MCExpr *Value;
|
|
|
|
SMLoc ExprLoc = getLexer().getLoc();
|
|
|
|
if (checkForValidSection() || parseExpression(Value))
|
2016-10-10 23:24:54 +08:00
|
|
|
return true;
|
2016-10-24 22:35:29 +08:00
|
|
|
// Special case constant expressions to match code generator.
|
|
|
|
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
|
|
|
|
assert(Size <= 8 && "Invalid size");
|
|
|
|
uint64_t IntValue = MCE->getValue();
|
|
|
|
if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))
|
|
|
|
return Error(ExprLoc, "out of range literal value");
|
|
|
|
getStreamer().EmitIntValue(IntValue, Size);
|
|
|
|
} else
|
|
|
|
getStreamer().EmitValue(Value, Size, ExprLoc);
|
|
|
|
return false;
|
|
|
|
};
|
2010-09-10 06:42:59 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseMany(parseOp))
|
|
|
|
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
|
2009-06-25 07:30:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-02 00:20:59 +08:00
|
|
|
/// ParseDirectiveOctaValue
|
|
|
|
/// ::= .octa [ hexconstant (, hexconstant)* ]
|
2016-10-24 22:35:29 +08:00
|
|
|
|
|
|
|
bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) {
|
|
|
|
auto parseOp = [&]() -> bool {
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection())
|
|
|
|
return true;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (getTok().isNot(AsmToken::Integer) && getTok().isNot(AsmToken::BigNum))
|
|
|
|
return TokError("unknown token in expression");
|
|
|
|
SMLoc ExprLoc = getTok().getLoc();
|
|
|
|
APInt IntValue = getTok().getAPIntVal();
|
|
|
|
uint64_t hi, lo;
|
|
|
|
Lex();
|
|
|
|
if (!IntValue.isIntN(128))
|
|
|
|
return Error(ExprLoc, "out of range literal value");
|
|
|
|
if (!IntValue.isIntN(64)) {
|
|
|
|
hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue();
|
|
|
|
lo = IntValue.getLoBits(64).getZExtValue();
|
|
|
|
} else {
|
|
|
|
hi = 0;
|
|
|
|
lo = IntValue.getZExtValue();
|
2014-02-02 00:20:59 +08:00
|
|
|
}
|
2016-10-24 22:35:29 +08:00
|
|
|
if (MAI.isLittleEndian()) {
|
|
|
|
getStreamer().EmitIntValue(lo, 8);
|
|
|
|
getStreamer().EmitIntValue(hi, 8);
|
|
|
|
} else {
|
|
|
|
getStreamer().EmitIntValue(hi, 8);
|
|
|
|
getStreamer().EmitIntValue(lo, 8);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
2014-02-02 00:20:59 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseMany(parseOp))
|
|
|
|
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
|
2014-02-02 00:20:59 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-24 03:25:15 +08:00
|
|
|
bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {
|
|
|
|
// We don't truly support arithmetic on floating point expressions, so we
|
|
|
|
// have to manually parse unary prefixes.
|
|
|
|
bool IsNeg = false;
|
|
|
|
if (getLexer().is(AsmToken::Minus)) {
|
|
|
|
Lexer.Lex();
|
|
|
|
IsNeg = true;
|
|
|
|
} else if (getLexer().is(AsmToken::Plus))
|
|
|
|
Lexer.Lex();
|
|
|
|
|
|
|
|
if (Lexer.is(AsmToken::Error))
|
|
|
|
return TokError(Lexer.getErr());
|
|
|
|
if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) &&
|
|
|
|
Lexer.isNot(AsmToken::Identifier))
|
|
|
|
return TokError("unexpected token in directive");
|
|
|
|
|
|
|
|
// Convert to an APFloat.
|
|
|
|
APFloat Value(Semantics);
|
|
|
|
StringRef IDVal = getTok().getString();
|
|
|
|
if (getLexer().is(AsmToken::Identifier)) {
|
|
|
|
if (!IDVal.compare_lower("infinity") || !IDVal.compare_lower("inf"))
|
|
|
|
Value = APFloat::getInf(Semantics);
|
|
|
|
else if (!IDVal.compare_lower("nan"))
|
|
|
|
Value = APFloat::getNaN(Semantics, false, ~0);
|
|
|
|
else
|
|
|
|
return TokError("invalid floating point literal");
|
|
|
|
} else if (Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) ==
|
|
|
|
APFloat::opInvalidOp)
|
|
|
|
return TokError("invalid floating point literal");
|
|
|
|
if (IsNeg)
|
|
|
|
Value.changeSign();
|
|
|
|
|
|
|
|
// Consume the numeric token.
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
Res = Value.bitcastToAPInt();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveRealValue
|
2010-09-24 09:59:56 +08:00
|
|
|
/// ::= (.single | .double) [ expression (, expression)* ]
|
2016-10-24 22:35:29 +08:00
|
|
|
bool AsmParser::parseDirectiveRealValue(StringRef IDVal,
|
|
|
|
const fltSemantics &Semantics) {
|
|
|
|
auto parseOp = [&]() -> bool {
|
|
|
|
APInt AsInt;
|
|
|
|
if (checkForValidSection() || parseRealValue(Semantics, AsInt))
|
2016-10-10 23:24:54 +08:00
|
|
|
return true;
|
2016-10-24 22:35:29 +08:00
|
|
|
getStreamer().EmitIntValue(AsInt.getLimitedValue(),
|
|
|
|
AsInt.getBitWidth() / 8);
|
|
|
|
return false;
|
|
|
|
};
|
2010-09-24 09:59:56 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseMany(parseOp))
|
|
|
|
return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
|
2010-09-24 09:59:56 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveZero
|
2010-09-16 23:03:59 +08:00
|
|
|
/// ::= .zero expression
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveZero() {
|
2016-05-28 13:57:48 +08:00
|
|
|
SMLoc NumBytesLoc = Lexer.getLoc();
|
|
|
|
const MCExpr *NumBytes;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseExpression(NumBytes))
|
2010-09-16 23:03:59 +08:00
|
|
|
return true;
|
|
|
|
|
2010-10-06 03:42:57 +08:00
|
|
|
int64_t Val = 0;
|
|
|
|
if (getLexer().is(AsmToken::Comma)) {
|
|
|
|
Lex();
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(Val))
|
2010-10-06 03:42:57 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.zero' directive"))
|
|
|
|
return true;
|
2016-05-28 13:57:48 +08:00
|
|
|
getStreamer().emitFill(*NumBytes, Val, NumBytesLoc);
|
2010-09-16 23:03:59 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveFill
|
2013-09-25 01:44:41 +08:00
|
|
|
/// ::= .fill expression [ , expression [ , expression ] ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveFill() {
|
2016-05-28 13:57:48 +08:00
|
|
|
SMLoc NumValuesLoc = Lexer.getLoc();
|
|
|
|
const MCExpr *NumValues;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseExpression(NumValues))
|
2009-06-25 07:30:00 +08:00
|
|
|
return true;
|
|
|
|
|
2013-09-25 01:44:41 +08:00
|
|
|
int64_t FillSize = 1;
|
|
|
|
int64_t FillExpr = 0;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2014-02-01 15:19:38 +08:00
|
|
|
SMLoc SizeLoc, ExprLoc;
|
2009-06-25 07:30:00 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseOptionalToken(AsmToken::Comma)) {
|
|
|
|
SizeLoc = getTok().getLoc();
|
|
|
|
if (parseAbsoluteExpression(FillSize))
|
2013-09-25 01:44:41 +08:00
|
|
|
return true;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseOptionalToken(AsmToken::Comma)) {
|
|
|
|
ExprLoc = getTok().getLoc();
|
|
|
|
if (parseAbsoluteExpression(FillExpr))
|
2013-09-25 01:44:41 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.fill' directive"))
|
|
|
|
return true;
|
2009-06-25 07:30:00 +08:00
|
|
|
|
2014-02-01 15:19:38 +08:00
|
|
|
if (FillSize < 0) {
|
|
|
|
Warning(SizeLoc, "'.fill' directive with negative size has no effect");
|
2016-05-28 16:20:08 +08:00
|
|
|
return false;
|
2014-02-01 15:19:38 +08:00
|
|
|
}
|
|
|
|
if (FillSize > 8) {
|
|
|
|
Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8");
|
|
|
|
FillSize = 8;
|
|
|
|
}
|
2009-06-25 07:30:00 +08:00
|
|
|
|
2014-02-01 15:19:38 +08:00
|
|
|
if (!isUInt<32>(FillExpr) && FillSize > 4)
|
|
|
|
Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits");
|
|
|
|
|
2016-05-28 13:57:48 +08:00
|
|
|
getStreamer().emitFill(*NumValues, FillSize, FillExpr, NumValuesLoc);
|
2009-06-25 07:30:00 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2009-06-26 06:44:51 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveOrg
|
2009-06-26 06:44:51 +08:00
|
|
|
/// ::= .org expression [ , expression ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveOrg() {
|
2009-08-31 16:09:28 +08:00
|
|
|
const MCExpr *Offset;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseExpression(Offset))
|
2009-06-26 06:44:51 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Parse optional fill expression.
|
|
|
|
int64_t FillExpr = 0;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseOptionalToken(AsmToken::Comma))
|
|
|
|
if (parseAbsoluteExpression(FillExpr))
|
|
|
|
return addErrorSuffix(" in '.org' directive");
|
|
|
|
if (parseToken(AsmToken::EndOfStatement))
|
|
|
|
return addErrorSuffix(" in '.org' directive");
|
2016-07-18 23:24:03 +08:00
|
|
|
|
2015-11-05 07:59:18 +08:00
|
|
|
getStreamer().emitValueToOffset(Offset, FillExpr);
|
2009-06-26 06:44:51 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-06-30 07:46:59 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveAlign
|
2009-06-30 07:46:59 +08:00
|
|
|
/// ::= {.align, ...} expression [ , expression [ , expression ]]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) {
|
2010-07-13 02:03:11 +08:00
|
|
|
SMLoc AlignmentLoc = getLexer().getLoc();
|
2009-06-30 07:46:59 +08:00
|
|
|
int64_t Alignment;
|
|
|
|
SMLoc MaxBytesLoc;
|
|
|
|
bool HasFillExpr = false;
|
|
|
|
int64_t FillExpr = 0;
|
|
|
|
int64_t MaxBytesToFill = 0;
|
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
auto parseAlign = [&]() -> bool {
|
|
|
|
if (checkForValidSection() || parseAbsoluteExpression(Alignment))
|
|
|
|
return true;
|
|
|
|
if (parseOptionalToken(AsmToken::Comma)) {
|
|
|
|
// The fill expression can be omitted while specifying a maximum number of
|
|
|
|
// alignment bytes, e.g:
|
|
|
|
// .align 3,,4
|
|
|
|
if (getTok().isNot(AsmToken::Comma)) {
|
|
|
|
HasFillExpr = true;
|
|
|
|
if (parseAbsoluteExpression(FillExpr))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (parseOptionalToken(AsmToken::Comma))
|
|
|
|
if (parseTokenLoc(MaxBytesLoc) ||
|
|
|
|
parseAbsoluteExpression(MaxBytesToFill))
|
|
|
|
return true;
|
2009-06-30 07:46:59 +08:00
|
|
|
}
|
2016-10-24 22:35:29 +08:00
|
|
|
return parseToken(AsmToken::EndOfStatement);
|
|
|
|
};
|
2009-06-30 07:46:59 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseAlign())
|
|
|
|
return addErrorSuffix(" in directive");
|
2009-06-30 07:46:59 +08:00
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
// Always emit an alignment here even if we thrown an error.
|
|
|
|
bool ReturnVal = false;
|
|
|
|
|
2009-06-30 07:46:59 +08:00
|
|
|
// Compute alignment in bytes.
|
|
|
|
if (IsPow2) {
|
|
|
|
// FIXME: Diagnose overflow.
|
2009-08-26 17:16:34 +08:00
|
|
|
if (Alignment >= 32) {
|
2016-09-17 02:30:20 +08:00
|
|
|
ReturnVal |= Error(AlignmentLoc, "invalid alignment value");
|
2009-08-26 17:16:34 +08:00
|
|
|
Alignment = 31;
|
|
|
|
}
|
|
|
|
|
2009-09-06 17:35:10 +08:00
|
|
|
Alignment = 1ULL << Alignment;
|
2013-02-16 23:00:16 +08:00
|
|
|
} else {
|
2015-09-09 02:59:47 +08:00
|
|
|
// Reject alignments that aren't either a power of two or zero,
|
|
|
|
// for gas compatibility. Alignment of zero is silently rounded
|
|
|
|
// up to one.
|
|
|
|
if (Alignment == 0)
|
|
|
|
Alignment = 1;
|
2013-02-16 23:00:16 +08:00
|
|
|
if (!isPowerOf2_64(Alignment))
|
2016-09-17 02:30:20 +08:00
|
|
|
ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2");
|
2009-06-30 07:46:59 +08:00
|
|
|
}
|
|
|
|
|
2009-08-26 17:16:34 +08:00
|
|
|
// Diagnose non-sensical max bytes to align.
|
2009-06-30 07:46:59 +08:00
|
|
|
if (MaxBytesLoc.isValid()) {
|
|
|
|
if (MaxBytesToFill < 1) {
|
2016-09-17 02:30:20 +08:00
|
|
|
ReturnVal |= Error(MaxBytesLoc,
|
|
|
|
"alignment directive can never be satisfied in this "
|
2013-09-21 07:08:21 +08:00
|
|
|
"many bytes, ignoring maximum bytes expression");
|
2009-08-22 07:01:53 +08:00
|
|
|
MaxBytesToFill = 0;
|
2009-06-30 07:46:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (MaxBytesToFill >= Alignment) {
|
2009-06-30 08:49:23 +08:00
|
|
|
Warning(MaxBytesLoc, "maximum bytes expression exceeds alignment and "
|
2013-09-21 07:08:21 +08:00
|
|
|
"has no effect");
|
2009-06-30 07:46:59 +08:00
|
|
|
MaxBytesToFill = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-18 05:54:30 +08:00
|
|
|
// Check whether we should use optimal code alignment for this .align
|
|
|
|
// directive.
|
2016-10-14 13:47:37 +08:00
|
|
|
const MCSection *Section = getStreamer().getCurrentSectionOnly();
|
2014-03-21 13:13:23 +08:00
|
|
|
assert(Section && "must have section to emit alignment");
|
|
|
|
bool UseCodeAlign = Section->UseCodeAlign();
|
2010-05-18 05:54:30 +08:00
|
|
|
if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) &&
|
|
|
|
ValueSize == 1 && UseCodeAlign) {
|
2010-07-13 02:03:11 +08:00
|
|
|
getStreamer().EmitCodeAlignment(Alignment, MaxBytesToFill);
|
2010-05-18 05:54:30 +08:00
|
|
|
} else {
|
2010-02-26 02:46:04 +08:00
|
|
|
// FIXME: Target specific behavior about how the "extra" bytes are filled.
|
2010-07-16 05:19:31 +08:00
|
|
|
getStreamer().EmitValueToAlignment(Alignment, FillExpr, ValueSize,
|
|
|
|
MaxBytesToFill);
|
2010-05-18 05:54:30 +08:00
|
|
|
}
|
2009-06-30 07:46:59 +08:00
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
return ReturnVal;
|
2012-12-21 03:05:53 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveFile
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .file [number] filename
|
|
|
|
/// ::= .file number directory filename
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
// FIXME: I'm not sure what this is.
|
|
|
|
int64_t FileNumber = -1;
|
|
|
|
SMLoc FileNumberLoc = getLexer().getLoc();
|
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
|
|
|
FileNumber = getTok().getIntVal();
|
|
|
|
Lex();
|
2012-12-21 03:05:53 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (FileNumber < 1)
|
|
|
|
return TokError("file number less than one");
|
|
|
|
}
|
2012-12-21 03:05:53 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
std::string Path = getTok().getString();
|
2012-12-21 03:05:53 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Usually the directory and filename together, otherwise just the directory.
|
2013-09-06 03:14:26 +08:00
|
|
|
// Allow the strings to have escaped octal character sequence.
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(getTok().isNot(AsmToken::String),
|
|
|
|
"unexpected token in '.file' directive") ||
|
|
|
|
parseEscapedString(Path))
|
2013-09-06 03:14:26 +08:00
|
|
|
return true;
|
2012-12-21 03:05:53 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
StringRef Directory;
|
|
|
|
StringRef Filename;
|
2013-09-06 03:14:26 +08:00
|
|
|
std::string FilenameData;
|
2013-01-16 06:59:42 +08:00
|
|
|
if (getLexer().is(AsmToken::String)) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(FileNumber == -1,
|
|
|
|
"explicit path specified, but no file number") ||
|
|
|
|
parseEscapedString(FilenameData))
|
2013-09-06 03:14:26 +08:00
|
|
|
return true;
|
|
|
|
Filename = FilenameData;
|
2013-01-16 06:59:42 +08:00
|
|
|
Directory = Path;
|
|
|
|
} else {
|
|
|
|
Filename = Path;
|
|
|
|
}
|
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.file' directive"))
|
|
|
|
return true;
|
2013-01-16 06:59:42 +08:00
|
|
|
|
|
|
|
if (FileNumber == -1)
|
|
|
|
getStreamer().EmitFileDirective(Filename);
|
|
|
|
else {
|
2016-05-26 08:22:26 +08:00
|
|
|
// If there is -g option as well as debug info from directive file,
|
|
|
|
// we turn off -g option, directly use the existing debug info instead.
|
2015-03-09 09:57:13 +08:00
|
|
|
if (getContext().getGenDwarfForAssembly())
|
2016-05-26 08:22:26 +08:00
|
|
|
getContext().setGenDwarfForAssembly(false);
|
|
|
|
else if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory, Filename) ==
|
2014-03-17 09:52:11 +08:00
|
|
|
0)
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(FileNumberLoc, "file number already allocated");
|
2013-01-16 06:59:42 +08:00
|
|
|
}
|
|
|
|
|
2012-12-21 03:05:53 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveLine
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .line [number]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveLine() {
|
2016-07-18 23:24:03 +08:00
|
|
|
int64_t LineNumber;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseIntToken(LineNumber, "unexpected token in '.line' directive"))
|
|
|
|
return true;
|
2013-09-21 07:08:21 +08:00
|
|
|
(void)LineNumber;
|
2013-01-16 06:59:42 +08:00
|
|
|
// FIXME: Do something with the .line.
|
2013-01-08 05:51:08 +08:00
|
|
|
}
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.line' directive"))
|
|
|
|
return true;
|
2012-12-21 03:05:53 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveLoc
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .loc FileNumber [LineNumber] [ColumnPos] [basic_block] [prologue_end]
|
|
|
|
/// [epilogue_begin] [is_stmt VALUE] [isa VALUE]
|
|
|
|
/// The first number is a file number, must have been previously assigned with
|
|
|
|
/// a .file directive, the second number is the line number and optionally the
|
|
|
|
/// third number is a column position (zero if not specified). The remaining
|
|
|
|
/// optional items are .loc sub-directives.
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveLoc() {
|
2016-07-18 23:24:03 +08:00
|
|
|
int64_t FileNumber = 0, LineNumber = 0;
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
|
|
|
if (parseIntToken(FileNumber, "unexpected token in '.loc' directive") ||
|
|
|
|
check(FileNumber < 1, Loc,
|
|
|
|
"file number less than one in '.loc' directive") ||
|
|
|
|
check(!getContext().isValidDwarfFileNumber(FileNumber), Loc,
|
|
|
|
"unassigned file number in '.loc' directive"))
|
|
|
|
return true;
|
2012-12-21 03:05:53 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
// optional
|
2013-01-16 06:59:42 +08:00
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
|
|
|
LineNumber = getTok().getIntVal();
|
2013-09-27 07:37:11 +08:00
|
|
|
if (LineNumber < 0)
|
|
|
|
return TokError("line number less than zero in '.loc' directive");
|
2013-01-16 06:59:42 +08:00
|
|
|
Lex();
|
|
|
|
}
|
2009-06-30 07:46:59 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t ColumnPos = 0;
|
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
|
|
|
ColumnPos = getTok().getIntVal();
|
|
|
|
if (ColumnPos < 0)
|
|
|
|
return TokError("column position less than zero in '.loc' directive");
|
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
|
|
|
|
unsigned Isa = 0;
|
|
|
|
int64_t Discriminator = 0;
|
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
auto parseLocOp = [&]() -> bool {
|
|
|
|
StringRef Name;
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
|
|
|
if (parseIdentifier(Name))
|
|
|
|
return TokError("unexpected token in '.loc' directive");
|
|
|
|
|
|
|
|
if (Name == "basic_block")
|
|
|
|
Flags |= DWARF2_FLAG_BASIC_BLOCK;
|
|
|
|
else if (Name == "prologue_end")
|
|
|
|
Flags |= DWARF2_FLAG_PROLOGUE_END;
|
|
|
|
else if (Name == "epilogue_begin")
|
|
|
|
Flags |= DWARF2_FLAG_EPILOGUE_BEGIN;
|
|
|
|
else if (Name == "is_stmt") {
|
|
|
|
Loc = getTok().getLoc();
|
|
|
|
const MCExpr *Value;
|
|
|
|
if (parseExpression(Value))
|
|
|
|
return true;
|
|
|
|
// The expression must be the constant 0 or 1.
|
|
|
|
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
|
|
|
|
int Value = MCE->getValue();
|
|
|
|
if (Value == 0)
|
|
|
|
Flags &= ~DWARF2_FLAG_IS_STMT;
|
|
|
|
else if (Value == 1)
|
|
|
|
Flags |= DWARF2_FLAG_IS_STMT;
|
|
|
|
else
|
|
|
|
return Error(Loc, "is_stmt value not 0 or 1");
|
2013-04-22 12:22:40 +08:00
|
|
|
} else {
|
2016-10-24 22:35:29 +08:00
|
|
|
return Error(Loc, "is_stmt value not the constant value of 0 or 1");
|
2013-01-16 06:59:42 +08:00
|
|
|
}
|
2016-10-24 22:35:29 +08:00
|
|
|
} else if (Name == "isa") {
|
|
|
|
Loc = getTok().getLoc();
|
|
|
|
const MCExpr *Value;
|
|
|
|
if (parseExpression(Value))
|
|
|
|
return true;
|
|
|
|
// The expression must be a constant greater or equal to 0.
|
|
|
|
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
|
|
|
|
int Value = MCE->getValue();
|
|
|
|
if (Value < 0)
|
|
|
|
return Error(Loc, "isa number less than zero");
|
|
|
|
Isa = Value;
|
|
|
|
} else {
|
|
|
|
return Error(Loc, "isa number not a constant value");
|
|
|
|
}
|
|
|
|
} else if (Name == "discriminator") {
|
|
|
|
if (parseAbsoluteExpression(Discriminator))
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return Error(Loc, "unknown sub-directive in '.loc' directive");
|
2009-06-30 08:33:19 +08:00
|
|
|
}
|
2016-10-24 22:35:29 +08:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2016-10-27 01:28:58 +08:00
|
|
|
if (parseMany(parseLocOp, false /*hasComma*/))
|
2016-10-24 22:35:29 +08:00
|
|
|
return true;
|
2009-06-30 08:33:19 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags,
|
|
|
|
Isa, Discriminator, StringRef());
|
|
|
|
|
2010-09-30 09:09:20 +08:00
|
|
|
return false;
|
2009-06-30 08:33:19 +08:00
|
|
|
}
|
2009-07-08 04:30:46 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveStabs
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .stabs string, number, number, number
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveStabs() {
|
2013-01-16 06:59:42 +08:00
|
|
|
return TokError("unsupported directive '.stabs'");
|
|
|
|
}
|
2010-09-10 06:42:59 +08:00
|
|
|
|
2016-01-29 08:49:42 +08:00
|
|
|
/// parseDirectiveCVFile
|
|
|
|
/// ::= .cv_file number filename
|
|
|
|
bool AsmParser::parseDirectiveCVFile() {
|
2016-07-18 23:24:03 +08:00
|
|
|
SMLoc FileNumberLoc = getTok().getLoc();
|
|
|
|
int64_t FileNumber;
|
2016-01-29 08:49:42 +08:00
|
|
|
std::string Filename;
|
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseIntToken(FileNumber,
|
|
|
|
"expected file number in '.cv_file' directive") ||
|
|
|
|
check(FileNumber < 1, FileNumberLoc, "file number less than one") ||
|
|
|
|
check(getTok().isNot(AsmToken::String),
|
|
|
|
"unexpected token in '.cv_file' directive") ||
|
|
|
|
// Usually directory and filename are together, otherwise just
|
|
|
|
// directory. Allow the strings to have escaped octal character sequence.
|
|
|
|
parseEscapedString(Filename) ||
|
|
|
|
parseToken(AsmToken::EndOfStatement,
|
2016-07-19 03:35:21 +08:00
|
|
|
"unexpected token in '.cv_file' directive"))
|
2016-08-27 01:58:37 +08:00
|
|
|
return true;
|
2016-07-19 03:35:21 +08:00
|
|
|
|
2016-08-27 01:58:37 +08:00
|
|
|
if (!getStreamer().EmitCVFileDirective(FileNumber, Filename))
|
2016-10-24 22:35:29 +08:00
|
|
|
return Error(FileNumberLoc, "file number already allocated");
|
2016-01-29 08:49:42 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-08 00:15:31 +08:00
|
|
|
bool AsmParser::parseCVFunctionId(int64_t &FunctionId,
|
|
|
|
StringRef DirectiveName) {
|
|
|
|
SMLoc Loc;
|
|
|
|
return parseTokenLoc(Loc) ||
|
|
|
|
parseIntToken(FunctionId, "expected function id in '" + DirectiveName +
|
|
|
|
"' directive") ||
|
|
|
|
check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc,
|
|
|
|
"expected function id within range [0, UINT_MAX)");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) {
|
|
|
|
SMLoc Loc;
|
|
|
|
return parseTokenLoc(Loc) ||
|
|
|
|
parseIntToken(FileNumber, "expected integer in '" + DirectiveName +
|
|
|
|
"' directive") ||
|
|
|
|
check(FileNumber < 1, Loc, "file number less than one in '" +
|
|
|
|
DirectiveName + "' directive") ||
|
|
|
|
check(!getCVContext().isValidFileNumber(FileNumber), Loc,
|
|
|
|
"unassigned file number in '" + DirectiveName + "' directive");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// parseDirectiveCVFuncId
|
|
|
|
/// ::= .cv_func_id FunctionId
|
|
|
|
///
|
|
|
|
/// Introduces a function ID that can be used with .cv_loc.
|
|
|
|
bool AsmParser::parseDirectiveCVFuncId() {
|
|
|
|
SMLoc FunctionIdLoc = getTok().getLoc();
|
|
|
|
int64_t FunctionId;
|
|
|
|
|
|
|
|
if (parseCVFunctionId(FunctionId, ".cv_func_id") ||
|
|
|
|
parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.cv_func_id' directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!getStreamer().EmitCVFuncIdDirective(FunctionId))
|
2016-10-24 22:35:29 +08:00
|
|
|
return Error(FunctionIdLoc, "function id already allocated");
|
2016-09-08 00:15:31 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// parseDirectiveCVInlineSiteId
|
|
|
|
/// ::= .cv_inline_site_id FunctionId
|
|
|
|
/// "within" IAFunc
|
|
|
|
/// "inlined_at" IAFile IALine [IACol]
|
|
|
|
///
|
|
|
|
/// Introduces a function ID that can be used with .cv_loc. Includes "inlined
|
|
|
|
/// at" source location information for use in the line table of the caller,
|
|
|
|
/// whether the caller is a real function or another inlined call site.
|
|
|
|
bool AsmParser::parseDirectiveCVInlineSiteId() {
|
|
|
|
SMLoc FunctionIdLoc = getTok().getLoc();
|
|
|
|
int64_t FunctionId;
|
|
|
|
int64_t IAFunc;
|
|
|
|
int64_t IAFile;
|
|
|
|
int64_t IALine;
|
|
|
|
int64_t IACol = 0;
|
|
|
|
|
|
|
|
// FunctionId
|
|
|
|
if (parseCVFunctionId(FunctionId, ".cv_inline_site_id"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// "within"
|
|
|
|
if (check((getLexer().isNot(AsmToken::Identifier) ||
|
|
|
|
getTok().getIdentifier() != "within"),
|
|
|
|
"expected 'within' identifier in '.cv_inline_site_id' directive"))
|
|
|
|
return true;
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
// IAFunc
|
|
|
|
if (parseCVFunctionId(IAFunc, ".cv_inline_site_id"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// "inlined_at"
|
|
|
|
if (check((getLexer().isNot(AsmToken::Identifier) ||
|
|
|
|
getTok().getIdentifier() != "inlined_at"),
|
|
|
|
"expected 'inlined_at' identifier in '.cv_inline_site_id' "
|
|
|
|
"directive") )
|
|
|
|
return true;
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
// IAFile IALine
|
|
|
|
if (parseCVFileId(IAFile, ".cv_inline_site_id") ||
|
|
|
|
parseIntToken(IALine, "expected line number after 'inlined_at'"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// [IACol]
|
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
|
|
|
IACol = getTok().getIntVal();
|
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.cv_inline_site_id' directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
|
|
|
|
IALine, IACol, FunctionIdLoc))
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(FunctionIdLoc, "function id already allocated");
|
2016-09-08 00:15:31 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-01-29 08:49:42 +08:00
|
|
|
/// parseDirectiveCVLoc
|
|
|
|
/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]
|
|
|
|
/// [is_stmt VALUE]
|
|
|
|
/// The first number is a file number, must have been previously assigned with
|
|
|
|
/// a .file directive, the second number is the line number and optionally the
|
|
|
|
/// third number is a column position (zero if not specified). The remaining
|
|
|
|
/// optional items are .loc sub-directives.
|
|
|
|
bool AsmParser::parseDirectiveCVLoc() {
|
2016-09-08 00:15:31 +08:00
|
|
|
SMLoc DirectiveLoc = getTok().getLoc();
|
2016-07-18 23:24:03 +08:00
|
|
|
SMLoc Loc;
|
|
|
|
int64_t FunctionId, FileNumber;
|
2016-09-08 00:15:31 +08:00
|
|
|
if (parseCVFunctionId(FunctionId, ".cv_loc") ||
|
|
|
|
parseCVFileId(FileNumber, ".cv_loc"))
|
2016-07-18 23:24:03 +08:00
|
|
|
return true;
|
2016-01-29 08:49:42 +08:00
|
|
|
|
|
|
|
int64_t LineNumber = 0;
|
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
|
|
|
LineNumber = getTok().getIntVal();
|
|
|
|
if (LineNumber < 0)
|
|
|
|
return TokError("line number less than zero in '.cv_loc' directive");
|
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t ColumnPos = 0;
|
|
|
|
if (getLexer().is(AsmToken::Integer)) {
|
|
|
|
ColumnPos = getTok().getIntVal();
|
|
|
|
if (ColumnPos < 0)
|
|
|
|
return TokError("column position less than zero in '.cv_loc' directive");
|
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PrologueEnd = false;
|
|
|
|
uint64_t IsStmt = 0;
|
2016-10-24 22:35:29 +08:00
|
|
|
|
|
|
|
auto parseOp = [&]() -> bool {
|
2016-01-29 08:49:42 +08:00
|
|
|
StringRef Name;
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
|
|
|
if (parseIdentifier(Name))
|
|
|
|
return TokError("unexpected token in '.cv_loc' directive");
|
|
|
|
if (Name == "prologue_end")
|
|
|
|
PrologueEnd = true;
|
|
|
|
else if (Name == "is_stmt") {
|
|
|
|
Loc = getTok().getLoc();
|
|
|
|
const MCExpr *Value;
|
|
|
|
if (parseExpression(Value))
|
|
|
|
return true;
|
|
|
|
// The expression must be the constant 0 or 1.
|
|
|
|
IsStmt = ~0ULL;
|
|
|
|
if (const auto *MCE = dyn_cast<MCConstantExpr>(Value))
|
|
|
|
IsStmt = MCE->getValue();
|
|
|
|
|
|
|
|
if (IsStmt > 1)
|
|
|
|
return Error(Loc, "is_stmt value not 0 or 1");
|
|
|
|
} else {
|
|
|
|
return Error(Loc, "unknown sub-directive in '.cv_loc' directive");
|
|
|
|
}
|
2016-10-24 22:35:29 +08:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (parseMany(parseOp, false /*hasComma*/))
|
|
|
|
return true;
|
2016-01-29 08:49:42 +08:00
|
|
|
|
|
|
|
getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber,
|
2016-09-08 00:15:31 +08:00
|
|
|
ColumnPos, PrologueEnd, IsStmt, StringRef(),
|
|
|
|
DirectiveLoc);
|
2016-01-29 08:49:42 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// parseDirectiveCVLinetable
|
|
|
|
/// ::= .cv_linetable FunctionId, FnStart, FnEnd
|
|
|
|
bool AsmParser::parseDirectiveCVLinetable() {
|
2016-07-18 23:24:03 +08:00
|
|
|
int64_t FunctionId;
|
|
|
|
StringRef FnStartName, FnEndName;
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
2016-09-08 00:15:31 +08:00
|
|
|
if (parseCVFunctionId(FunctionId, ".cv_linetable") ||
|
2016-07-18 23:24:03 +08:00
|
|
|
parseToken(AsmToken::Comma,
|
|
|
|
"unexpected token in '.cv_linetable' directive") ||
|
2016-08-30 22:15:43 +08:00
|
|
|
parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
|
|
|
|
"expected identifier in directive") ||
|
2016-07-18 23:24:03 +08:00
|
|
|
parseToken(AsmToken::Comma,
|
|
|
|
"unexpected token in '.cv_linetable' directive") ||
|
2016-08-30 22:15:43 +08:00
|
|
|
parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,
|
|
|
|
"expected identifier in directive"))
|
2016-07-18 23:24:03 +08:00
|
|
|
return true;
|
2016-01-29 08:49:42 +08:00
|
|
|
|
|
|
|
MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);
|
|
|
|
MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
|
|
|
|
|
|
|
|
getStreamer().EmitCVLinetableDirective(FunctionId, FnStartSym, FnEndSym);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-01-30 03:24:12 +08:00
|
|
|
/// parseDirectiveCVInlineLinetable
|
2016-02-03 03:22:34 +08:00
|
|
|
/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd
|
2016-01-30 03:24:12 +08:00
|
|
|
bool AsmParser::parseDirectiveCVInlineLinetable() {
|
2016-07-18 23:24:03 +08:00
|
|
|
int64_t PrimaryFunctionId, SourceFileId, SourceLineNum;
|
|
|
|
StringRef FnStartName, FnEndName;
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
2016-09-08 00:15:31 +08:00
|
|
|
if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") ||
|
2016-08-30 22:15:43 +08:00
|
|
|
parseTokenLoc(Loc) ||
|
2016-07-18 23:24:03 +08:00
|
|
|
parseIntToken(
|
|
|
|
SourceFileId,
|
|
|
|
"expected SourceField in '.cv_inline_linetable' directive") ||
|
|
|
|
check(SourceFileId <= 0, Loc,
|
|
|
|
"File id less than zero in '.cv_inline_linetable' directive") ||
|
2016-08-30 22:15:43 +08:00
|
|
|
parseTokenLoc(Loc) ||
|
2016-07-18 23:24:03 +08:00
|
|
|
parseIntToken(
|
|
|
|
SourceLineNum,
|
|
|
|
"expected SourceLineNum in '.cv_inline_linetable' directive") ||
|
|
|
|
check(SourceLineNum < 0, Loc,
|
|
|
|
"Line number less than zero in '.cv_inline_linetable' directive") ||
|
2016-08-30 22:15:43 +08:00
|
|
|
parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
|
|
|
|
"expected identifier in directive") ||
|
|
|
|
parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,
|
|
|
|
"expected identifier in directive"))
|
2016-07-18 23:24:03 +08:00
|
|
|
return true;
|
2016-02-03 03:22:34 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);
|
|
|
|
MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
|
2016-02-03 01:41:18 +08:00
|
|
|
getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId,
|
|
|
|
SourceLineNum, FnStartSym,
|
2016-09-08 00:15:31 +08:00
|
|
|
FnEndSym);
|
2016-01-30 03:24:12 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-02-05 09:55:49 +08:00
|
|
|
/// parseDirectiveCVDefRange
|
|
|
|
/// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes*
|
|
|
|
bool AsmParser::parseDirectiveCVDefRange() {
|
|
|
|
SMLoc Loc;
|
|
|
|
std::vector<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;
|
|
|
|
while (getLexer().is(AsmToken::Identifier)) {
|
|
|
|
Loc = getLexer().getLoc();
|
|
|
|
StringRef GapStartName;
|
|
|
|
if (parseIdentifier(GapStartName))
|
|
|
|
return Error(Loc, "expected identifier in directive");
|
|
|
|
MCSymbol *GapStartSym = getContext().getOrCreateSymbol(GapStartName);
|
|
|
|
|
|
|
|
Loc = getLexer().getLoc();
|
|
|
|
StringRef GapEndName;
|
|
|
|
if (parseIdentifier(GapEndName))
|
|
|
|
return Error(Loc, "expected identifier in directive");
|
|
|
|
MCSymbol *GapEndSym = getContext().getOrCreateSymbol(GapEndName);
|
|
|
|
|
|
|
|
Ranges.push_back({GapStartSym, GapEndSym});
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string FixedSizePortion;
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::Comma, "unexpected token in directive") ||
|
|
|
|
parseEscapedString(FixedSizePortion))
|
2016-02-05 09:55:49 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
getStreamer().EmitCVDefRangeDirective(Ranges, FixedSizePortion);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-01-29 08:49:42 +08:00
|
|
|
/// parseDirectiveCVStringTable
|
|
|
|
/// ::= .cv_stringtable
|
|
|
|
bool AsmParser::parseDirectiveCVStringTable() {
|
|
|
|
getStreamer().EmitCVStringTableDirective();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// parseDirectiveCVFileChecksums
|
|
|
|
/// ::= .cv_filechecksums
|
|
|
|
bool AsmParser::parseDirectiveCVFileChecksums() {
|
|
|
|
getStreamer().EmitCVFileChecksumsDirective();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFISections
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_sections section [, section]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFISections() {
|
2009-08-01 08:48:30 +08:00
|
|
|
StringRef Name;
|
2013-01-16 06:59:42 +08:00
|
|
|
bool EH = false;
|
|
|
|
bool Debug = false;
|
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseIdentifier(Name))
|
2013-01-16 06:59:42 +08:00
|
|
|
return TokError("Expected an identifier");
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (Name == ".eh_frame")
|
|
|
|
EH = true;
|
|
|
|
else if (Name == ".debug_frame")
|
|
|
|
Debug = true;
|
2009-07-08 04:30:46 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (getLexer().is(AsmToken::Comma)) {
|
|
|
|
Lex();
|
2009-07-08 04:30:46 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseIdentifier(Name))
|
2013-01-16 06:59:42 +08:00
|
|
|
return TokError("Expected an identifier");
|
2012-09-08 01:25:13 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (Name == ".eh_frame")
|
|
|
|
EH = true;
|
|
|
|
else if (Name == ".debug_frame")
|
|
|
|
Debug = true;
|
2009-07-08 04:30:46 +08:00
|
|
|
}
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFISections(EH, Debug);
|
|
|
|
return false;
|
|
|
|
}
|
2009-07-08 04:30:46 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIStartProc
|
2014-01-28 01:20:25 +08:00
|
|
|
/// ::= .cfi_startproc [simple]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIStartProc() {
|
2014-01-28 01:20:25 +08:00
|
|
|
StringRef Simple;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (!parseOptionalToken(AsmToken::EndOfStatement)) {
|
|
|
|
if (check(parseIdentifier(Simple) || Simple != "simple",
|
|
|
|
"unexpected token") ||
|
|
|
|
parseToken(AsmToken::EndOfStatement))
|
|
|
|
return addErrorSuffix(" in '.cfi_startproc' directive");
|
|
|
|
}
|
2016-07-18 23:24:03 +08:00
|
|
|
|
2014-11-03 20:19:03 +08:00
|
|
|
getStreamer().EmitCFIStartProc(!Simple.empty());
|
2013-01-16 06:59:42 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-07-08 04:30:46 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIEndProc
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_endproc
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIEndProc() {
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIEndProc();
|
|
|
|
return false;
|
|
|
|
}
|
2009-07-08 04:30:46 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// \brief parse register name or number.
|
|
|
|
bool AsmParser::parseRegisterOrRegisterNumber(int64_t &Register,
|
2013-01-16 06:59:42 +08:00
|
|
|
SMLoc DirectiveLoc) {
|
|
|
|
unsigned RegNo;
|
2009-07-08 04:30:46 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (getLexer().isNot(AsmToken::Integer)) {
|
|
|
|
if (getTargetParser().ParseRegister(RegNo, DirectiveLoc, DirectiveLoc))
|
|
|
|
return true;
|
2013-06-18 15:20:20 +08:00
|
|
|
Register = getContext().getRegisterInfo()->getDwarfRegNum(RegNo, true);
|
2013-01-16 06:59:42 +08:00
|
|
|
} else
|
2013-02-21 06:21:35 +08:00
|
|
|
return parseAbsoluteExpression(Register);
|
2009-07-08 04:30:46 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2009-07-11 06:20:30 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIDefCfa
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_def_cfa register, offset
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIDefCfa(SMLoc DirectiveLoc) {
|
2016-07-18 23:24:03 +08:00
|
|
|
int64_t Register = 0, Offset = 0;
|
|
|
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
|
|
|
|
parseToken(AsmToken::Comma, "unexpected token in directive") ||
|
|
|
|
parseAbsoluteExpression(Offset))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2009-07-14 07:15:14 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIDefCfa(Register, Offset);
|
2009-07-14 07:15:14 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-07-15 05:35:03 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIDefCfaOffset
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_def_cfa_offset offset
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIDefCfaOffset() {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Offset = 0;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(Offset))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIDefCfaOffset(Offset);
|
|
|
|
return false;
|
|
|
|
}
|
2009-07-15 07:21:55 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIRegister
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_register register, register
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIRegister(SMLoc DirectiveLoc) {
|
2016-07-18 23:24:03 +08:00
|
|
|
int64_t Register1 = 0, Register2 = 0;
|
|
|
|
if (parseRegisterOrRegisterNumber(Register1, DirectiveLoc) ||
|
|
|
|
parseToken(AsmToken::Comma, "unexpected token in directive") ||
|
|
|
|
parseRegisterOrRegisterNumber(Register2, DirectiveLoc))
|
2009-07-16 14:14:39 +08:00
|
|
|
return true;
|
2009-07-15 07:21:55 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIRegister(Register1, Register2);
|
2009-07-15 07:21:55 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-07-15 23:30:11 +08:00
|
|
|
|
2013-09-26 22:49:40 +08:00
|
|
|
/// parseDirectiveCFIWindowSave
|
|
|
|
/// ::= .cfi_window_save
|
|
|
|
bool AsmParser::parseDirectiveCFIWindowSave() {
|
|
|
|
getStreamer().EmitCFIWindowSave();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIAdjustCfaOffset
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_adjust_cfa_offset adjustment
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIAdjustCfaOffset() {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Adjustment = 0;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(Adjustment))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2011-12-15 05:47:48 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIAdjustCfaOffset(Adjustment);
|
|
|
|
return false;
|
|
|
|
}
|
2011-12-15 05:47:48 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIDefCfaRegister
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_def_cfa_register register
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Register = 0;
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
|
2011-12-15 05:47:48 +08:00
|
|
|
return true;
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIDefCfaRegister(Register);
|
2011-12-15 05:47:48 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIOffset
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_offset register, offset
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Register = 0;
|
|
|
|
int64_t Offset = 0;
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
|
|
|
|
parseToken(AsmToken::Comma, "unexpected token in directive") ||
|
|
|
|
parseAbsoluteExpression(Offset))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIOffset(Register, Offset);
|
2009-08-08 06:46:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIRelOffset
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_rel_offset register, offset
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIRelOffset(SMLoc DirectiveLoc) {
|
2016-07-18 23:24:03 +08:00
|
|
|
int64_t Register = 0, Offset = 0;
|
2012-05-12 19:18:42 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
|
|
|
|
parseToken(AsmToken::Comma, "unexpected token in directive") ||
|
|
|
|
parseAbsoluteExpression(Offset))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2012-05-12 19:18:42 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIRelOffset(Register, Offset);
|
2012-05-12 19:18:42 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
static bool isValidEncoding(int64_t Encoding) {
|
|
|
|
if (Encoding & ~0xff)
|
|
|
|
return false;
|
2012-05-12 19:18:51 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (Encoding == dwarf::DW_EH_PE_omit)
|
|
|
|
return true;
|
2012-05-12 19:18:51 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
const unsigned Format = Encoding & 0xf;
|
|
|
|
if (Format != dwarf::DW_EH_PE_absptr && Format != dwarf::DW_EH_PE_udata2 &&
|
|
|
|
Format != dwarf::DW_EH_PE_udata4 && Format != dwarf::DW_EH_PE_udata8 &&
|
|
|
|
Format != dwarf::DW_EH_PE_sdata2 && Format != dwarf::DW_EH_PE_sdata4 &&
|
|
|
|
Format != dwarf::DW_EH_PE_sdata8 && Format != dwarf::DW_EH_PE_signed)
|
|
|
|
return false;
|
2012-05-12 19:18:51 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
const unsigned Application = Encoding & 0x70;
|
|
|
|
if (Application != dwarf::DW_EH_PE_absptr &&
|
|
|
|
Application != dwarf::DW_EH_PE_pcrel)
|
|
|
|
return false;
|
2012-05-12 19:18:51 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-05-12 19:18:51 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIPersonalityOrLsda
|
2013-01-16 06:59:42 +08:00
|
|
|
/// IsPersonality true for cfi_personality, false for cfi_lsda
|
|
|
|
/// ::= .cfi_personality encoding, [symbol_name]
|
|
|
|
/// ::= .cfi_lsda encoding, [symbol_name]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIPersonalityOrLsda(bool IsPersonality) {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Encoding = 0;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(Encoding))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
|
|
|
if (Encoding == dwarf::DW_EH_PE_omit)
|
|
|
|
return false;
|
2012-05-12 19:18:51 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
StringRef Name;
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(!isValidEncoding(Encoding), "unsupported encoding.") ||
|
|
|
|
parseToken(AsmToken::Comma, "unexpected token in directive") ||
|
|
|
|
check(parseIdentifier(Name), "expected identifier in directive"))
|
|
|
|
return true;
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
|
2013-01-16 06:59:42 +08:00
|
|
|
|
|
|
|
if (IsPersonality)
|
|
|
|
getStreamer().EmitCFIPersonality(Sym, Encoding);
|
|
|
|
else
|
|
|
|
getStreamer().EmitCFILsda(Sym, Encoding);
|
2012-05-12 19:18:51 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIRememberState
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_remember_state
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIRememberState() {
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIRememberState();
|
|
|
|
return false;
|
|
|
|
}
|
2011-02-09 06:29:56 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIRestoreState
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_remember_state
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIRestoreState() {
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIRestoreState();
|
|
|
|
return false;
|
|
|
|
}
|
2011-02-09 06:29:56 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFISameValue
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_same_value register
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Register = 0;
|
2011-02-09 06:29:56 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2011-02-09 06:29:56 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFISameValue(Register);
|
2011-02-09 06:29:56 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIRestore
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_restore register
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Register = 0;
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIRestore(Register);
|
|
|
|
return false;
|
|
|
|
}
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIEscape
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_escape expression[,...]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIEscape() {
|
2013-01-16 06:59:42 +08:00
|
|
|
std::string Values;
|
|
|
|
int64_t CurrValue;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(CurrValue))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
Values.push_back((uint8_t)CurrValue);
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
while (getLexer().is(AsmToken::Comma)) {
|
2010-01-20 04:22:31 +08:00
|
|
|
Lex();
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(CurrValue))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
Values.push_back((uint8_t)CurrValue);
|
2009-08-08 06:46:00 +08:00
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFIEscape(Values);
|
2009-08-08 06:46:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFISignalFrame
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_signal_frame
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFISignalFrame() {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.cfi_signal_frame'"))
|
|
|
|
return true;
|
2010-10-09 19:00:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitCFISignalFrame();
|
|
|
|
return false;
|
|
|
|
}
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveCFIUndefined
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .cfi_undefined register
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Register = 0;
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
getStreamer().EmitCFIUndefined(Register);
|
2009-08-08 06:46:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveMacrosOnOff
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .macros_on
|
|
|
|
/// ::= .macros_off
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveMacrosOnOff(StringRef Directive) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '" + Directive + "' directive"))
|
|
|
|
return true;
|
2009-08-08 06:46:00 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
setMacrosEnabled(Directive == ".macros_on");
|
2009-08-08 06:46:00 +08:00
|
|
|
return false;
|
|
|
|
}
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveMacro
|
2014-02-16 12:56:31 +08:00
|
|
|
/// ::= .macro name[,] [parameters]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
StringRef Name;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseIdentifier(Name))
|
2013-01-16 06:59:42 +08:00
|
|
|
return TokError("expected identifier in '.macro' directive");
|
2013-01-11 06:44:57 +08:00
|
|
|
|
2014-02-16 12:56:31 +08:00
|
|
|
if (getLexer().is(AsmToken::Comma))
|
|
|
|
Lex();
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
MCAsmMacroParameters Parameters;
|
2014-01-30 02:57:46 +08:00
|
|
|
while (getLexer().isNot(AsmToken::EndOfStatement)) {
|
2014-04-23 14:56:28 +08:00
|
|
|
|
2015-01-15 19:41:30 +08:00
|
|
|
if (!Parameters.empty() && Parameters.back().Vararg)
|
2014-04-23 14:56:28 +08:00
|
|
|
return Error(Lexer.getLoc(),
|
|
|
|
"Vararg parameter '" + Parameters.back().Name +
|
|
|
|
"' should be last one in the list of parameters.");
|
|
|
|
|
2014-01-30 02:57:46 +08:00
|
|
|
MCAsmMacroParameter Parameter;
|
2014-02-19 11:00:23 +08:00
|
|
|
if (parseIdentifier(Parameter.Name))
|
2014-01-30 02:57:46 +08:00
|
|
|
return TokError("expected identifier in '.macro' directive");
|
2010-07-13 01:45:27 +08:00
|
|
|
|
2014-02-19 11:00:29 +08:00
|
|
|
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;
|
2014-08-05 07:14:37 +08:00
|
|
|
else if (Qualifier == "vararg")
|
2014-04-23 14:56:28 +08:00
|
|
|
Parameter.Vararg = true;
|
2014-02-19 11:00:29 +08:00
|
|
|
else
|
|
|
|
return Error(QualLoc, Qualifier + " is not a valid parameter qualifier "
|
|
|
|
"for '" + Parameter.Name + "' in macro '" + Name + "'");
|
|
|
|
}
|
|
|
|
|
2014-01-30 02:57:46 +08:00
|
|
|
if (getLexer().is(AsmToken::Equal)) {
|
|
|
|
Lex();
|
2014-02-19 11:00:29 +08:00
|
|
|
|
|
|
|
SMLoc ParamLoc;
|
|
|
|
|
|
|
|
ParamLoc = Lexer.getLoc();
|
2014-04-23 14:56:28 +08:00
|
|
|
if (parseMacroArgument(Parameter.Value, /*Vararg=*/false ))
|
2014-01-30 02:57:46 +08:00
|
|
|
return true;
|
2014-02-19 11:00:29 +08:00
|
|
|
|
|
|
|
if (Parameter.Required)
|
|
|
|
Warning(ParamLoc, "pointless default value for required parameter "
|
|
|
|
"'" + Parameter.Name + "' in macro '" + Name + "'");
|
2014-01-30 02:57:46 +08:00
|
|
|
}
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2014-10-04 02:32:55 +08:00
|
|
|
Parameters.push_back(std::move(Parameter));
|
2010-07-13 01:45:27 +08:00
|
|
|
|
2014-01-30 02:57:46 +08:00
|
|
|
if (getLexer().is(AsmToken::Comma))
|
|
|
|
Lex();
|
2013-01-16 06:59:42 +08:00
|
|
|
}
|
|
|
|
|
2016-06-03 01:15:05 +08:00
|
|
|
// Eat just the end of statement.
|
|
|
|
Lexer.Lex();
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2016-06-03 01:15:05 +08:00
|
|
|
// Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors
|
2013-01-16 06:59:42 +08:00
|
|
|
AsmToken EndToken, StartToken = getTok();
|
2014-02-10 00:22:00 +08:00
|
|
|
unsigned MacroDepth = 0;
|
2013-01-16 06:59:42 +08:00
|
|
|
// Lex the macro definition.
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2016-06-03 01:15:05 +08:00
|
|
|
// Ignore Lexing errors in macros.
|
|
|
|
while (Lexer.is(AsmToken::Error)) {
|
|
|
|
Lexer.Lex();
|
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Check whether we have reached the end of the file.
|
|
|
|
if (getLexer().is(AsmToken::Eof))
|
|
|
|
return Error(DirectiveLoc, "no matching '.endmacro' in definition");
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Otherwise, check whether we have reach the .endmacro.
|
2014-02-10 00:22:00 +08:00
|
|
|
if (getLexer().is(AsmToken::Identifier)) {
|
|
|
|
if (getTok().getIdentifier() == ".endm" ||
|
|
|
|
getTok().getIdentifier() == ".endmacro") {
|
|
|
|
if (MacroDepth == 0) { // Outermost macro.
|
|
|
|
EndToken = getTok();
|
2016-06-03 01:15:05 +08:00
|
|
|
Lexer.Lex();
|
2014-02-10 00:22:00 +08:00
|
|
|
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;
|
|
|
|
}
|
2013-01-16 06:59:42 +08:00
|
|
|
}
|
2012-01-12 02:04:47 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Otherwise, scan til the end of the statement.
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2010-07-29 04:55:35 +08:00
|
|
|
}
|
2010-07-13 01:45:27 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (lookupMacro(Name)) {
|
2013-01-16 06:59:42 +08:00
|
|
|
return Error(DirectiveLoc, "macro '" + Name + "' is already defined");
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *BodyStart = StartToken.getLoc().getPointer();
|
|
|
|
const char *BodyEnd = EndToken.getLoc().getPointer();
|
|
|
|
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
|
2013-09-21 07:08:21 +08:00
|
|
|
checkForBadMacro(DirectiveLoc, Name, Body, Parameters);
|
2014-10-04 02:32:55 +08:00
|
|
|
defineMacro(Name, MCAsmMacro(Name, Body, std::move(Parameters)));
|
2009-08-11 12:24:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// checkForBadMacro
|
2013-01-23 05:44:53 +08:00
|
|
|
///
|
|
|
|
/// 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
|
2014-01-25 01:20:08 +08:00
|
|
|
/// not support named parameters they would be ignored on the macro definition.
|
2013-01-23 05:44:53 +08:00
|
|
|
/// But to support both styles of parameters this is not possible so if a macro
|
2014-01-25 01:20:08 +08:00
|
|
|
/// definition has named parameters but does not use them and has what appears
|
2013-01-23 05:44:53 +08:00
|
|
|
/// 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
|
2014-01-25 01:20:08 +08:00
|
|
|
/// definition so the positional parameters get used if that was what was
|
2013-01-23 05:44:53 +08:00
|
|
|
/// 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.
|
2013-09-21 07:08:21 +08:00
|
|
|
void AsmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef Name,
|
2013-01-23 05:44:53 +08:00
|
|
|
StringRef Body,
|
2014-02-10 01:13:11 +08:00
|
|
|
ArrayRef<MCAsmMacroParameter> Parameters) {
|
2013-01-23 05:44:53 +08:00
|
|
|
// If this macro is not defined with named parameters the warning we are
|
|
|
|
// checking for here doesn't apply.
|
|
|
|
unsigned NParameters = Parameters.size();
|
|
|
|
if (NParameters == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool NamedParametersFound = false;
|
|
|
|
bool PositionalParametersFound = false;
|
|
|
|
|
|
|
|
// Look at the body of the macro for use of both the named parameters and what
|
|
|
|
// are likely to be positional parameters. This is what expandMacro() is
|
|
|
|
// doing when it finds the parameters in the body.
|
|
|
|
while (!Body.empty()) {
|
|
|
|
// Scan for the next possible parameter.
|
|
|
|
std::size_t End = Body.size(), Pos = 0;
|
|
|
|
for (; Pos != End; ++Pos) {
|
|
|
|
// Check for a substitution or escape.
|
|
|
|
// This macro is defined with parameters, look for \foo, \bar, etc.
|
|
|
|
if (Body[Pos] == '\\' && Pos + 1 != End)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// This macro should have parameters, but look for $0, $1, ..., $n too.
|
|
|
|
if (Body[Pos] != '$' || Pos + 1 == End)
|
|
|
|
continue;
|
|
|
|
char Next = Body[Pos + 1];
|
2013-02-13 05:21:59 +08:00
|
|
|
if (Next == '$' || Next == 'n' ||
|
|
|
|
isdigit(static_cast<unsigned char>(Next)))
|
2013-01-23 05:44:53 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we reached the end.
|
|
|
|
if (Pos == End)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (Body[Pos] == '$') {
|
2013-09-21 07:08:21 +08:00
|
|
|
switch (Body[Pos + 1]) {
|
|
|
|
// $$ => $
|
2013-01-23 05:44:53 +08:00
|
|
|
case '$':
|
|
|
|
break;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// $n => number of arguments
|
2013-01-23 05:44:53 +08:00
|
|
|
case 'n':
|
|
|
|
PositionalParametersFound = true;
|
|
|
|
break;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
// $[0-9] => argument
|
2013-01-23 05:44:53 +08:00
|
|
|
default: {
|
|
|
|
PositionalParametersFound = true;
|
|
|
|
break;
|
2013-09-21 07:08:21 +08:00
|
|
|
}
|
2013-01-23 05:44:53 +08:00
|
|
|
}
|
|
|
|
Pos += 2;
|
|
|
|
} else {
|
|
|
|
unsigned I = Pos + 1;
|
|
|
|
while (isIdentifierChar(Body[I]) && I + 1 != End)
|
|
|
|
++I;
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
const char *Begin = Body.data() + Pos + 1;
|
|
|
|
StringRef Argument(Begin, I - (Pos + 1));
|
2013-01-23 05:44:53 +08:00
|
|
|
unsigned Index = 0;
|
|
|
|
for (; Index < NParameters; ++Index)
|
2014-02-19 11:00:23 +08:00
|
|
|
if (Parameters[Index].Name == Argument)
|
2013-01-23 05:44:53 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (Index == NParameters) {
|
2013-09-21 07:08:21 +08:00
|
|
|
if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')')
|
|
|
|
Pos += 3;
|
|
|
|
else {
|
|
|
|
Pos = I;
|
|
|
|
}
|
2013-01-23 05:44:53 +08:00
|
|
|
} else {
|
|
|
|
NamedParametersFound = true;
|
|
|
|
Pos += 1 + Argument.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Update the scan point.
|
|
|
|
Body = Body.substr(Pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NamedParametersFound && PositionalParametersFound)
|
|
|
|
Warning(DirectiveLoc, "macro defined with named parameters which are not "
|
|
|
|
"used in macro body, possible positional parameter "
|
|
|
|
"found in body which will have no effect");
|
|
|
|
}
|
|
|
|
|
2014-07-25 01:08:39 +08:00
|
|
|
/// parseDirectiveExitMacro
|
|
|
|
/// ::= .exitm
|
|
|
|
bool AsmParser::parseDirectiveExitMacro(StringRef Directive) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '" + Directive + "' directive"))
|
|
|
|
return true;
|
2014-07-25 01:08:39 +08:00
|
|
|
|
|
|
|
if (!isInsideMacroInstantiation())
|
|
|
|
return TokError("unexpected '" + Directive + "' in file, "
|
|
|
|
"no current macro definition");
|
|
|
|
|
|
|
|
// Exit all conditionals that are active in the current macro.
|
|
|
|
while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) {
|
|
|
|
TheCondState = TheCondStack.back();
|
|
|
|
TheCondStack.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
handleMacroExit();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveEndMacro
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .endm
|
|
|
|
/// ::= .endmacro
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveEndMacro(StringRef Directive) {
|
2013-01-16 06:59:42 +08:00
|
|
|
if (getLexer().isNot(AsmToken::EndOfStatement))
|
|
|
|
return TokError("unexpected token in '" + Directive + "' directive");
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// If we are inside a macro instantiation, terminate the current
|
|
|
|
// instantiation.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (isInsideMacroInstantiation()) {
|
|
|
|
handleMacroExit();
|
2013-01-16 06:59:42 +08:00
|
|
|
return false;
|
2009-08-11 12:24:50 +08:00
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Otherwise, this .endmacro is a stray entry in the file; well formed
|
|
|
|
// .endmacro directives are handled during the macro definition parsing.
|
|
|
|
return TokError("unexpected '" + Directive + "' in file, "
|
2013-09-21 07:08:21 +08:00
|
|
|
"no current macro definition");
|
2013-01-16 06:59:42 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectivePurgeMacro
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .purgem
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
StringRef Name;
|
2016-07-18 23:24:03 +08:00
|
|
|
SMLoc Loc;
|
2016-08-30 22:15:43 +08:00
|
|
|
if (parseTokenLoc(Loc) ||
|
|
|
|
check(parseIdentifier(Name), Loc,
|
|
|
|
"expected identifier in '.purgem' directive") ||
|
2016-07-18 23:24:03 +08:00
|
|
|
parseToken(AsmToken::EndOfStatement,
|
2016-07-19 03:35:21 +08:00
|
|
|
"unexpected token in '.purgem' directive"))
|
2016-07-18 23:24:03 +08:00
|
|
|
return true;
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2016-07-19 03:35:21 +08:00
|
|
|
if (!lookupMacro(Name))
|
|
|
|
return Error(DirectiveLoc, "macro '" + Name + "' is not defined");
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
undefineMacro(Name);
|
2009-08-11 12:24:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveBundleAlignMode
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= {.bundle_align_mode} expression
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveBundleAlignMode() {
|
2013-01-16 06:59:42 +08:00
|
|
|
// Expect a single argument: an expression that evaluates to a constant
|
|
|
|
// in the inclusive range 0-30.
|
|
|
|
SMLoc ExprLoc = getLexer().getLoc();
|
|
|
|
int64_t AlignSizePow2;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseAbsoluteExpression(AlignSizePow2) ||
|
2016-07-18 23:24:03 +08:00
|
|
|
parseToken(AsmToken::EndOfStatement, "unexpected token after expression "
|
|
|
|
"in '.bundle_align_mode' "
|
|
|
|
"directive") ||
|
|
|
|
check(AlignSizePow2 < 0 || AlignSizePow2 > 30, ExprLoc,
|
|
|
|
"invalid bundle alignment size (expected between 0 and 30)"))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// Because of AlignSizePow2's verified range we can safely truncate it to
|
|
|
|
// unsigned.
|
|
|
|
getStreamer().EmitBundleAlignMode(static_cast<unsigned>(AlignSizePow2));
|
|
|
|
return false;
|
|
|
|
}
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveBundleLock
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= {.bundle_lock} [align_to_end]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveBundleLock() {
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection())
|
|
|
|
return true;
|
2013-01-16 06:59:42 +08:00
|
|
|
bool AlignToEnd = false;
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
StringRef Option;
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
|
|
|
const char *kInvalidOptionError =
|
|
|
|
"invalid option for '.bundle_lock' directive";
|
2009-08-11 12:24:50 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (!parseOptionalToken(AsmToken::EndOfStatement)) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(parseIdentifier(Option), Loc, kInvalidOptionError) ||
|
|
|
|
check(Option != "align_to_end", Loc, kInvalidOptionError) ||
|
2016-10-24 22:35:29 +08:00
|
|
|
parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token after '.bundle_lock' directive option"))
|
2016-07-18 23:24:03 +08:00
|
|
|
return true;
|
2013-01-16 06:59:42 +08:00
|
|
|
AlignToEnd = true;
|
2009-08-11 12:24:50 +08:00
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
getStreamer().EmitBundleLock(AlignToEnd);
|
2009-08-11 12:24:50 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveBundleLock
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= {.bundle_lock}
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveBundleUnlock() {
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() ||
|
|
|
|
parseToken(AsmToken::EndOfStatement,
|
2016-07-18 23:24:03 +08:00
|
|
|
"unexpected token in '.bundle_unlock' directive"))
|
|
|
|
return true;
|
2013-01-16 06:59:42 +08:00
|
|
|
|
|
|
|
getStreamer().EmitBundleUnlock();
|
|
|
|
return false;
|
2010-10-16 12:56:42 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveSpace
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= (.skip | .space) expression [ , expression ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveSpace(StringRef IDVal) {
|
2013-01-12 06:55:28 +08:00
|
|
|
|
2016-05-28 13:57:48 +08:00
|
|
|
SMLoc NumBytesLoc = Lexer.getLoc();
|
|
|
|
const MCExpr *NumBytes;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseExpression(NumBytes))
|
2013-01-12 06:55:28 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
int64_t FillExpr = 0;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseOptionalToken(AsmToken::Comma))
|
|
|
|
if (parseAbsoluteExpression(FillExpr))
|
|
|
|
return addErrorSuffix("in '" + Twine(IDVal) + "' directive");
|
|
|
|
if (parseToken(AsmToken::EndOfStatement))
|
|
|
|
return addErrorSuffix("in '" + Twine(IDVal) + "' directive");
|
2010-11-17 02:34:07 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0.
|
2016-05-28 13:57:48 +08:00
|
|
|
getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc);
|
2011-02-12 03:05:56 +08:00
|
|
|
|
2011-01-28 01:16:37 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-24 03:25:15 +08:00
|
|
|
/// parseDirectiveDCB
|
|
|
|
/// ::= .dcb.{b, l, w} expression, expression
|
|
|
|
bool AsmParser::parseDirectiveDCB(StringRef IDVal, unsigned Size) {
|
|
|
|
SMLoc NumValuesLoc = Lexer.getLoc();
|
|
|
|
int64_t NumValues;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseAbsoluteExpression(NumValues))
|
2016-09-24 03:25:15 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (NumValues < 0) {
|
|
|
|
Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseToken(AsmToken::Comma,
|
|
|
|
"unexpected token in '" + Twine(IDVal) + "' directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const MCExpr *Value;
|
|
|
|
SMLoc ExprLoc = getLexer().getLoc();
|
|
|
|
if (parseExpression(Value))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Special case constant expressions to match code generator.
|
|
|
|
if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
|
|
|
|
assert(Size <= 8 && "Invalid size");
|
|
|
|
uint64_t IntValue = MCE->getValue();
|
|
|
|
if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))
|
|
|
|
return Error(ExprLoc, "literal value out of range for directive");
|
|
|
|
for (uint64_t i = 0, e = NumValues; i != e; ++i)
|
|
|
|
getStreamer().EmitIntValue(IntValue, Size);
|
|
|
|
} else {
|
|
|
|
for (uint64_t i = 0, e = NumValues; i != e; ++i)
|
|
|
|
getStreamer().EmitValue(Value, Size, ExprLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '" + Twine(IDVal) + "' directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// parseDirectiveRealDCB
|
|
|
|
/// ::= .dcb.{d, s} expression, expression
|
|
|
|
bool AsmParser::parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &Semantics) {
|
|
|
|
SMLoc NumValuesLoc = Lexer.getLoc();
|
|
|
|
int64_t NumValues;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseAbsoluteExpression(NumValues))
|
2016-09-24 03:25:15 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (NumValues < 0) {
|
|
|
|
Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseToken(AsmToken::Comma,
|
|
|
|
"unexpected token in '" + Twine(IDVal) + "' directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
APInt AsInt;
|
|
|
|
if (parseRealValue(Semantics, AsInt))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '" + Twine(IDVal) + "' directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for (uint64_t i = 0, e = NumValues; i != e; ++i)
|
|
|
|
getStreamer().EmitIntValue(AsInt.getLimitedValue(),
|
|
|
|
AsInt.getBitWidth() / 8);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-24 05:53:36 +08:00
|
|
|
/// parseDirectiveDS
|
|
|
|
/// ::= .ds.{b, d, l, p, s, w, x} expression
|
|
|
|
bool AsmParser::parseDirectiveDS(StringRef IDVal, unsigned Size) {
|
|
|
|
|
|
|
|
SMLoc NumValuesLoc = Lexer.getLoc();
|
|
|
|
int64_t NumValues;
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection() || parseAbsoluteExpression(NumValues))
|
2016-09-24 05:53:36 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (NumValues < 0) {
|
|
|
|
Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '" + Twine(IDVal) + "' directive"))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
for (uint64_t i = 0, e = NumValues; i != e; ++i)
|
|
|
|
getStreamer().emitFill(Size, 0);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveLEB128
|
2015-02-20 04:24:04 +08:00
|
|
|
/// ::= (.sleb128 | .uleb128) [ expression (, expression)* ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveLEB128(bool Signed) {
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection())
|
|
|
|
return true;
|
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
auto parseOp = [&]() -> bool {
|
|
|
|
const MCExpr *Value;
|
2015-02-20 04:24:04 +08:00
|
|
|
if (parseExpression(Value))
|
|
|
|
return true;
|
|
|
|
if (Signed)
|
|
|
|
getStreamer().EmitSLEB128Value(Value);
|
|
|
|
else
|
|
|
|
getStreamer().EmitULEB128Value(Value);
|
2016-10-24 22:35:29 +08:00
|
|
|
return false;
|
|
|
|
};
|
2010-12-29 09:42:56 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseMany(parseOp))
|
|
|
|
return addErrorSuffix(" in directive");
|
2010-12-29 09:42:56 +08:00
|
|
|
|
2011-04-13 07:59:07 +08:00
|
|
|
return false;
|
2010-12-29 09:42:56 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveSymbolAttribute
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
|
2016-10-24 22:35:29 +08:00
|
|
|
auto parseOp = [&]() -> bool {
|
|
|
|
StringRef Name;
|
|
|
|
SMLoc Loc = getTok().getLoc();
|
|
|
|
if (parseIdentifier(Name))
|
|
|
|
return Error(Loc, "expected identifier");
|
|
|
|
MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
|
2010-11-17 02:34:07 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
// Assembler local symbols don't make any sense here. Complain loudly.
|
|
|
|
if (Sym->isTemporary())
|
|
|
|
return Error(Loc, "non-local symbol required");
|
2010-11-22 22:27:24 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (!getStreamer().EmitSymbolAttribute(Sym, Attr))
|
|
|
|
return Error(Loc, "unable to emit symbol attribute");
|
|
|
|
return false;
|
|
|
|
};
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseMany(parseOp))
|
|
|
|
return addErrorSuffix(" in directive");
|
2011-04-13 07:59:07 +08:00
|
|
|
return false;
|
2010-11-17 02:34:07 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveComm
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveComm(bool IsLocal) {
|
2016-10-10 23:24:54 +08:00
|
|
|
if (checkForValidSection())
|
|
|
|
return true;
|
2011-01-28 01:16:37 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
SMLoc IDLoc = getLexer().getLoc();
|
|
|
|
StringRef Name;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseIdentifier(Name))
|
2013-01-16 06:59:42 +08:00
|
|
|
return TokError("expected identifier in directive");
|
|
|
|
|
|
|
|
// Handle the identifier as the key symbol.
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
|
2010-11-17 02:34:07 +08:00
|
|
|
|
|
|
|
if (getLexer().isNot(AsmToken::Comma))
|
|
|
|
return TokError("unexpected token in directive");
|
|
|
|
Lex();
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Size;
|
|
|
|
SMLoc SizeLoc = getLexer().getLoc();
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(Size))
|
2010-11-17 02:34:07 +08:00
|
|
|
return true;
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t Pow2Alignment = 0;
|
|
|
|
SMLoc Pow2AlignmentLoc;
|
|
|
|
if (getLexer().is(AsmToken::Comma)) {
|
|
|
|
Lex();
|
|
|
|
Pow2AlignmentLoc = getLexer().getLoc();
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(Pow2Alignment))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2010-11-17 02:34:07 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType();
|
|
|
|
if (IsLocal && LCOMM == LCOMM::NoAlignment)
|
|
|
|
return Error(Pow2AlignmentLoc, "alignment not supported on this target");
|
2011-04-12 05:49:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// If this target takes alignments in bytes (not log) validate and convert.
|
|
|
|
if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) ||
|
|
|
|
(IsLocal && LCOMM == LCOMM::ByteAlignment)) {
|
|
|
|
if (!isPowerOf2_64(Pow2Alignment))
|
|
|
|
return Error(Pow2AlignmentLoc, "alignment must be a power of 2");
|
|
|
|
Pow2Alignment = Log2_64(Pow2Alignment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.comm' or '.lcomm' directive"))
|
|
|
|
return true;
|
2011-04-12 05:49:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// NOTE: a size of zero for a .comm should create a undefined symbol
|
|
|
|
// but a size of .lcomm creates a bss symbol of size zero.
|
|
|
|
if (Size < 0)
|
|
|
|
return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't "
|
2013-09-21 07:08:21 +08:00
|
|
|
"be less than zero");
|
2011-04-12 05:49:50 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
// NOTE: The alignment in the directive is a power of 2 value, the assembler
|
|
|
|
// may internally end up wanting an alignment in bytes.
|
|
|
|
// FIXME: Diagnose overflow.
|
|
|
|
if (Pow2Alignment < 0)
|
|
|
|
return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive "
|
2013-09-21 07:08:21 +08:00
|
|
|
"alignment, can't be less than zero");
|
2013-01-16 06:59:42 +08:00
|
|
|
|
|
|
|
if (!Sym->isUndefined())
|
|
|
|
return Error(IDLoc, "invalid symbol redefinition");
|
|
|
|
|
|
|
|
// Create the Symbol as a common or local common with Size and Pow2Alignment
|
|
|
|
if (IsLocal) {
|
|
|
|
getStreamer().EmitLocalCommonSymbol(Sym, Size, 1 << Pow2Alignment);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
getStreamer().EmitCommonSymbol(Sym, Size, 1 << Pow2Alignment);
|
2011-04-13 00:12:03 +08:00
|
|
|
return false;
|
2011-04-12 05:49:50 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveAbort
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .abort [... message ...]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveAbort() {
|
2013-01-16 06:59:42 +08:00
|
|
|
// FIXME: Use loc from directive.
|
|
|
|
SMLoc Loc = getLexer().getLoc();
|
2010-12-27 04:20:31 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
StringRef Str = parseStringToEndOfStatement();
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.abort' directive"))
|
|
|
|
return true;
|
2010-12-27 04:20:31 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (Str.empty())
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(Loc, ".abort detected. Assembly stopping.");
|
2013-01-16 06:59:42 +08:00
|
|
|
else
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(Loc, ".abort '" + Str + "' detected. Assembly stopping.");
|
2013-01-16 06:59:42 +08:00
|
|
|
// FIXME: Actually abort assembly here.
|
2010-12-27 04:20:31 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
return false;
|
2010-12-27 04:20:31 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveInclude
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .include "filename"
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveInclude() {
|
2013-09-06 03:14:26 +08:00
|
|
|
// Allow the strings to have escaped octal character sequence.
|
|
|
|
std::string Filename;
|
2016-07-18 23:24:03 +08:00
|
|
|
SMLoc IncludeLoc = getTok().getLoc();
|
|
|
|
|
|
|
|
if (check(getTok().isNot(AsmToken::String),
|
|
|
|
"expected string in '.include' directive") ||
|
|
|
|
parseEscapedString(Filename) ||
|
|
|
|
check(getTok().isNot(AsmToken::EndOfStatement),
|
|
|
|
"unexpected token in '.include' directive") ||
|
|
|
|
// Attempt to switch the lexer to the included file before consuming the
|
|
|
|
// end of statement to avoid losing it when we switch.
|
|
|
|
check(enterIncludeFile(Filename), IncludeLoc,
|
|
|
|
"Could not find include file '" + Filename + "'"))
|
2013-09-06 03:14:26 +08:00
|
|
|
return true;
|
2010-12-29 02:36:23 +08:00
|
|
|
|
2011-04-13 07:59:07 +08:00
|
|
|
return false;
|
2010-12-29 02:36:23 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveIncbin
|
2016-09-23 08:41:06 +08:00
|
|
|
/// ::= .incbin "filename" [ , skip [ , count ] ]
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveIncbin() {
|
2013-09-06 03:14:26 +08:00
|
|
|
// Allow the strings to have escaped octal character sequence.
|
|
|
|
std::string Filename;
|
2016-07-18 23:24:03 +08:00
|
|
|
SMLoc IncbinLoc = getTok().getLoc();
|
|
|
|
if (check(getTok().isNot(AsmToken::String),
|
|
|
|
"expected string in '.incbin' directive") ||
|
2016-09-23 08:41:06 +08:00
|
|
|
parseEscapedString(Filename))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
int64_t Skip = 0;
|
|
|
|
const MCExpr *Count = nullptr;
|
|
|
|
SMLoc SkipLoc, CountLoc;
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseOptionalToken(AsmToken::Comma)) {
|
2016-09-23 08:41:06 +08:00
|
|
|
// The skip expression can be omitted while specifying the count, e.g:
|
|
|
|
// .incbin "filename",,4
|
|
|
|
if (getTok().isNot(AsmToken::Comma)) {
|
|
|
|
if (parseTokenLoc(SkipLoc) || parseAbsoluteExpression(Skip))
|
|
|
|
return true;
|
|
|
|
}
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseOptionalToken(AsmToken::Comma)) {
|
|
|
|
CountLoc = getTok().getLoc();
|
|
|
|
if (parseExpression(Count))
|
2016-09-23 08:41:06 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
2016-07-19 03:35:21 +08:00
|
|
|
"unexpected token in '.incbin' directive"))
|
2013-09-06 03:14:26 +08:00
|
|
|
return true;
|
2016-07-19 03:35:21 +08:00
|
|
|
|
2016-09-23 08:41:06 +08:00
|
|
|
if (check(Skip < 0, SkipLoc, "skip is negative"))
|
|
|
|
return true;
|
|
|
|
|
2016-07-19 03:35:21 +08:00
|
|
|
// Attempt to process the included file.
|
2016-09-23 08:41:06 +08:00
|
|
|
if (processIncbinFile(Filename, Skip, Count, CountLoc))
|
2016-07-19 03:35:21 +08:00
|
|
|
return Error(IncbinLoc, "Could not find incbin file '" + Filename + "'");
|
2011-12-30 05:43:03 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveIf
|
2014-06-19 04:57:28 +08:00
|
|
|
/// ::= .if{,eq,ge,gt,le,lt,ne} expression
|
|
|
|
bool AsmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) {
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondStack.push_back(TheCondState);
|
|
|
|
TheCondState.TheCond = AsmCond::IfCond;
|
|
|
|
if (TheCondState.Ignore) {
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2013-01-16 06:59:42 +08:00
|
|
|
} else {
|
|
|
|
int64_t ExprValue;
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseAbsoluteExpression(ExprValue) ||
|
|
|
|
parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.if' directive"))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2011-12-30 04:24:47 +08:00
|
|
|
|
2014-06-19 04:57:28 +08:00
|
|
|
switch (DirKind) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unsupported directive");
|
|
|
|
case DK_IF:
|
|
|
|
case DK_IFNE:
|
|
|
|
break;
|
|
|
|
case DK_IFEQ:
|
|
|
|
ExprValue = ExprValue == 0;
|
|
|
|
break;
|
|
|
|
case DK_IFGE:
|
|
|
|
ExprValue = ExprValue >= 0;
|
|
|
|
break;
|
|
|
|
case DK_IFGT:
|
|
|
|
ExprValue = ExprValue > 0;
|
|
|
|
break;
|
|
|
|
case DK_IFLE:
|
|
|
|
ExprValue = ExprValue <= 0;
|
|
|
|
break;
|
|
|
|
case DK_IFLT:
|
|
|
|
ExprValue = ExprValue < 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondState.CondMet = ExprValue;
|
|
|
|
TheCondState.Ignore = !TheCondState.CondMet;
|
2011-12-30 04:24:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveIfb
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .ifb string
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) {
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondStack.push_back(TheCondState);
|
|
|
|
TheCondState.TheCond = AsmCond::IfCond;
|
2012-01-24 05:51:52 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (TheCondState.Ignore) {
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2013-01-16 06:59:42 +08:00
|
|
|
} else {
|
2013-02-21 06:21:35 +08:00
|
|
|
StringRef Str = parseStringToEndOfStatement();
|
2012-01-24 05:51:52 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.ifb' directive"))
|
|
|
|
return true;
|
2012-11-24 00:59:41 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondState.CondMet = ExpectBlank == Str.empty();
|
|
|
|
TheCondState.Ignore = !TheCondState.CondMet;
|
|
|
|
}
|
2012-11-24 00:59:41 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveIfc
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .ifc string1, string2
|
2014-02-23 23:53:36 +08:00
|
|
|
/// ::= .ifnc string1, string2
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) {
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondStack.push_back(TheCondState);
|
|
|
|
TheCondState.TheCond = AsmCond::IfCond;
|
2012-11-25 23:14:49 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (TheCondState.Ignore) {
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2013-01-16 06:59:42 +08:00
|
|
|
} else {
|
2013-09-21 07:08:21 +08:00
|
|
|
StringRef Str1 = parseStringToComma();
|
2012-11-25 23:14:49 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::Comma, "unexpected token in '.ifc' directive"))
|
|
|
|
return true;
|
2012-11-25 23:14:49 +08:00
|
|
|
|
2013-02-21 06:21:35 +08:00
|
|
|
StringRef Str2 = parseStringToEndOfStatement();
|
2012-11-25 23:14:49 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.ifc' directive"))
|
|
|
|
return true;
|
2010-07-19 02:38:02 +08:00
|
|
|
|
2014-02-23 23:53:36 +08:00
|
|
|
TheCondState.CondMet = ExpectEqual == (Str1.trim() == Str2.trim());
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondState.Ignore = !TheCondState.CondMet;
|
|
|
|
}
|
2010-07-19 02:38:02 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2010-07-17 10:26:10 +08:00
|
|
|
|
2014-02-24 07:02:18 +08:00
|
|
|
/// parseDirectiveIfeqs
|
|
|
|
/// ::= .ifeqs string1, string2
|
2015-03-18 22:20:54 +08:00
|
|
|
bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) {
|
2014-02-24 07:02:18 +08:00
|
|
|
if (Lexer.isNot(AsmToken::String)) {
|
2015-03-18 22:20:54 +08:00
|
|
|
if (ExpectEqual)
|
2016-09-17 02:30:20 +08:00
|
|
|
return TokError("expected string parameter for '.ifeqs' directive");
|
|
|
|
return TokError("expected string parameter for '.ifnes' directive");
|
2014-02-24 07:02:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef String1 = getTok().getStringContents();
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
if (Lexer.isNot(AsmToken::Comma)) {
|
2015-03-18 22:20:54 +08:00
|
|
|
if (ExpectEqual)
|
2016-09-17 02:30:20 +08:00
|
|
|
return TokError(
|
|
|
|
"expected comma after first string for '.ifeqs' directive");
|
|
|
|
return TokError("expected comma after first string for '.ifnes' directive");
|
2014-02-24 07:02:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
if (Lexer.isNot(AsmToken::String)) {
|
2015-03-18 22:20:54 +08:00
|
|
|
if (ExpectEqual)
|
2016-09-17 02:30:20 +08:00
|
|
|
return TokError("expected string parameter for '.ifeqs' directive");
|
|
|
|
return TokError("expected string parameter for '.ifnes' directive");
|
2014-02-24 07:02:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef String2 = getTok().getStringContents();
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
TheCondStack.push_back(TheCondState);
|
|
|
|
TheCondState.TheCond = AsmCond::IfCond;
|
2015-03-18 22:20:54 +08:00
|
|
|
TheCondState.CondMet = ExpectEqual == (String1 == String2);
|
2014-02-24 07:02:18 +08:00
|
|
|
TheCondState.Ignore = !TheCondState.CondMet;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveIfdef
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .ifdef symbol
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) {
|
2010-07-19 02:47:21 +08:00
|
|
|
StringRef Name;
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondStack.push_back(TheCondState);
|
|
|
|
TheCondState.TheCond = AsmCond::IfCond;
|
2010-07-19 02:47:21 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (TheCondState.Ignore) {
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2013-01-16 06:59:42 +08:00
|
|
|
} else {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(parseIdentifier(Name), "expected identifier after '.ifdef'") ||
|
|
|
|
parseToken(AsmToken::EndOfStatement, "unexpected token in '.ifdef'"))
|
|
|
|
return true;
|
2012-09-20 04:29:04 +08:00
|
|
|
|
2015-05-19 02:43:14 +08:00
|
|
|
MCSymbol *Sym = getContext().lookupSymbol(Name);
|
2011-06-05 10:43:45 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (expect_defined)
|
2014-04-24 14:44:33 +08:00
|
|
|
TheCondState.CondMet = (Sym && !Sym->isUndefined());
|
2013-01-16 06:59:42 +08:00
|
|
|
else
|
2014-04-24 14:44:33 +08:00
|
|
|
TheCondState.CondMet = (!Sym || Sym->isUndefined());
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondState.Ignore = !TheCondState.CondMet;
|
2011-06-05 10:43:45 +08:00
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
return false;
|
|
|
|
}
|
2010-07-19 02:47:21 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveElseIf
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .elseif expression
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) {
|
2013-01-16 06:59:42 +08:00
|
|
|
if (TheCondState.TheCond != AsmCond::IfCond &&
|
|
|
|
TheCondState.TheCond != AsmCond::ElseIfCond)
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an"
|
|
|
|
" .if or an .elseif");
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondState.TheCond = AsmCond::ElseIfCond;
|
2010-07-19 02:47:21 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
bool LastIgnoreState = false;
|
|
|
|
if (!TheCondStack.empty())
|
2013-04-22 12:24:02 +08:00
|
|
|
LastIgnoreState = TheCondStack.back().Ignore;
|
2013-01-16 06:59:42 +08:00
|
|
|
if (LastIgnoreState || TheCondState.CondMet) {
|
|
|
|
TheCondState.Ignore = true;
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2013-04-22 12:22:40 +08:00
|
|
|
} else {
|
2013-01-16 06:59:42 +08:00
|
|
|
int64_t ExprValue;
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseAbsoluteExpression(ExprValue))
|
2013-01-16 06:59:42 +08:00
|
|
|
return true;
|
2010-07-19 02:47:21 +08:00
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.elseif' directive"))
|
|
|
|
return true;
|
2013-01-16 06:59:42 +08:00
|
|
|
|
|
|
|
TheCondState.CondMet = ExprValue;
|
|
|
|
TheCondState.Ignore = !TheCondState.CondMet;
|
2010-07-19 02:47:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveElse
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .else
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveElse(SMLoc DirectiveLoc) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.else' directive"))
|
|
|
|
return true;
|
2012-05-12 19:21:46 +08:00
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
if (TheCondState.TheCond != AsmCond::IfCond &&
|
|
|
|
TheCondState.TheCond != AsmCond::ElseIfCond)
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(DirectiveLoc, "Encountered a .else that doesn't follow "
|
|
|
|
" an .if or an .elseif");
|
2013-01-16 06:59:42 +08:00
|
|
|
TheCondState.TheCond = AsmCond::ElseCond;
|
|
|
|
bool LastIgnoreState = false;
|
|
|
|
if (!TheCondStack.empty())
|
|
|
|
LastIgnoreState = TheCondStack.back().Ignore;
|
|
|
|
if (LastIgnoreState || TheCondState.CondMet)
|
|
|
|
TheCondState.Ignore = true;
|
|
|
|
else
|
|
|
|
TheCondState.Ignore = false;
|
2012-05-12 19:21:46 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-12-18 10:53:03 +08:00
|
|
|
/// parseDirectiveEnd
|
|
|
|
/// ::= .end
|
|
|
|
bool AsmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.end' directive"))
|
|
|
|
return true;
|
2013-12-18 10:53:03 +08:00
|
|
|
|
|
|
|
while (Lexer.isNot(AsmToken::Eof))
|
2016-10-24 22:35:29 +08:00
|
|
|
Lexer.Lex();
|
2013-12-18 10:53:03 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-02-24 07:02:23 +08:00
|
|
|
/// parseDirectiveError
|
|
|
|
/// ::= .err
|
|
|
|
/// ::= .error [string]
|
|
|
|
bool AsmParser::parseDirectiveError(SMLoc L, bool WithMessage) {
|
|
|
|
if (!TheCondStack.empty()) {
|
|
|
|
if (TheCondStack.back().Ignore) {
|
|
|
|
eatToEndOfStatement();
|
2014-02-23 23:53:30 +08:00
|
|
|
return false;
|
2014-02-24 07:02:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WithMessage)
|
|
|
|
return Error(L, ".err encountered");
|
|
|
|
|
|
|
|
StringRef Message = ".error directive invoked in source file";
|
|
|
|
if (Lexer.isNot(AsmToken::EndOfStatement)) {
|
2016-09-17 02:30:20 +08:00
|
|
|
if (Lexer.isNot(AsmToken::String))
|
|
|
|
return TokError(".error argument must be a string");
|
2014-02-24 07:02:23 +08:00
|
|
|
|
|
|
|
Message = getTok().getStringContents();
|
|
|
|
Lex();
|
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(L, Message);
|
2014-02-23 23:53:30 +08:00
|
|
|
}
|
|
|
|
|
2014-07-25 00:26:06 +08:00
|
|
|
/// parseDirectiveWarning
|
|
|
|
/// ::= .warning [string]
|
|
|
|
bool AsmParser::parseDirectiveWarning(SMLoc L) {
|
|
|
|
if (!TheCondStack.empty()) {
|
|
|
|
if (TheCondStack.back().Ignore) {
|
|
|
|
eatToEndOfStatement();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef Message = ".warning directive invoked in source file";
|
2016-10-24 22:35:29 +08:00
|
|
|
|
|
|
|
if (!parseOptionalToken(AsmToken::EndOfStatement)) {
|
2016-09-17 02:30:20 +08:00
|
|
|
if (Lexer.isNot(AsmToken::String))
|
|
|
|
return TokError(".warning argument must be a string");
|
2014-07-25 00:26:06 +08:00
|
|
|
|
|
|
|
Message = getTok().getStringContents();
|
|
|
|
Lex();
|
2016-10-24 22:35:29 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"expected end of statement in '.warning' directive"))
|
|
|
|
return true;
|
2014-07-25 00:26:06 +08:00
|
|
|
}
|
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
return Warning(L, Message);
|
2014-07-25 00:26:06 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveEndIf
|
2013-01-16 06:59:42 +08:00
|
|
|
/// ::= .endif
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '.endif' directive"))
|
|
|
|
return true;
|
2013-01-16 06:59:42 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty())
|
2016-09-17 02:30:20 +08:00
|
|
|
return Error(DirectiveLoc, "Encountered a .endif that doesn't follow "
|
|
|
|
"an .if or .else");
|
2013-01-16 06:59:42 +08:00
|
|
|
if (!TheCondStack.empty()) {
|
|
|
|
TheCondState = TheCondStack.back();
|
|
|
|
TheCondStack.pop_back();
|
|
|
|
}
|
2010-11-03 01:22:24 +08:00
|
|
|
|
2010-09-12 00:45:15 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-01-16 06:59:42 +08:00
|
|
|
void AsmParser::initializeDirectiveKindMap() {
|
|
|
|
DirectiveKindMap[".set"] = DK_SET;
|
|
|
|
DirectiveKindMap[".equ"] = DK_EQU;
|
|
|
|
DirectiveKindMap[".equiv"] = DK_EQUIV;
|
|
|
|
DirectiveKindMap[".ascii"] = DK_ASCII;
|
|
|
|
DirectiveKindMap[".asciz"] = DK_ASCIZ;
|
|
|
|
DirectiveKindMap[".string"] = DK_STRING;
|
|
|
|
DirectiveKindMap[".byte"] = DK_BYTE;
|
|
|
|
DirectiveKindMap[".short"] = DK_SHORT;
|
|
|
|
DirectiveKindMap[".value"] = DK_VALUE;
|
|
|
|
DirectiveKindMap[".2byte"] = DK_2BYTE;
|
|
|
|
DirectiveKindMap[".long"] = DK_LONG;
|
|
|
|
DirectiveKindMap[".int"] = DK_INT;
|
|
|
|
DirectiveKindMap[".4byte"] = DK_4BYTE;
|
|
|
|
DirectiveKindMap[".quad"] = DK_QUAD;
|
|
|
|
DirectiveKindMap[".8byte"] = DK_8BYTE;
|
2014-02-02 00:20:59 +08:00
|
|
|
DirectiveKindMap[".octa"] = DK_OCTA;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".single"] = DK_SINGLE;
|
|
|
|
DirectiveKindMap[".float"] = DK_FLOAT;
|
|
|
|
DirectiveKindMap[".double"] = DK_DOUBLE;
|
|
|
|
DirectiveKindMap[".align"] = DK_ALIGN;
|
|
|
|
DirectiveKindMap[".align32"] = DK_ALIGN32;
|
|
|
|
DirectiveKindMap[".balign"] = DK_BALIGN;
|
|
|
|
DirectiveKindMap[".balignw"] = DK_BALIGNW;
|
|
|
|
DirectiveKindMap[".balignl"] = DK_BALIGNL;
|
|
|
|
DirectiveKindMap[".p2align"] = DK_P2ALIGN;
|
|
|
|
DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW;
|
|
|
|
DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL;
|
|
|
|
DirectiveKindMap[".org"] = DK_ORG;
|
|
|
|
DirectiveKindMap[".fill"] = DK_FILL;
|
|
|
|
DirectiveKindMap[".zero"] = DK_ZERO;
|
|
|
|
DirectiveKindMap[".extern"] = DK_EXTERN;
|
|
|
|
DirectiveKindMap[".globl"] = DK_GLOBL;
|
|
|
|
DirectiveKindMap[".global"] = DK_GLOBAL;
|
|
|
|
DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE;
|
|
|
|
DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP;
|
|
|
|
DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER;
|
|
|
|
DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN;
|
|
|
|
DirectiveKindMap[".reference"] = DK_REFERENCE;
|
|
|
|
DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION;
|
|
|
|
DirectiveKindMap[".weak_reference"] = DK_WEAK_REFERENCE;
|
|
|
|
DirectiveKindMap[".weak_def_can_be_hidden"] = DK_WEAK_DEF_CAN_BE_HIDDEN;
|
|
|
|
DirectiveKindMap[".comm"] = DK_COMM;
|
|
|
|
DirectiveKindMap[".common"] = DK_COMMON;
|
|
|
|
DirectiveKindMap[".lcomm"] = DK_LCOMM;
|
|
|
|
DirectiveKindMap[".abort"] = DK_ABORT;
|
|
|
|
DirectiveKindMap[".include"] = DK_INCLUDE;
|
|
|
|
DirectiveKindMap[".incbin"] = DK_INCBIN;
|
|
|
|
DirectiveKindMap[".code16"] = DK_CODE16;
|
|
|
|
DirectiveKindMap[".code16gcc"] = DK_CODE16GCC;
|
|
|
|
DirectiveKindMap[".rept"] = DK_REPT;
|
2013-12-28 13:54:33 +08:00
|
|
|
DirectiveKindMap[".rep"] = DK_REPT;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".irp"] = DK_IRP;
|
|
|
|
DirectiveKindMap[".irpc"] = DK_IRPC;
|
|
|
|
DirectiveKindMap[".endr"] = DK_ENDR;
|
|
|
|
DirectiveKindMap[".bundle_align_mode"] = DK_BUNDLE_ALIGN_MODE;
|
|
|
|
DirectiveKindMap[".bundle_lock"] = DK_BUNDLE_LOCK;
|
|
|
|
DirectiveKindMap[".bundle_unlock"] = DK_BUNDLE_UNLOCK;
|
|
|
|
DirectiveKindMap[".if"] = DK_IF;
|
2014-06-19 04:57:28 +08:00
|
|
|
DirectiveKindMap[".ifeq"] = DK_IFEQ;
|
|
|
|
DirectiveKindMap[".ifge"] = DK_IFGE;
|
|
|
|
DirectiveKindMap[".ifgt"] = DK_IFGT;
|
|
|
|
DirectiveKindMap[".ifle"] = DK_IFLE;
|
|
|
|
DirectiveKindMap[".iflt"] = DK_IFLT;
|
2014-02-23 23:53:41 +08:00
|
|
|
DirectiveKindMap[".ifne"] = DK_IFNE;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".ifb"] = DK_IFB;
|
|
|
|
DirectiveKindMap[".ifnb"] = DK_IFNB;
|
|
|
|
DirectiveKindMap[".ifc"] = DK_IFC;
|
2014-02-24 07:02:18 +08:00
|
|
|
DirectiveKindMap[".ifeqs"] = DK_IFEQS;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".ifnc"] = DK_IFNC;
|
2015-03-18 22:20:54 +08:00
|
|
|
DirectiveKindMap[".ifnes"] = DK_IFNES;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".ifdef"] = DK_IFDEF;
|
|
|
|
DirectiveKindMap[".ifndef"] = DK_IFNDEF;
|
|
|
|
DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF;
|
|
|
|
DirectiveKindMap[".elseif"] = DK_ELSEIF;
|
|
|
|
DirectiveKindMap[".else"] = DK_ELSE;
|
2013-12-18 10:53:03 +08:00
|
|
|
DirectiveKindMap[".end"] = DK_END;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".endif"] = DK_ENDIF;
|
|
|
|
DirectiveKindMap[".skip"] = DK_SKIP;
|
|
|
|
DirectiveKindMap[".space"] = DK_SPACE;
|
|
|
|
DirectiveKindMap[".file"] = DK_FILE;
|
|
|
|
DirectiveKindMap[".line"] = DK_LINE;
|
|
|
|
DirectiveKindMap[".loc"] = DK_LOC;
|
|
|
|
DirectiveKindMap[".stabs"] = DK_STABS;
|
2016-01-29 08:49:42 +08:00
|
|
|
DirectiveKindMap[".cv_file"] = DK_CV_FILE;
|
2016-09-08 00:15:31 +08:00
|
|
|
DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;
|
2016-01-29 08:49:42 +08:00
|
|
|
DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
|
|
|
|
DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
|
2016-01-30 03:24:12 +08:00
|
|
|
DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;
|
2016-09-08 00:15:31 +08:00
|
|
|
DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;
|
2016-02-05 09:55:49 +08:00
|
|
|
DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;
|
2016-01-29 08:49:42 +08:00
|
|
|
DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
|
|
|
|
DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".sleb128"] = DK_SLEB128;
|
|
|
|
DirectiveKindMap[".uleb128"] = DK_ULEB128;
|
|
|
|
DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
|
|
|
|
DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;
|
|
|
|
DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;
|
|
|
|
DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;
|
|
|
|
DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;
|
|
|
|
DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;
|
|
|
|
DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;
|
|
|
|
DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
|
|
|
|
DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
|
|
|
|
DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
|
|
|
|
DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;
|
|
|
|
DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;
|
|
|
|
DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;
|
|
|
|
DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;
|
|
|
|
DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;
|
|
|
|
DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;
|
|
|
|
DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;
|
|
|
|
DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;
|
|
|
|
DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
|
2013-09-26 22:49:40 +08:00
|
|
|
DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".macros_on"] = DK_MACROS_ON;
|
|
|
|
DirectiveKindMap[".macros_off"] = DK_MACROS_OFF;
|
|
|
|
DirectiveKindMap[".macro"] = DK_MACRO;
|
2014-07-25 01:08:39 +08:00
|
|
|
DirectiveKindMap[".exitm"] = DK_EXITM;
|
2013-01-16 06:59:42 +08:00
|
|
|
DirectiveKindMap[".endm"] = DK_ENDM;
|
|
|
|
DirectiveKindMap[".endmacro"] = DK_ENDMACRO;
|
|
|
|
DirectiveKindMap[".purgem"] = DK_PURGEM;
|
2014-02-23 23:53:30 +08:00
|
|
|
DirectiveKindMap[".err"] = DK_ERR;
|
2014-02-24 07:02:23 +08:00
|
|
|
DirectiveKindMap[".error"] = DK_ERROR;
|
2014-07-25 00:26:06 +08:00
|
|
|
DirectiveKindMap[".warning"] = DK_WARNING;
|
2015-11-12 21:33:00 +08:00
|
|
|
DirectiveKindMap[".reloc"] = DK_RELOC;
|
2016-08-24 05:34:53 +08:00
|
|
|
DirectiveKindMap[".dc"] = DK_DC;
|
|
|
|
DirectiveKindMap[".dc.a"] = DK_DC_A;
|
|
|
|
DirectiveKindMap[".dc.b"] = DK_DC_B;
|
|
|
|
DirectiveKindMap[".dc.d"] = DK_DC_D;
|
|
|
|
DirectiveKindMap[".dc.l"] = DK_DC_L;
|
|
|
|
DirectiveKindMap[".dc.s"] = DK_DC_S;
|
|
|
|
DirectiveKindMap[".dc.w"] = DK_DC_W;
|
|
|
|
DirectiveKindMap[".dc.x"] = DK_DC_X;
|
2016-09-24 03:25:15 +08:00
|
|
|
DirectiveKindMap[".dcb"] = DK_DCB;
|
|
|
|
DirectiveKindMap[".dcb.b"] = DK_DCB_B;
|
|
|
|
DirectiveKindMap[".dcb.d"] = DK_DCB_D;
|
|
|
|
DirectiveKindMap[".dcb.l"] = DK_DCB_L;
|
|
|
|
DirectiveKindMap[".dcb.s"] = DK_DCB_S;
|
|
|
|
DirectiveKindMap[".dcb.w"] = DK_DCB_W;
|
|
|
|
DirectiveKindMap[".dcb.x"] = DK_DCB_X;
|
2016-09-24 05:53:36 +08:00
|
|
|
DirectiveKindMap[".ds"] = DK_DS;
|
|
|
|
DirectiveKindMap[".ds.b"] = DK_DS_B;
|
|
|
|
DirectiveKindMap[".ds.d"] = DK_DS_D;
|
|
|
|
DirectiveKindMap[".ds.l"] = DK_DS_L;
|
|
|
|
DirectiveKindMap[".ds.p"] = DK_DS_P;
|
|
|
|
DirectiveKindMap[".ds.s"] = DK_DS_S;
|
|
|
|
DirectiveKindMap[".ds.w"] = DK_DS_W;
|
|
|
|
DirectiveKindMap[".ds.x"] = DK_DS_X;
|
2013-01-16 06:59:42 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {
|
2012-05-13 00:31:10 +08:00
|
|
|
AsmToken EndToken, StartToken = getTok();
|
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
unsigned NestLevel = 0;
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2012-05-13 00:31:10 +08:00
|
|
|
// Check whether we have reached the end of the file.
|
2012-06-04 07:57:14 +08:00
|
|
|
if (getLexer().is(AsmToken::Eof)) {
|
2016-09-17 02:30:20 +08:00
|
|
|
printError(DirectiveLoc, "no matching '.endr' in definition");
|
2014-04-24 14:44:33 +08:00
|
|
|
return nullptr;
|
2012-06-04 07:57:14 +08:00
|
|
|
}
|
2012-05-13 00:31:10 +08:00
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
if (Lexer.is(AsmToken::Identifier) &&
|
2016-03-01 16:18:28 +08:00
|
|
|
(getTok().getIdentifier() == ".rept" ||
|
|
|
|
getTok().getIdentifier() == ".irp" ||
|
|
|
|
getTok().getIdentifier() == ".irpc")) {
|
2012-06-04 07:57:14 +08:00
|
|
|
++NestLevel;
|
2012-05-13 00:31:10 +08:00
|
|
|
}
|
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
// Otherwise, check whether we have reached the .endr.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (Lexer.is(AsmToken::Identifier) && getTok().getIdentifier() == ".endr") {
|
2012-06-04 07:57:14 +08:00
|
|
|
if (NestLevel == 0) {
|
2012-05-13 00:31:10 +08:00
|
|
|
EndToken = getTok();
|
|
|
|
Lex();
|
2012-06-04 07:57:14 +08:00
|
|
|
if (Lexer.isNot(AsmToken::EndOfStatement)) {
|
2016-09-17 02:30:20 +08:00
|
|
|
printError(getTok().getLoc(),
|
|
|
|
"unexpected token in '.endr' directive");
|
2014-04-24 14:44:33 +08:00
|
|
|
return nullptr;
|
2012-06-04 07:57:14 +08:00
|
|
|
}
|
2012-05-13 00:31:10 +08:00
|
|
|
break;
|
|
|
|
}
|
2012-06-04 07:57:14 +08:00
|
|
|
--NestLevel;
|
2012-05-13 00:31:10 +08:00
|
|
|
}
|
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
// Otherwise, scan till the end of the statement.
|
2013-02-21 06:21:35 +08:00
|
|
|
eatToEndOfStatement();
|
2012-05-13 00:31:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *BodyStart = StartToken.getLoc().getPointer();
|
|
|
|
const char *BodyEnd = EndToken.getLoc().getPointer();
|
|
|
|
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
|
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
// We Are Anonymous.
|
2015-05-30 03:43:39 +08:00
|
|
|
MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters());
|
2013-08-04 17:06:29 +08:00
|
|
|
return &MacroLikeBodies.back();
|
2012-06-04 07:57:14 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
|
2012-06-04 07:57:14 +08:00
|
|
|
raw_svector_ostream &OS) {
|
2012-05-13 00:31:10 +08:00
|
|
|
OS << ".endr\n";
|
|
|
|
|
2014-08-28 04:03:13 +08:00
|
|
|
std::unique_ptr<MemoryBuffer> Instantiation =
|
|
|
|
MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
|
2012-05-13 00:31:10 +08:00
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
// Create the macro instantiation object and add to the current macro
|
|
|
|
// instantiation stack.
|
2014-08-28 03:49:03 +08:00
|
|
|
MacroInstantiation *MI = new MacroInstantiation(
|
|
|
|
DirectiveLoc, CurBuffer, getTok().getLoc(), TheCondStack.size());
|
2012-06-04 07:57:14 +08:00
|
|
|
ActiveMacros.push_back(MI);
|
|
|
|
|
|
|
|
// Jump to the macro instantiation and prime the lexer.
|
2014-08-22 04:44:56 +08:00
|
|
|
CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
|
2014-07-06 22:17:29 +08:00
|
|
|
Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
|
2012-06-04 07:57:14 +08:00
|
|
|
Lex();
|
|
|
|
}
|
2012-05-13 00:31:10 +08:00
|
|
|
|
2013-12-28 13:54:33 +08:00
|
|
|
/// parseDirectiveRept
|
|
|
|
/// ::= .rep | .rept count
|
|
|
|
bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) {
|
2013-12-28 14:39:29 +08:00
|
|
|
const MCExpr *CountExpr;
|
|
|
|
SMLoc CountLoc = getTok().getLoc();
|
|
|
|
if (parseExpression(CountExpr))
|
|
|
|
return true;
|
|
|
|
|
2012-06-04 07:57:14 +08:00
|
|
|
int64_t Count;
|
2015-05-30 09:25:56 +08:00
|
|
|
if (!CountExpr->evaluateAsAbsolute(Count)) {
|
2013-12-28 14:39:29 +08:00
|
|
|
return Error(CountLoc, "unexpected token in '" + Dir + "' directive");
|
|
|
|
}
|
2012-06-04 07:57:14 +08:00
|
|
|
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(Count < 0, CountLoc, "Count is negative") ||
|
|
|
|
parseToken(AsmToken::EndOfStatement,
|
|
|
|
"unexpected token in '" + Dir + "' directive"))
|
|
|
|
return true;
|
2012-06-04 07:57:14 +08:00
|
|
|
|
|
|
|
// Lex the rept definition.
|
2013-09-21 07:08:21 +08:00
|
|
|
MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
|
2012-06-04 07:57:14 +08:00
|
|
|
if (!M)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Macro instantiation is lexical, unfortunately. We construct a new buffer
|
|
|
|
// to hold the macro body with substitutions.
|
|
|
|
SmallString<256> Buf;
|
|
|
|
raw_svector_ostream OS(Buf);
|
|
|
|
while (Count--) {
|
2015-04-27 18:50:29 +08:00
|
|
|
// Note that the AtPseudoVariable is disabled for instantiations of .rep(t).
|
|
|
|
if (expandMacro(OS, M->Body, None, None, false, getTok().getLoc()))
|
2012-06-04 07:57:14 +08:00
|
|
|
return true;
|
|
|
|
}
|
2013-09-21 07:08:21 +08:00
|
|
|
instantiateMacroLikeBody(M, DirectiveLoc, OS);
|
2012-05-13 00:31:10 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveIrp
|
2012-06-15 22:02:34 +08:00
|
|
|
/// ::= .irp symbol,values
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) {
|
2013-01-15 07:22:36 +08:00
|
|
|
MCAsmMacroParameter Parameter;
|
|
|
|
MCAsmMacroArguments A;
|
2016-07-18 23:24:03 +08:00
|
|
|
if (check(parseIdentifier(Parameter.Name),
|
|
|
|
"expected identifier in '.irp' directive") ||
|
|
|
|
parseToken(AsmToken::Comma, "expected comma in '.irp' directive") ||
|
|
|
|
parseMacroArguments(nullptr, A) ||
|
|
|
|
parseToken(AsmToken::EndOfStatement, "expected End of Statement"))
|
2012-06-15 22:02:34 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// Lex the irp definition.
|
2013-09-21 07:08:21 +08:00
|
|
|
MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
|
2012-06-15 22:02:34 +08:00
|
|
|
if (!M)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Macro instantiation is lexical, unfortunately. We construct a new buffer
|
|
|
|
// to hold the macro body with substitutions.
|
|
|
|
SmallString<256> Buf;
|
|
|
|
raw_svector_ostream OS(Buf);
|
|
|
|
|
2015-10-10 13:38:14 +08:00
|
|
|
for (const MCAsmMacroArgument &Arg : A) {
|
2015-04-27 18:50:29 +08:00
|
|
|
// Note that the AtPseudoVariable is enabled for instantiations of .irp.
|
|
|
|
// This is undocumented, but GAS seems to support it.
|
2015-10-10 13:38:14 +08:00
|
|
|
if (expandMacro(OS, M->Body, Parameter, Arg, true, getTok().getLoc()))
|
2012-06-15 22:02:34 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
instantiateMacroLikeBody(M, DirectiveLoc, OS);
|
2012-06-15 22:02:34 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
/// parseDirectiveIrpc
|
2012-06-17 02:03:25 +08:00
|
|
|
/// ::= .irpc symbol,values
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) {
|
2013-01-15 07:22:36 +08:00
|
|
|
MCAsmMacroParameter Parameter;
|
|
|
|
MCAsmMacroArguments A;
|
2016-07-18 23:24:03 +08:00
|
|
|
|
|
|
|
if (check(parseIdentifier(Parameter.Name),
|
|
|
|
"expected identifier in '.irpc' directive") ||
|
|
|
|
parseToken(AsmToken::Comma, "expected comma in '.irpc' directive") ||
|
|
|
|
parseMacroArguments(nullptr, A))
|
2012-06-17 02:03:25 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (A.size() != 1 || A.front().size() != 1)
|
|
|
|
return TokError("unexpected token in '.irpc' directive");
|
|
|
|
|
|
|
|
// Eat the end of statement.
|
2016-07-18 23:24:03 +08:00
|
|
|
if (parseToken(AsmToken::EndOfStatement, "expected end of statement"))
|
|
|
|
return true;
|
2012-06-17 02:03:25 +08:00
|
|
|
|
|
|
|
// Lex the irpc definition.
|
2013-09-21 07:08:21 +08:00
|
|
|
MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
|
2012-06-17 02:03:25 +08:00
|
|
|
if (!M)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Macro instantiation is lexical, unfortunately. We construct a new buffer
|
|
|
|
// to hold the macro body with substitutions.
|
|
|
|
SmallString<256> Buf;
|
|
|
|
raw_svector_ostream OS(Buf);
|
|
|
|
|
|
|
|
StringRef Values = A.front().front().getString();
|
2014-02-10 01:13:11 +08:00
|
|
|
for (std::size_t I = 0, End = Values.size(); I != End; ++I) {
|
2013-01-15 03:00:26 +08:00
|
|
|
MCAsmMacroArgument Arg;
|
2015-05-30 03:43:39 +08:00
|
|
|
Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1));
|
2012-06-17 02:03:25 +08:00
|
|
|
|
2015-04-27 18:50:29 +08:00
|
|
|
// Note that the AtPseudoVariable is enabled for instantiations of .irpc.
|
|
|
|
// This is undocumented, but GAS seems to support it.
|
|
|
|
if (expandMacro(OS, M->Body, Parameter, Arg, true, getTok().getLoc()))
|
2012-06-17 02:03:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
instantiateMacroLikeBody(M, DirectiveLoc, OS);
|
2012-06-17 02:03:25 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveEndr(SMLoc DirectiveLoc) {
|
2012-06-04 07:57:14 +08:00
|
|
|
if (ActiveMacros.empty())
|
2012-09-20 04:23:43 +08:00
|
|
|
return TokError("unmatched '.endr' directive");
|
2012-05-13 00:31:10 +08:00
|
|
|
|
|
|
|
// The only .repl that should get here are the ones created by
|
2013-09-21 07:08:21 +08:00
|
|
|
// instantiateMacroLikeBody.
|
2012-05-13 00:31:10 +08:00
|
|
|
assert(getLexer().is(AsmToken::EndOfStatement));
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
handleMacroExit();
|
2012-05-13 00:31:10 +08:00
|
|
|
return false;
|
|
|
|
}
|
2010-09-12 00:45:15 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info,
|
2013-02-16 04:37:21 +08:00
|
|
|
size_t Len) {
|
2012-10-23 07:58:19 +08:00
|
|
|
const MCExpr *Value;
|
|
|
|
SMLoc ExprLoc = getLexer().getLoc();
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseExpression(Value))
|
2012-10-23 07:58:19 +08:00
|
|
|
return true;
|
|
|
|
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);
|
|
|
|
if (!MCE)
|
|
|
|
return Error(ExprLoc, "unexpected expression in _emit");
|
|
|
|
uint64_t IntValue = MCE->getValue();
|
2015-10-11 04:17:07 +08:00
|
|
|
if (!isUInt<8>(IntValue) && !isInt<8>(IntValue))
|
2012-10-23 07:58:19 +08:00
|
|
|
return Error(ExprLoc, "literal value out of range for directive");
|
|
|
|
|
2015-10-10 13:25:02 +08:00
|
|
|
Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len);
|
2013-02-13 05:33:51 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) {
|
2013-02-13 05:33:51 +08:00
|
|
|
const MCExpr *Value;
|
|
|
|
SMLoc ExprLoc = getLexer().getLoc();
|
2013-02-21 06:21:35 +08:00
|
|
|
if (parseExpression(Value))
|
2013-02-13 05:33:51 +08:00
|
|
|
return true;
|
|
|
|
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);
|
|
|
|
if (!MCE)
|
|
|
|
return Error(ExprLoc, "unexpected expression in align");
|
|
|
|
uint64_t IntValue = MCE->getValue();
|
|
|
|
if (!isPowerOf2_64(IntValue))
|
|
|
|
return Error(ExprLoc, "literal value not a power of two greater then zero");
|
|
|
|
|
2015-10-10 13:25:02 +08:00
|
|
|
Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue));
|
2012-10-23 07:58:19 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-02-14 05:27:17 +08:00
|
|
|
// We are comparing pointers, but the pointers are relative to a single string.
|
|
|
|
// Thus, this should always be deterministic.
|
2013-09-22 22:09:50 +08:00
|
|
|
static int rewritesSort(const AsmRewrite *AsmRewriteA,
|
|
|
|
const AsmRewrite *AsmRewriteB) {
|
2013-02-14 02:38:58 +08:00
|
|
|
if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())
|
|
|
|
return -1;
|
|
|
|
if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())
|
|
|
|
return 1;
|
2013-02-16 06:54:16 +08:00
|
|
|
|
2013-04-09 01:43:47 +08:00
|
|
|
// It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output
|
|
|
|
// rewrite to the same location. Make sure the SizeDirective rewrite is
|
|
|
|
// performed first, then the Imm/ImmPrefix and finally the Input/Output. This
|
|
|
|
// ensures the sort algorithm is stable.
|
2013-09-21 07:08:21 +08:00
|
|
|
if (AsmRewritePrecedence[AsmRewriteA->Kind] >
|
|
|
|
AsmRewritePrecedence[AsmRewriteB->Kind])
|
2013-02-16 06:54:16 +08:00
|
|
|
return -1;
|
2013-04-09 01:43:47 +08:00
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
if (AsmRewritePrecedence[AsmRewriteA->Kind] <
|
|
|
|
AsmRewritePrecedence[AsmRewriteB->Kind])
|
2013-02-16 06:54:16 +08:00
|
|
|
return 1;
|
2013-09-21 07:08:21 +08:00
|
|
|
llvm_unreachable("Unstable rewrite sort.");
|
2013-02-13 09:03:13 +08:00
|
|
|
}
|
|
|
|
|
2013-09-21 07:08:21 +08:00
|
|
|
bool AsmParser::parseMSInlineAsm(
|
|
|
|
void *AsmLoc, std::string &AsmString, unsigned &NumOutputs,
|
|
|
|
unsigned &NumInputs, SmallVectorImpl<std::pair<void *, bool> > &OpDecls,
|
|
|
|
SmallVectorImpl<std::string> &Constraints,
|
|
|
|
SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII,
|
|
|
|
const MCInstPrinter *IP, MCAsmParserSemaCallback &SI) {
|
2012-10-24 01:43:43 +08:00
|
|
|
SmallVector<void *, 4> InputDecls;
|
|
|
|
SmallVector<void *, 4> OutputDecls;
|
2013-01-11 06:10:27 +08:00
|
|
|
SmallVector<bool, 4> InputDeclsAddressOf;
|
|
|
|
SmallVector<bool, 4> OutputDeclsAddressOf;
|
2012-10-18 23:49:34 +08:00
|
|
|
SmallVector<std::string, 4> InputConstraints;
|
|
|
|
SmallVector<std::string, 4> OutputConstraints;
|
2013-02-16 04:37:21 +08:00
|
|
|
SmallVector<unsigned, 4> ClobberRegs;
|
2012-10-18 23:49:34 +08:00
|
|
|
|
2013-02-16 04:37:21 +08:00
|
|
|
SmallVector<AsmRewrite, 4> AsmStrRewrites;
|
2012-10-18 23:49:34 +08:00
|
|
|
|
|
|
|
// Prime the lexer.
|
|
|
|
Lex();
|
|
|
|
|
|
|
|
// While we have input, parse each statement.
|
|
|
|
unsigned InputIdx = 0;
|
|
|
|
unsigned OutputIdx = 0;
|
|
|
|
while (getLexer().isNot(AsmToken::Eof)) {
|
2016-03-08 02:11:16 +08:00
|
|
|
// Parse curly braces marking block start/end
|
|
|
|
if (parseCurlyBlockScope(AsmStrRewrites))
|
|
|
|
continue;
|
|
|
|
|
2012-10-23 07:58:19 +08:00
|
|
|
ParseStatementInfo Info(&AsmStrRewrites);
|
2016-09-17 02:30:20 +08:00
|
|
|
bool StatementErr = parseStatement(Info, &SI);
|
2016-09-13 21:55:06 +08:00
|
|
|
|
2016-09-17 02:30:20 +08:00
|
|
|
if (StatementErr || Info.ParseError) {
|
|
|
|
// Emit pending errors if any exist.
|
|
|
|
printPendingErrors();
|
2016-09-14 02:17:00 +08:00
|
|
|
return true;
|
2016-09-17 02:30:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// No pending error should exist here.
|
|
|
|
assert(!hasPendingError() && "unexpected error from parseStatement");
|
2012-12-13 06:45:52 +08:00
|
|
|
|
2013-02-16 04:37:21 +08:00
|
|
|
if (Info.Opcode == ~0U)
|
|
|
|
continue;
|
2012-10-18 23:49:34 +08:00
|
|
|
|
2013-02-16 04:37:21 +08:00
|
|
|
const MCInstrDesc &Desc = MII->get(Info.Opcode);
|
2012-10-18 23:49:34 +08:00
|
|
|
|
2013-02-16 04:37:21 +08:00
|
|
|
// Build the list of clobbers, outputs and inputs.
|
|
|
|
for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {
|
2014-06-09 00:18:35 +08:00
|
|
|
MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];
|
2012-10-18 23:49:34 +08:00
|
|
|
|
2013-02-16 04:37:21 +08:00
|
|
|
// Immediate.
|
2014-06-09 00:18:35 +08:00
|
|
|
if (Operand.isImm())
|
2013-02-16 04:37:21 +08:00
|
|
|
continue;
|
2012-10-18 23:49:34 +08:00
|
|
|
|
2013-02-16 04:37:21 +08:00
|
|
|
// Register operand.
|
2014-07-18 04:24:55 +08:00
|
|
|
if (Operand.isReg() && !Operand.needAddressOf() &&
|
|
|
|
!getTargetParser().OmitRegisterFromClobberLists(Operand.getReg())) {
|
2013-02-16 04:37:21 +08:00
|
|
|
unsigned NumDefs = Desc.getNumDefs();
|
|
|
|
// Clobber.
|
2014-06-09 00:18:35 +08:00
|
|
|
if (NumDefs && Operand.getMCOperandNum() < NumDefs)
|
|
|
|
ClobberRegs.push_back(Operand.getReg());
|
2013-02-16 04:37:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expr/Input or Output.
|
2014-06-09 00:18:35 +08:00
|
|
|
StringRef SymName = Operand.getSymName();
|
2013-04-10 01:53:49 +08:00
|
|
|
if (SymName.empty())
|
|
|
|
continue;
|
|
|
|
|
2014-06-09 00:18:35 +08:00
|
|
|
void *OpDecl = Operand.getOpDecl();
|
2013-02-16 04:37:21 +08:00
|
|
|
if (!OpDecl)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool isOutput = (i == 1) && Desc.mayStore();
|
2013-04-10 01:53:49 +08:00
|
|
|
SMLoc Start = SMLoc::getFromPointer(SymName.data());
|
2013-02-16 04:37:21 +08:00
|
|
|
if (isOutput) {
|
|
|
|
++InputIdx;
|
|
|
|
OutputDecls.push_back(OpDecl);
|
2014-06-09 00:18:35 +08:00
|
|
|
OutputDeclsAddressOf.push_back(Operand.needAddressOf());
|
2015-03-30 23:42:36 +08:00
|
|
|
OutputConstraints.push_back(("=" + Operand.getConstraint()).str());
|
2015-10-10 13:25:02 +08:00
|
|
|
AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size());
|
2013-02-16 04:37:21 +08:00
|
|
|
} else {
|
|
|
|
InputDecls.push_back(OpDecl);
|
2014-06-09 00:18:35 +08:00
|
|
|
InputDeclsAddressOf.push_back(Operand.needAddressOf());
|
|
|
|
InputConstraints.push_back(Operand.getConstraint().str());
|
2015-10-10 13:25:02 +08:00
|
|
|
AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
|
2012-10-18 23:49:34 +08:00
|
|
|
}
|
|
|
|
}
|
2013-12-11 02:27:32 +08:00
|
|
|
|
|
|
|
// Consider implicit defs to be clobbers. Think of cpuid and push.
|
2015-12-05 15:13:35 +08:00
|
|
|
ArrayRef<MCPhysReg> ImpDefs(Desc.getImplicitDefs(),
|
|
|
|
Desc.getNumImplicitDefs());
|
2014-06-23 10:17:16 +08:00
|
|
|
ClobberRegs.insert(ClobberRegs.end(), ImpDefs.begin(), ImpDefs.end());
|
2012-10-18 23:49:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set the number of Outputs and Inputs.
|
2012-10-19 03:39:30 +08:00
|
|
|
NumOutputs = OutputDecls.size();
|
|
|
|
NumInputs = InputDecls.size();
|
2012-10-18 23:49:34 +08:00
|
|
|
|
|
|
|
// Set the unique clobbers.
|
2013-02-16 04:37:21 +08:00
|
|
|
array_pod_sort(ClobberRegs.begin(), ClobberRegs.end());
|
|
|
|
ClobberRegs.erase(std::unique(ClobberRegs.begin(), ClobberRegs.end()),
|
|
|
|
ClobberRegs.end());
|
|
|
|
Clobbers.assign(ClobberRegs.size(), std::string());
|
|
|
|
for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {
|
|
|
|
raw_string_ostream OS(Clobbers[I]);
|
|
|
|
IP->printRegName(OS, ClobberRegs[I]);
|
|
|
|
}
|
2012-10-18 23:49:34 +08:00
|
|
|
|
|
|
|
// Merge the various outputs and inputs. Output are expected first.
|
|
|
|
if (NumOutputs || NumInputs) {
|
|
|
|
unsigned NumExprs = NumOutputs + NumInputs;
|
2012-10-19 03:39:30 +08:00
|
|
|
OpDecls.resize(NumExprs);
|
2012-10-18 23:49:34 +08:00
|
|
|
Constraints.resize(NumExprs);
|
|
|
|
for (unsigned i = 0; i < NumOutputs; ++i) {
|
2013-01-11 06:10:27 +08:00
|
|
|
OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsAddressOf[i]);
|
2013-01-16 07:07:53 +08:00
|
|
|
Constraints[i] = OutputConstraints[i];
|
2012-10-18 23:49:34 +08:00
|
|
|
}
|
|
|
|
for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {
|
2013-01-11 06:10:27 +08:00
|
|
|
OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsAddressOf[i]);
|
2013-01-16 07:07:53 +08:00
|
|
|
Constraints[j] = InputConstraints[i];
|
2012-10-18 23:49:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the IR assembly string.
|
2014-06-27 06:52:05 +08:00
|
|
|
std::string AsmStringIR;
|
|
|
|
raw_string_ostream OS(AsmStringIR);
|
2014-07-06 18:33:31 +08:00
|
|
|
StringRef ASMString =
|
|
|
|
SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer();
|
|
|
|
const char *AsmStart = ASMString.begin();
|
|
|
|
const char *AsmEnd = ASMString.end();
|
2013-09-21 07:08:21 +08:00
|
|
|
array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);
|
2014-06-23 10:17:16 +08:00
|
|
|
for (const AsmRewrite &AR : AsmStrRewrites) {
|
|
|
|
AsmRewriteKind Kind = AR.Kind;
|
2013-04-13 00:26:42 +08:00
|
|
|
if (Kind == AOK_Delete)
|
|
|
|
continue;
|
|
|
|
|
2014-06-23 10:17:16 +08:00
|
|
|
const char *Loc = AR.Loc.getPointer();
|
2013-03-20 05:12:14 +08:00
|
|
|
assert(Loc >= AsmStart && "Expected Loc to be at or after Start!");
|
2012-10-20 04:57:14 +08:00
|
|
|
|
2013-03-20 01:32:17 +08:00
|
|
|
// Emit everything up to the immediate/expression.
|
2014-06-23 10:17:16 +08:00
|
|
|
if (unsigned Len = Loc - AsmStart)
|
2013-03-20 05:12:14 +08:00
|
|
|
OS << StringRef(AsmStart, Len);
|
2012-10-20 04:57:14 +08:00
|
|
|
|
2012-10-24 01:43:43 +08:00
|
|
|
// Skip the original expression.
|
|
|
|
if (Kind == AOK_Skip) {
|
2014-06-23 10:17:16 +08:00
|
|
|
AsmStart = Loc + AR.Len;
|
2012-10-24 01:43:43 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-04-13 00:26:42 +08:00
|
|
|
unsigned AdditionalSkip = 0;
|
2012-10-18 23:49:34 +08:00
|
|
|
// Rewrite expressions in $N notation.
|
2012-10-20 04:57:14 +08:00
|
|
|
switch (Kind) {
|
2013-09-21 07:08:21 +08:00
|
|
|
default:
|
|
|
|
break;
|
2012-10-18 23:49:34 +08:00
|
|
|
case AOK_Imm:
|
2014-06-23 10:17:16 +08:00
|
|
|
OS << "$$" << AR.Val;
|
2012-10-27 02:04:20 +08:00
|
|
|
break;
|
|
|
|
case AOK_ImmPrefix:
|
2013-02-16 04:37:21 +08:00
|
|
|
OS << "$$";
|
2012-10-18 23:49:34 +08:00
|
|
|
break;
|
2014-09-22 10:21:35 +08:00
|
|
|
case AOK_Label:
|
2014-12-04 08:06:57 +08:00
|
|
|
OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label;
|
2014-09-22 10:21:35 +08:00
|
|
|
break;
|
2012-10-18 23:49:34 +08:00
|
|
|
case AOK_Input:
|
2013-02-16 04:37:21 +08:00
|
|
|
OS << '$' << InputIdx++;
|
2012-10-18 23:49:34 +08:00
|
|
|
break;
|
|
|
|
case AOK_Output:
|
2013-02-16 04:37:21 +08:00
|
|
|
OS << '$' << OutputIdx++;
|
2012-10-18 23:49:34 +08:00
|
|
|
break;
|
2012-10-20 04:57:14 +08:00
|
|
|
case AOK_SizeDirective:
|
2014-06-23 10:17:16 +08:00
|
|
|
switch (AR.Val) {
|
2012-10-20 04:57:14 +08:00
|
|
|
default: break;
|
|
|
|
case 8: OS << "byte ptr "; break;
|
|
|
|
case 16: OS << "word ptr "; break;
|
|
|
|
case 32: OS << "dword ptr "; break;
|
|
|
|
case 64: OS << "qword ptr "; break;
|
|
|
|
case 80: OS << "xword ptr "; break;
|
|
|
|
case 128: OS << "xmmword ptr "; break;
|
|
|
|
case 256: OS << "ymmword ptr "; break;
|
|
|
|
}
|
2012-10-23 07:58:19 +08:00
|
|
|
break;
|
|
|
|
case AOK_Emit:
|
|
|
|
OS << ".byte";
|
|
|
|
break;
|
2013-02-13 05:33:51 +08:00
|
|
|
case AOK_Align: {
|
2015-10-28 01:32:48 +08:00
|
|
|
// MS alignment directives are measured in bytes. If the native assembler
|
|
|
|
// measures alignment in bytes, we can pass it straight through.
|
|
|
|
OS << ".align";
|
|
|
|
if (getContext().getAsmInfo()->getAlignmentIsInBytes())
|
|
|
|
break;
|
2013-02-13 05:33:51 +08:00
|
|
|
|
2015-10-28 01:32:48 +08:00
|
|
|
// Alignment is in log2 form, so print that instead and skip the original
|
|
|
|
// immediate.
|
|
|
|
unsigned Val = AR.Val;
|
|
|
|
OS << ' ' << Val;
|
2013-02-16 04:37:21 +08:00
|
|
|
assert(Val < 10 && "Expected alignment less then 2^10.");
|
2013-02-13 05:33:51 +08:00
|
|
|
AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;
|
|
|
|
break;
|
|
|
|
}
|
2015-12-14 01:07:23 +08:00
|
|
|
case AOK_EVEN:
|
|
|
|
OS << ".even";
|
|
|
|
break;
|
2012-10-26 04:41:34 +08:00
|
|
|
case AOK_DotOperator:
|
2014-03-07 03:19:12 +08:00
|
|
|
// Insert the dot if the user omitted it.
|
2014-06-27 06:52:05 +08:00
|
|
|
OS.flush();
|
|
|
|
if (AsmStringIR.back() != '.')
|
2014-03-07 03:19:12 +08:00
|
|
|
OS << '.';
|
2014-06-23 10:17:16 +08:00
|
|
|
OS << AR.Val;
|
2012-10-26 04:41:34 +08:00
|
|
|
break;
|
2016-03-08 02:11:16 +08:00
|
|
|
case AOK_EndOfStatement:
|
|
|
|
OS << "\n\t";
|
|
|
|
break;
|
2012-10-18 23:49:34 +08:00
|
|
|
}
|
2012-10-20 04:57:14 +08:00
|
|
|
|
2012-10-18 23:49:34 +08:00
|
|
|
// Skip the original expression.
|
2014-06-23 10:17:16 +08:00
|
|
|
AsmStart = Loc + AR.Len + AdditionalSkip;
|
2012-10-18 23:49:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the remainder of the asm string.
|
2013-03-20 05:12:14 +08:00
|
|
|
if (AsmStart != AsmEnd)
|
|
|
|
OS << StringRef(AsmStart, AsmEnd - AsmStart);
|
2012-10-18 23:49:34 +08:00
|
|
|
|
|
|
|
AsmString = OS.str();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-23 03:35:57 +08:00
|
|
|
namespace llvm {
|
|
|
|
namespace MCParserUtils {
|
|
|
|
|
|
|
|
/// Returns whether the given symbol is used anywhere in the given expression,
|
|
|
|
/// or subexpressions.
|
|
|
|
static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) {
|
|
|
|
switch (Value->getKind()) {
|
|
|
|
case MCExpr::Binary: {
|
|
|
|
const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Value);
|
|
|
|
return isSymbolUsedInExpression(Sym, BE->getLHS()) ||
|
|
|
|
isSymbolUsedInExpression(Sym, BE->getRHS());
|
|
|
|
}
|
|
|
|
case MCExpr::Target:
|
|
|
|
case MCExpr::Constant:
|
|
|
|
return false;
|
|
|
|
case MCExpr::SymbolRef: {
|
|
|
|
const MCSymbol &S =
|
|
|
|
static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
|
|
|
|
if (S.isVariable())
|
|
|
|
return isSymbolUsedInExpression(Sym, S.getVariableValue());
|
|
|
|
return &S == Sym;
|
|
|
|
}
|
|
|
|
case MCExpr::Unary:
|
|
|
|
return isSymbolUsedInExpression(
|
|
|
|
Sym, static_cast<const MCUnaryExpr *>(Value)->getSubExpr());
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm_unreachable("Unknown expr kind!");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool parseAssignmentExpression(StringRef Name, bool allow_redef,
|
|
|
|
MCAsmParser &Parser, MCSymbol *&Sym,
|
|
|
|
const MCExpr *&Value) {
|
|
|
|
|
|
|
|
// FIXME: Use better location, we should use proper tokens.
|
2016-06-18 00:06:17 +08:00
|
|
|
SMLoc EqualLoc = Parser.getTok().getLoc();
|
2015-06-23 03:35:57 +08:00
|
|
|
|
|
|
|
if (Parser.parseExpression(Value)) {
|
2016-10-24 22:35:29 +08:00
|
|
|
return Parser.TokError("missing expression");
|
2015-06-23 03:35:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Note: we don't count b as used in "a = b". This is to allow
|
|
|
|
// a = b
|
|
|
|
// b = c
|
|
|
|
|
2016-10-24 22:35:29 +08:00
|
|
|
if (Parser.parseToken(AsmToken::EndOfStatement))
|
|
|
|
return true;
|
2015-06-23 03:35:57 +08:00
|
|
|
|
|
|
|
// Validate that the LHS is allowed to be a variable (either it has not been
|
|
|
|
// used as a symbol, or it is an absolute symbol).
|
|
|
|
Sym = Parser.getContext().lookupSymbol(Name);
|
|
|
|
if (Sym) {
|
|
|
|
// Diagnose assignment to a label.
|
|
|
|
//
|
|
|
|
// FIXME: Diagnostics. Note the location of the definition as a label.
|
|
|
|
// FIXME: Diagnose assignment to protected identifier (e.g., register name).
|
|
|
|
if (isSymbolUsedInExpression(Sym, Value))
|
|
|
|
return Parser.Error(EqualLoc, "Recursive use of '" + Name + "'");
|
2015-09-01 01:44:53 +08:00
|
|
|
else if (Sym->isUndefined(/*SetUsed*/ false) && !Sym->isUsed() &&
|
|
|
|
!Sym->isVariable())
|
2015-06-23 03:35:57 +08:00
|
|
|
; // Allow redefinitions of undefined symbols only used in directives.
|
|
|
|
else if (Sym->isVariable() && !Sym->isUsed() && allow_redef)
|
|
|
|
; // Allow redefinitions of variables that haven't yet been used.
|
|
|
|
else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef))
|
|
|
|
return Parser.Error(EqualLoc, "redefinition of '" + Name + "'");
|
|
|
|
else if (!Sym->isVariable())
|
|
|
|
return Parser.Error(EqualLoc, "invalid assignment to '" + Name + "'");
|
|
|
|
else if (!isa<MCConstantExpr>(Sym->getVariableValue()))
|
|
|
|
return Parser.Error(EqualLoc,
|
|
|
|
"invalid reassignment of non-absolute variable '" +
|
|
|
|
Name + "'");
|
|
|
|
} else if (Name == ".") {
|
2015-11-05 07:59:18 +08:00
|
|
|
Parser.getStreamer().emitValueToOffset(Value, 0);
|
2015-06-23 03:35:57 +08:00
|
|
|
return false;
|
|
|
|
} else
|
|
|
|
Sym = Parser.getContext().getOrCreateSymbol(Name);
|
|
|
|
|
|
|
|
Sym->setRedefinable(allow_redef);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-08-24 01:14:32 +08:00
|
|
|
} // end namespace MCParserUtils
|
|
|
|
} // end namespace llvm
|
2015-06-23 03:35:57 +08:00
|
|
|
|
2010-07-17 10:26:10 +08:00
|
|
|
/// \brief Create an MCAsmParser instance.
|
2013-09-21 07:08:21 +08:00
|
|
|
MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C,
|
|
|
|
MCStreamer &Out, const MCAsmInfo &MAI) {
|
2011-08-17 02:33:49 +08:00
|
|
|
return new AsmParser(SM, C, Out, MAI);
|
2010-07-17 10:26:10 +08:00
|
|
|
}
|