//
//===----------------------------------------------------------------------===//
-#include "ARMBuildAttrs.h"
#include "ARMFPUName.h"
#include "ARMFeatures.h"
-#include "llvm/MC/MCTargetAsmParser.h"
#include "MCTargetDesc/ARMAddressingModes.h"
#include "MCTargetDesc/ARMArchName.h"
#include "MCTargetDesc/ARMBaseInfo.h"
#include "MCTargetDesc/ARMMCExpr.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCELF.h"
#include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCELFSymbolFlags.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/ARMEHABI.h"
+#include "llvm/Support/COFF.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SourceMgr.h"
enum VectorLaneTy { NoLanes, AllLanes, IndexedLane };
-// A class to keep track of assembler-generated constant pools that are use to
-// implement the ldr-pseudo.
-class ConstantPool {
- typedef SmallVector<std::pair<MCSymbol *, const MCExpr *>, 4> EntryVecTy;
- EntryVecTy Entries;
+class UnwindContext {
+ MCAsmParser &Parser;
-public:
- // Initialize a new empty constant pool
- ConstantPool() { }
+ typedef SmallVector<SMLoc, 4> Locs;
- // Add a new entry to the constant pool in the next slot.
- // \param Value is the new entry to put in the constant pool.
- //
- // \returns a MCExpr that references the newly inserted value
- const MCExpr *addEntry(const MCExpr *Value, MCContext &Context) {
- MCSymbol *CPEntryLabel = Context.CreateTempSymbol();
-
- Entries.push_back(std::make_pair(CPEntryLabel, Value));
- return MCSymbolRefExpr::Create(CPEntryLabel, Context);
- }
+ Locs FnStartLocs;
+ Locs CantUnwindLocs;
+ Locs PersonalityLocs;
+ Locs PersonalityIndexLocs;
+ Locs HandlerDataLocs;
+ int FPReg;
- // Emit the contents of the constant pool using the provided streamer.
- void emitEntries(MCStreamer &Streamer) {
- if (Entries.empty())
- return;
- Streamer.EmitCodeAlignment(4); // align to 4-byte address
- Streamer.EmitDataRegion(MCDR_DataRegion);
- for (EntryVecTy::const_iterator I = Entries.begin(), E = Entries.end();
- I != E; ++I) {
- Streamer.EmitLabel(I->first);
- Streamer.EmitValue(I->second, 4);
+public:
+ UnwindContext(MCAsmParser &P) : Parser(P), FPReg(ARM::SP) {}
+
+ bool hasFnStart() const { return !FnStartLocs.empty(); }
+ bool cantUnwind() const { return !CantUnwindLocs.empty(); }
+ bool hasHandlerData() const { return !HandlerDataLocs.empty(); }
+ bool hasPersonality() const {
+ return !(PersonalityLocs.empty() && PersonalityIndexLocs.empty());
+ }
+
+ void recordFnStart(SMLoc L) { FnStartLocs.push_back(L); }
+ void recordCantUnwind(SMLoc L) { CantUnwindLocs.push_back(L); }
+ void recordPersonality(SMLoc L) { PersonalityLocs.push_back(L); }
+ void recordHandlerData(SMLoc L) { HandlerDataLocs.push_back(L); }
+ void recordPersonalityIndex(SMLoc L) { PersonalityIndexLocs.push_back(L); }
+
+ void saveFPReg(int Reg) { FPReg = Reg; }
+ int getFPReg() const { return FPReg; }
+
+ void emitFnStartLocNotes() const {
+ for (Locs::const_iterator FI = FnStartLocs.begin(), FE = FnStartLocs.end();
+ FI != FE; ++FI)
+ Parser.Note(*FI, ".fnstart was specified here");
+ }
+ void emitCantUnwindLocNotes() const {
+ for (Locs::const_iterator UI = CantUnwindLocs.begin(),
+ UE = CantUnwindLocs.end(); UI != UE; ++UI)
+ Parser.Note(*UI, ".cantunwind was specified here");
+ }
+ void emitHandlerDataLocNotes() const {
+ for (Locs::const_iterator HI = HandlerDataLocs.begin(),
+ HE = HandlerDataLocs.end(); HI != HE; ++HI)
+ Parser.Note(*HI, ".handlerdata was specified here");
+ }
+ void emitPersonalityLocNotes() const {
+ for (Locs::const_iterator PI = PersonalityLocs.begin(),
+ PE = PersonalityLocs.end(),
+ PII = PersonalityIndexLocs.begin(),
+ PIE = PersonalityIndexLocs.end();
+ PI != PE || PII != PIE;) {
+ if (PI != PE && (PII == PIE || PI->getPointer() < PII->getPointer()))
+ Parser.Note(*PI++, ".personality was specified here");
+ else if (PII != PIE && (PI == PE || PII->getPointer() < PI->getPointer()))
+ Parser.Note(*PII++, ".personalityindex was specified here");
+ else
+ llvm_unreachable(".personality and .personalityindex cannot be "
+ "at the same location");
}
- Streamer.EmitDataRegion(MCDR_DataRegionEnd);
- Entries.clear();
}
- // Return true if the constant pool is empty
- bool empty() {
- return Entries.empty();
+ void reset() {
+ FnStartLocs = Locs();
+ CantUnwindLocs = Locs();
+ PersonalityLocs = Locs();
+ HandlerDataLocs = Locs();
+ PersonalityIndexLocs = Locs();
+ FPReg = ARM::SP;
}
};
-// Map type used to keep track of per-Section constant pools used by the
-// ldr-pseudo opcode. The map associates a section to its constant pool. The
-// constant pool is a vector of (label, value) pairs. When the ldr
-// pseudo is parsed we insert a new (label, value) pair into the constant pool
-// for the current section and add MCSymbolRefExpr to the new label as
-// an opcode to the ldr. After we have parsed all the user input we
-// output the (label, value) pairs in each constant pool at the end of the
-// section.
-//
-// We use the MapVector for the map type to ensure stable iteration of
-// the sections at the end of the parse. We need to iterate over the
-// sections in a stable order to ensure that we have print the
-// constant pools in a deterministic order when printing an assembly
-// file.
-typedef MapVector<const MCSection *, ConstantPool> ConstantPoolMapTy;
-
class ARMAsmParser : public MCTargetAsmParser {
MCSubtargetInfo &STI;
MCAsmParser &Parser;
const MCInstrInfo &MII;
const MCRegisterInfo *MRI;
- ConstantPoolMapTy ConstantPools;
-
- // Assembler created constant pools for ldr pseudo
- ConstantPool *getConstantPool(const MCSection *Section) {
- ConstantPoolMapTy::iterator CP = ConstantPools.find(Section);
- if (CP == ConstantPools.end())
- return 0;
-
- return &CP->second;
- }
-
- ConstantPool &getOrCreateConstantPool(const MCSection *Section) {
- return ConstantPools[Section];
- }
+ UnwindContext UC;
ARMTargetStreamer &getTargetStreamer() {
- MCTargetStreamer &TS = getParser().getStreamer().getTargetStreamer();
+ MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
return static_cast<ARMTargetStreamer &>(TS);
}
- // Unwind directives state
- SMLoc FnStartLoc;
- SMLoc CantUnwindLoc;
- SMLoc PersonalityLoc;
- SMLoc HandlerDataLoc;
- int FPReg;
- void resetUnwindDirectiveParserState() {
- FnStartLoc = SMLoc();
- CantUnwindLoc = SMLoc();
- PersonalityLoc = SMLoc();
- HandlerDataLoc = SMLoc();
- FPReg = -1;
- }
-
// Map of register aliases registers via the .req directive.
StringMap<unsigned> RegisterReqs;
MCAsmParser &getParser() const { return Parser; }
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
+ void Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = None) {
+ return Parser.Note(L, Msg, Ranges);
+ }
bool Warning(SMLoc L, const Twine &Msg,
ArrayRef<SMRange> Ranges = None) {
return Parser.Warning(L, Msg, Ranges);
bool parsePrefix(ARMMCExpr::VariantKind &RefKind);
bool parseMemRegOffsetShift(ARM_AM::ShiftOpc &ShiftType,
unsigned &ShiftAmount);
- bool parseDirectiveWord(unsigned Size, SMLoc L);
+ bool parseLiteralValues(unsigned Size, SMLoc L);
bool parseDirectiveThumb(SMLoc L);
bool parseDirectiveARM(SMLoc L);
bool parseDirectiveThumbFunc(SMLoc L);
bool parseDirectiveInst(SMLoc L, char Suffix = '\0');
bool parseDirectiveLtorg(SMLoc L);
bool parseDirectiveEven(SMLoc L);
+ bool parseDirectivePersonalityIndex(SMLoc L);
+ bool parseDirectiveUnwindRaw(SMLoc L);
+ bool parseDirectiveTLSDescSeq(SMLoc L);
+ bool parseDirectiveMovSP(SMLoc L);
+ bool parseDirectiveObjectArch(SMLoc L);
+ bool parseDirectiveArchExtension(SMLoc L);
+ bool parseDirectiveAlign(SMLoc L);
+ bool parseDirectiveThumbSet(SMLoc L);
StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
bool &CarrySetting, unsigned &ProcessorIMod,
const SmallVectorImpl<MCParsedAsmOperand*> &);
void cvtThumbBranches(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &);
-
+
bool validateInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
bool processInstruction(MCInst &Inst,
ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser,
const MCInstrInfo &MII)
- : MCTargetAsmParser(), STI(_STI), Parser(_Parser), MII(MII), FPReg(-1) {
+ : MCTargetAsmParser(), STI(_STI), Parser(_Parser), MII(MII), UC(_Parser) {
MCAsmParserExtension::Initialize(_Parser);
// Cache the MCRegisterInfo.
}
// Implementation of the MCTargetAsmParser interface:
- bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
- bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
- SMLoc NameLoc,
- SmallVectorImpl<MCParsedAsmOperand*> &Operands);
- bool ParseDirective(AsmToken DirectiveID);
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
+ bool
+ ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc,
+ SmallVectorImpl<MCParsedAsmOperand*> &Operands) override;
+ bool ParseDirective(AsmToken DirectiveID) override;
- unsigned validateTargetOperandClass(MCParsedAsmOperand *Op, unsigned Kind);
- unsigned checkTargetMatchPredicate(MCInst &Inst);
+ unsigned validateTargetOperandClass(MCParsedAsmOperand *Op,
+ unsigned Kind) override;
+ unsigned checkTargetMatchPredicate(MCInst &Inst) override;
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
MCStreamer &Out, unsigned &ErrorInfo,
- bool MatchingInlineAsm);
- void onLabelParsed(MCSymbol *Symbol);
- void finishParse();
+ bool MatchingInlineAsm) override;
+ void onLabelParsed(MCSymbol *Symbol) override;
};
} // end anonymous namespace
}
/// getStartLoc - Get the location of the first token of this operand.
- SMLoc getStartLoc() const { return StartLoc; }
+ SMLoc getStartLoc() const override { return StartLoc; }
/// getEndLoc - Get the location of the last token of this operand.
- SMLoc getEndLoc() const { return EndLoc; }
+ SMLoc getEndLoc() const override { return EndLoc; }
/// getLocRange - Get the range between the first and last token of this
/// operand.
SMRange getLocRange() const { return SMRange(StartLoc, EndLoc); }
return StringRef(Tok.Data, Tok.Length);
}
- unsigned getReg() const {
+ unsigned getReg() const override {
assert((Kind == k_Register || Kind == k_CCOut) && "Invalid access!");
return Reg.RegNum;
}
bool isCCOut() const { return Kind == k_CCOut; }
bool isITMask() const { return Kind == k_ITCondMask; }
bool isITCondCode() const { return Kind == k_CondCode; }
- bool isImm() const { return Kind == k_Immediate; }
+ bool isImm() const override { return Kind == k_Immediate; }
// checks whether this operand is an unsigned offset which fits is a field
// of specified width and scaled by a specific number of bits
template<unsigned width, unsigned scale>
int64_t Value = CE->getValue();
return Value == 1 || Value == 0;
}
- bool isReg() const { return Kind == k_Register; }
+ bool isReg() const override { return Kind == k_Register; }
bool isRegList() const { return Kind == k_RegisterList; }
bool isDPRRegList() const { return Kind == k_DPRRegisterList; }
bool isSPRRegList() const { return Kind == k_SPRRegisterList; }
- bool isToken() const { return Kind == k_Token; }
+ bool isToken() const override { return Kind == k_Token; }
bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; }
bool isInstSyncBarrierOpt() const { return Kind == k_InstSyncBarrierOpt; }
- bool isMem() const { return Kind == k_Memory; }
+ bool isMem() const override { return Kind == k_Memory; }
bool isShifterImm() const { return Kind == k_ShifterImmediate; }
bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; }
bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; }
Inst.addOperand(MCOperand::CreateImm(Imm | 0x1e00));
}
- virtual void print(raw_ostream &OS) const;
+ void print(raw_ostream &OS) const override;
static ARMOperand *CreateITMask(unsigned Mask, SMLoc S) {
ARMOperand *Op = new ARMOperand(k_ITCondMask);
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
- assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
+ if (Tok.isNot(AsmToken::Identifier))
+ return -1;
std::string lowerCase = Tok.getString().lower();
ARM_AM::ShiftOpc ShiftTy = StringSwitch<ARM_AM::ShiftOpc>(lowerCase)
Error(Loc, "illegal expression");
return MatchOperand_ParseFail;
}
-
+
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(MemBarrierID);
if (!CE) {
Error(Loc, "constant expression expected");
isAdd = false;
haveEaten = true;
}
-
+
Tok = Parser.getTok();
int Reg = tryParseRegister();
if (Reg == -1) {
break;
}
}
-
+
// now decide on encoding size based on branch target range
switch(Inst.getOpcode()) {
// classify tB as either t2B or t1B based on range of immediate operand
// for these:
// vmov.i{8|16|32|64} <dreg|qreg>, #imm
ARMOperand *TyOp = static_cast<ARMOperand*>(Operands[2]);
- if (!TyOp->isToken() || (TyOp->getToken() != ".f32" &&
- TyOp->getToken() != ".f64"))
+ bool isVmovf = TyOp->isToken() && (TyOp->getToken() == ".f32" ||
+ TyOp->getToken() == ".f64");
+ ARMOperand *Mnemonic = static_cast<ARMOperand*>(Operands[0]);
+ bool isFconst = Mnemonic->isToken() && (Mnemonic->getToken() == "fconstd" ||
+ Mnemonic->getToken() == "fconsts");
+ if (!(isVmovf || isFconst))
return MatchOperand_NoMatch;
Parser.Lex(); // Eat '#' or '$'.
}
const AsmToken &Tok = Parser.getTok();
SMLoc Loc = Tok.getLoc();
- if (Tok.is(AsmToken::Real)) {
+ if (Tok.is(AsmToken::Real) && isVmovf) {
APFloat RealVal(APFloat::IEEEsingle, Tok.getString());
uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
// If we had a '-' in front, toggle the sign bit.
}
// Also handle plain integers. Instructions which allow floating point
// immediates also allow a raw encoded 8-bit value.
- if (Tok.is(AsmToken::Integer)) {
+ if (Tok.is(AsmToken::Integer) && isFconst) {
int64_t Val = Tok.getIntVal();
Parser.Lex(); // Eat the token.
if (Val > 255 || Val < 0) {
Error(Loc, "encoded floating point value out of range");
return MatchOperand_ParseFail;
}
- double RealVal = ARM_AM::getFPImmFloat(Val);
- Val = APFloat(APFloat::IEEEdouble, RealVal).bitcastToAPInt().getZExtValue();
+ float RealVal = ARM_AM::getFPImmFloat(Val);
+ Val = APFloat(RealVal).bitcastToAPInt().getZExtValue();
+
Operands.push_back(ARMOperand::CreateImm(
MCConstantExpr::Create(Val, getContext()), S,
Parser.getTok().getLoc()));
if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val)
return Error(Parser.getTok().getLoc(), "unexpected token in operand");
- const MCSection *Section =
- getParser().getStreamer().getCurrentSection().first;
- assert(Section);
Parser.Lex(); // Eat '='
const MCExpr *SubExprVal;
if (getParser().parseExpression(SubExprVal))
return true;
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
- const MCExpr *CPLoc =
- getOrCreateConstantPool(Section).addEntry(SubExprVal, getContext());
+ const MCExpr *CPLoc = getTargetStreamer().addConstantPoolEntry(SubExprVal);
Operands.push_back(ARMOperand::CreateImm(CPLoc, S, E));
return false;
}
bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) {
RefKind = ARMMCExpr::VK_ARM_None;
+ // consume an optional '#' (GNU compatibility)
+ if (getLexer().is(AsmToken::Hash))
+ Parser.Lex();
+
// :lower16: and :upper16: modifiers
assert(getLexer().is(AsmToken::Colon) && "expected a :");
Parser.Lex(); // Eat ':'
Mnemonic == "fmrs" || Mnemonic == "fsqrts" || Mnemonic == "fsubs" ||
Mnemonic == "fsts" || Mnemonic == "fcpys" || Mnemonic == "fdivs" ||
Mnemonic == "fmuls" || Mnemonic == "fcmps" || Mnemonic == "fcmpzs" ||
- Mnemonic == "vfms" || Mnemonic == "vfnms" ||
+ Mnemonic == "vfms" || Mnemonic == "vfnms" || Mnemonic == "fconsts" ||
(Mnemonic == "movs" && isThumb()))) {
Mnemonic = Mnemonic.slice(0, Mnemonic.size() - 1);
CarrySetting = true;
}
static void applyMnemonicAliases(StringRef &Mnemonic, unsigned Features,
unsigned VariantID);
+
+static bool RequiresVFPRegListValidation(StringRef Inst,
+ bool &AcceptSinglePrecisionOnly,
+ bool &AcceptDoublePrecisionOnly) {
+ if (Inst.size() < 7)
+ return false;
+
+ if (Inst.startswith("fldm") || Inst.startswith("fstm")) {
+ StringRef AddressingMode = Inst.substr(4, 2);
+ if (AddressingMode == "ia" || AddressingMode == "db" ||
+ AddressingMode == "ea" || AddressingMode == "fd") {
+ AcceptSinglePrecisionOnly = Inst[6] == 's';
+ AcceptDoublePrecisionOnly = Inst[6] == 'd' || Inst[6] == 'x';
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// Parse an arm instruction mnemonic followed by its operands.
bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc,
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
// FIXME: Can this be done via tablegen in some fashion?
- bool HasPrecisionRestrictions;
- bool AcceptDoublePrecisionOnly;
+ bool RequireVFPRegisterListCheck;
bool AcceptSinglePrecisionOnly;
- HasPrecisionRestrictions = Name.startswith("fldm") || Name.startswith("fstm");
- AcceptDoublePrecisionOnly =
- HasPrecisionRestrictions && (Name.back() == 'd' || Name.back() == 'x');
- AcceptSinglePrecisionOnly = HasPrecisionRestrictions && Name.back() == 's';
+ bool AcceptDoublePrecisionOnly;
+ RequireVFPRegisterListCheck =
+ RequiresVFPRegListValidation(Name, AcceptSinglePrecisionOnly,
+ AcceptDoublePrecisionOnly);
// Apply mnemonic aliases before doing anything else, as the destination
// mnemonic may include suffices and we want to handle them normally.
// For for ARM mode generate an error if the .n qualifier is used.
if (ExtraToken == ".n" && !isThumb()) {
SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Start);
+ Parser.eatToEndOfStatement();
return Error(Loc, "instruction with .n (narrow) qualifier not allowed in "
"arm mode");
}
Parser.Lex(); // Consume the EndOfStatement
- if (HasPrecisionRestrictions) {
+ if (RequireVFPRegisterListCheck) {
ARMOperand *Op = static_cast<ARMOperand*>(Operands.back());
- assert(Op->isRegList());
- const SmallVectorImpl<unsigned> &RegList = Op->getRegList();
- for (SmallVectorImpl<unsigned>::const_iterator RLI = RegList.begin(),
- RLE = RegList.end();
- RLI != RLE; ++RLI) {
- if (AcceptSinglePrecisionOnly &&
- !ARMMCRegisterClasses[ARM::SPRRegClassID].contains(*RLI))
- return Error(Op->getStartLoc(),
- "VFP/Neon single precision register expected");
- else if (AcceptDoublePrecisionOnly &&
- !ARMMCRegisterClasses[ARM::DPRRegClassID].contains(*RLI))
- return Error(Op->getStartLoc(),
- "VFP/Neon double precision register expected");
- else
- llvm_unreachable("must have single or double precision restrictions");
- }
+ if (AcceptSinglePrecisionOnly && !Op->isSPRRegList())
+ return Error(Op->getStartLoc(),
+ "VFP/Neon single precision register expected");
+ if (AcceptDoublePrecisionOnly && !Op->isDPRRegList())
+ return Error(Op->getStartLoc(),
+ "VFP/Neon double precision register expected");
}
// Some instructions, mostly Thumb, have forms for the same mnemonic that
}
}
+ // GNU Assembler extension (compatibility)
+ if ((Mnemonic == "ldrd" || Mnemonic == "strd") && !isThumb() &&
+ Operands.size() == 4) {
+ ARMOperand *Op = static_cast<ARMOperand *>(Operands[2]);
+ assert(Op->isReg() && "expected register argument");
+ assert(MRI->getMatchingSuperReg(Op->getReg(), ARM::gsub_0,
+ &MRI->getRegClass(ARM::GPRPairRegClassID))
+ && "expected register pair");
+ Operands.insert(Operands.begin() + 3,
+ ARMOperand::CreateReg(Op->getReg() + 1, Op->getStartLoc(),
+ Op->getEndLoc()));
+ }
+
// FIXME: As said above, this is all a pretty gross hack. This instruction
// does not fit with other "subs" and tblgen.
// Adjust operands of B9.3.19 SUBS PC, LR, #imm (Thumb2) system instruction
case ARM::sysSTMIB_UPD:
return Error(Operands[2]->getStartLoc(),
"system STM cannot have writeback register");
- break;
case ARM::tMUL: {
// The second source operand must be the same register as the destination
// operand.
processInstruction(MCInst &Inst,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
switch (Inst.getOpcode()) {
+ // Alias for alternate form of 'ldr{,b}t Rt, [Rn], #imm' instruction.
+ case ARM::LDRT_POST:
+ case ARM::LDRBT_POST: {
+ const unsigned Opcode =
+ (Inst.getOpcode() == ARM::LDRT_POST) ? ARM::LDRT_POST_IMM
+ : ARM::LDRBT_POST_IMM;
+ MCInst TmpInst;
+ TmpInst.setOpcode(Opcode);
+ TmpInst.addOperand(Inst.getOperand(0));
+ TmpInst.addOperand(Inst.getOperand(1));
+ TmpInst.addOperand(Inst.getOperand(1));
+ TmpInst.addOperand(MCOperand::CreateReg(0));
+ TmpInst.addOperand(MCOperand::CreateImm(0));
+ TmpInst.addOperand(Inst.getOperand(2));
+ TmpInst.addOperand(Inst.getOperand(3));
+ Inst = TmpInst;
+ return true;
+ }
+ // Alias for alternate form of 'str{,b}t Rt, [Rn], #imm' instruction.
+ case ARM::STRT_POST:
+ case ARM::STRBT_POST: {
+ const unsigned Opcode =
+ (Inst.getOpcode() == ARM::STRT_POST) ? ARM::STRT_POST_IMM
+ : ARM::STRBT_POST_IMM;
+ MCInst TmpInst;
+ TmpInst.setOpcode(Opcode);
+ TmpInst.addOperand(Inst.getOperand(1));
+ TmpInst.addOperand(Inst.getOperand(0));
+ TmpInst.addOperand(Inst.getOperand(1));
+ TmpInst.addOperand(MCOperand::CreateReg(0));
+ TmpInst.addOperand(MCOperand::CreateImm(0));
+ TmpInst.addOperand(Inst.getOperand(2));
+ TmpInst.addOperand(Inst.getOperand(3));
+ Inst = TmpInst;
+ return true;
+ }
// Alias for alternate form of 'ADR Rd, #imm' instruction.
case ARM::ADDri: {
if (Inst.getOperand(1).getReg() != ARM::PC ||
return Match_Success;
}
+template<> inline bool IsCPSRDead<MCInst>(MCInst* Instr) {
+ return true; // In an assembly source, no need to second-guess
+}
+
static const char *getSubtargetFeatureName(unsigned Val);
bool ARMAsmParser::
MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
// Only after the instruction is fully processed, we can validate it
if (wasInITBlock && hasV8Ops() && isThumb() &&
- !isV8EligibleForIT(&Inst, 2)) {
+ !isV8EligibleForIT(&Inst)) {
Warning(IDLoc, "deprecated instruction in IT block");
}
}
return false;
Inst.setLoc(IDLoc);
- Out.EmitInstruction(Inst);
+ Out.EmitInstruction(Inst, STI);
return false;
case Match_MissingFeature: {
assert(ErrorInfo && "Unknown missing feature!");
bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
StringRef IDVal = DirectiveID.getIdentifier();
if (IDVal == ".word")
- return parseDirectiveWord(4, DirectiveID.getLoc());
+ return parseLiteralValues(4, DirectiveID.getLoc());
+ else if (IDVal == ".short" || IDVal == ".hword")
+ return parseLiteralValues(2, DirectiveID.getLoc());
else if (IDVal == ".thumb")
return parseDirectiveThumb(DirectiveID.getLoc());
else if (IDVal == ".arm")
return parseDirectiveLtorg(DirectiveID.getLoc());
else if (IDVal == ".even")
return parseDirectiveEven(DirectiveID.getLoc());
+ else if (IDVal == ".personalityindex")
+ return parseDirectivePersonalityIndex(DirectiveID.getLoc());
+ else if (IDVal == ".unwind_raw")
+ return parseDirectiveUnwindRaw(DirectiveID.getLoc());
+ else if (IDVal == ".tlsdescseq")
+ return parseDirectiveTLSDescSeq(DirectiveID.getLoc());
+ else if (IDVal == ".movsp")
+ return parseDirectiveMovSP(DirectiveID.getLoc());
+ else if (IDVal == ".object_arch")
+ return parseDirectiveObjectArch(DirectiveID.getLoc());
+ else if (IDVal == ".arch_extension")
+ return parseDirectiveArchExtension(DirectiveID.getLoc());
+ else if (IDVal == ".align")
+ return parseDirectiveAlign(DirectiveID.getLoc());
+ else if (IDVal == ".thumb_set")
+ return parseDirectiveThumbSet(DirectiveID.getLoc());
return true;
}
-/// parseDirectiveWord
-/// ::= .word [ expression (, expression)* ]
-bool ARMAsmParser::parseDirectiveWord(unsigned Size, SMLoc L) {
+/// parseLiteralValues
+/// ::= .hword expression [, expression]*
+/// ::= .short expression [, expression]*
+/// ::= .word expression [, expression]*
+bool ARMAsmParser::parseLiteralValues(unsigned Size, SMLoc L) {
if (getLexer().isNot(AsmToken::EndOfStatement)) {
for (;;) {
const MCExpr *Value;
- if (getParser().parseExpression(Value))
- return true;
+ if (getParser().parseExpression(Value)) {
+ Parser.eatToEndOfStatement();
+ return false;
+ }
getParser().getStreamer().EmitValue(Value, Size);
break;
// FIXME: Improve diagnostic.
- if (getLexer().isNot(AsmToken::Comma))
- return Error(L, "unexpected token in directive");
+ if (getLexer().isNot(AsmToken::Comma)) {
+ Error(L, "unexpected token in directive");
+ return false;
+ }
Parser.Lex();
}
}
/// parseDirectiveThumb
/// ::= .thumb
bool ARMAsmParser::parseDirectiveThumb(SMLoc L) {
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return Error(L, "unexpected token in directive");
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ Error(L, "unexpected token in directive");
+ return false;
+ }
Parser.Lex();
- if (!hasThumb())
- return Error(L, "target does not support Thumb mode");
+ if (!hasThumb()) {
+ Error(L, "target does not support Thumb mode");
+ return false;
+ }
if (!isThumb())
SwitchMode();
+
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
return false;
}
/// parseDirectiveARM
/// ::= .arm
bool ARMAsmParser::parseDirectiveARM(SMLoc L) {
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return Error(L, "unexpected token in directive");
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ Error(L, "unexpected token in directive");
+ return false;
+ }
Parser.Lex();
- if (!hasARM())
- return Error(L, "target does not support ARM mode");
+ if (!hasARM()) {
+ Error(L, "target does not support ARM mode");
+ return false;
+ }
if (isThumb())
SwitchMode();
+
getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
return false;
}
if (NextSymbolIsThumb) {
getParser().getStreamer().EmitThumbFunc(Symbol);
NextSymbolIsThumb = false;
+ return;
+ }
+
+ if (!isThumb())
+ return;
+
+ const MCObjectFileInfo::Environment Format =
+ getContext().getObjectFileInfo()->getObjectFileType();
+ switch (Format) {
+ case MCObjectFileInfo::IsCOFF: {
+ const MCSymbolData &SD =
+ getParser().getStreamer().getOrCreateSymbolData(Symbol);
+ char Type = COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT;
+ if (SD.getFlags() & (Type << COFF::SF_TypeShift))
+ getParser().getStreamer().EmitThumbFunc(Symbol);
+ break;
+ }
+ case MCObjectFileInfo::IsELF: {
+ const MCSymbolData &SD =
+ getParser().getStreamer().getOrCreateSymbolData(Symbol);
+ if (MCELF::GetType(SD) & (ELF::STT_FUNC << ELF_STT_Shift))
+ getParser().getStreamer().EmitThumbFunc(Symbol);
+ break;
+ }
+ case MCObjectFileInfo::IsMachO:
+ break;
}
}
if (isMachO) {
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::EndOfStatement)) {
- if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String))
- return Error(L, "unexpected token in .thumb_func directive");
+ if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) {
+ Error(L, "unexpected token in .thumb_func directive");
+ return false;
+ }
+
MCSymbol *Func =
getParser().getContext().GetOrCreateSymbol(Tok.getIdentifier());
getParser().getStreamer().EmitThumbFunc(Func);
}
}
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return Error(L, "unexpected token in directive");
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ Error(L, "unexpected token in directive");
+ return false;
+ }
NextSymbolIsThumb = true;
-
return false;
}
/// ::= .syntax unified | divided
bool ARMAsmParser::parseDirectiveSyntax(SMLoc L) {
const AsmToken &Tok = Parser.getTok();
- if (Tok.isNot(AsmToken::Identifier))
- return Error(L, "unexpected token in .syntax directive");
+ if (Tok.isNot(AsmToken::Identifier)) {
+ Error(L, "unexpected token in .syntax directive");
+ return false;
+ }
+
StringRef Mode = Tok.getString();
- if (Mode == "unified" || Mode == "UNIFIED")
+ if (Mode == "unified" || Mode == "UNIFIED") {
Parser.Lex();
- else if (Mode == "divided" || Mode == "DIVIDED")
- return Error(L, "'.syntax divided' arm asssembly not supported");
- else
- return Error(L, "unrecognized syntax mode in .syntax directive");
+ } else if (Mode == "divided" || Mode == "DIVIDED") {
+ Error(L, "'.syntax divided' arm asssembly not supported");
+ return false;
+ } else {
+ Error(L, "unrecognized syntax mode in .syntax directive");
+ return false;
+ }
if (getLexer().isNot(AsmToken::EndOfStatement)) {
Error(Parser.getTok().getLoc(), "unexpected token in directive");
Error(L, "unexpected input in .unreq directive.");
return false;
}
- RegisterReqs.erase(Parser.getTok().getIdentifier());
+ RegisterReqs.erase(Parser.getTok().getIdentifier().lower());
Parser.Lex(); // Eat the identifier.
return false;
}
}
/// parseDirectiveEabiAttr
-/// ::= .eabi_attribute int, int
+/// ::= .eabi_attribute int, int [, "str"]
+/// ::= .eabi_attribute Tag_name, int [, "str"]
bool ARMAsmParser::parseDirectiveEabiAttr(SMLoc L) {
- if (Parser.getTok().isNot(AsmToken::Integer)) {
- Error(L, "integer expected");
- return false;
+ int64_t Tag;
+ SMLoc TagLoc;
+
+ TagLoc = Parser.getTok().getLoc();
+ if (Parser.getTok().is(AsmToken::Identifier)) {
+ StringRef Name = Parser.getTok().getIdentifier();
+ Tag = ARMBuildAttrs::AttrTypeFromString(Name);
+ if (Tag == -1) {
+ Error(TagLoc, "attribute name not recognised: " + Name);
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+ Parser.Lex();
+ } else {
+ const MCExpr *AttrExpr;
+
+ TagLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(AttrExpr)) {
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr);
+ if (!CE) {
+ Error(TagLoc, "expected numeric constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ Tag = CE->getValue();
}
- int64_t Tag = Parser.getTok().getIntVal();
- Parser.Lex(); // eat tag integer
if (Parser.getTok().isNot(AsmToken::Comma)) {
- Error(L, "comma expected");
+ Error(Parser.getTok().getLoc(), "comma expected");
+ Parser.eatToEndOfStatement();
return false;
}
Parser.Lex(); // skip comma
- L = Parser.getTok().getLoc();
- if (Parser.getTok().isNot(AsmToken::Integer)) {
- Error(L, "integer expected");
- return false;
+ StringRef StringValue = "";
+ bool IsStringValue = false;
+
+ int64_t IntegerValue = 0;
+ bool IsIntegerValue = false;
+
+ if (Tag == ARMBuildAttrs::CPU_raw_name || Tag == ARMBuildAttrs::CPU_name)
+ IsStringValue = true;
+ else if (Tag == ARMBuildAttrs::compatibility) {
+ IsStringValue = true;
+ IsIntegerValue = true;
+ } else if (Tag < 32 || Tag % 2 == 0)
+ IsIntegerValue = true;
+ else if (Tag % 2 == 1)
+ IsStringValue = true;
+ else
+ llvm_unreachable("invalid tag type");
+
+ if (IsIntegerValue) {
+ const MCExpr *ValueExpr;
+ SMLoc ValueExprLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(ValueExpr)) {
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr);
+ if (!CE) {
+ Error(ValueExprLoc, "expected numeric constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ IntegerValue = CE->getValue();
}
- int64_t Value = Parser.getTok().getIntVal();
- Parser.Lex(); // eat value integer
- getTargetStreamer().emitAttribute(Tag, Value);
+ if (Tag == ARMBuildAttrs::compatibility) {
+ if (Parser.getTok().isNot(AsmToken::Comma))
+ IsStringValue = false;
+ else
+ Parser.Lex();
+ }
+
+ if (IsStringValue) {
+ if (Parser.getTok().isNot(AsmToken::String)) {
+ Error(Parser.getTok().getLoc(), "bad string constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ StringValue = Parser.getTok().getStringContents();
+ Parser.Lex();
+ }
+
+ if (IsIntegerValue && IsStringValue) {
+ assert(Tag == ARMBuildAttrs::compatibility);
+ getTargetStreamer().emitIntTextAttribute(Tag, IntegerValue, StringValue);
+ } else if (IsIntegerValue)
+ getTargetStreamer().emitAttribute(Tag, IntegerValue);
+ else if (IsStringValue)
+ getTargetStreamer().emitTextAttribute(Tag, StringValue);
return false;
}
/// parseDirectiveFnStart
/// ::= .fnstart
bool ARMAsmParser::parseDirectiveFnStart(SMLoc L) {
- if (FnStartLoc.isValid()) {
+ if (UC.hasFnStart()) {
Error(L, ".fnstart starts before the end of previous one");
- Error(FnStartLoc, "previous .fnstart starts here");
+ UC.emitFnStartLocNotes();
return false;
}
- FnStartLoc = L;
+ // Reset the unwind directives parser state
+ UC.reset();
+
getTargetStreamer().emitFnStart();
+
+ UC.recordFnStart(L);
return false;
}
/// ::= .fnend
bool ARMAsmParser::parseDirectiveFnEnd(SMLoc L) {
// Check the ordering of unwind directives
- if (!FnStartLoc.isValid()) {
+ if (!UC.hasFnStart()) {
Error(L, ".fnstart must precede .fnend directive");
return false;
}
// Reset the unwind directives parser state
- resetUnwindDirectiveParserState();
getTargetStreamer().emitFnEnd();
+
+ UC.reset();
return false;
}
/// parseDirectiveCantUnwind
/// ::= .cantunwind
bool ARMAsmParser::parseDirectiveCantUnwind(SMLoc L) {
+ UC.recordCantUnwind(L);
+
// Check the ordering of unwind directives
- CantUnwindLoc = L;
- if (!FnStartLoc.isValid()) {
+ if (!UC.hasFnStart()) {
Error(L, ".fnstart must precede .cantunwind directive");
return false;
}
- if (HandlerDataLoc.isValid()) {
+ if (UC.hasHandlerData()) {
Error(L, ".cantunwind can't be used with .handlerdata directive");
- Error(HandlerDataLoc, ".handlerdata was specified here");
+ UC.emitHandlerDataLocNotes();
return false;
}
- if (PersonalityLoc.isValid()) {
+ if (UC.hasPersonality()) {
Error(L, ".cantunwind can't be used with .personality directive");
- Error(PersonalityLoc, ".personality was specified here");
+ UC.emitPersonalityLocNotes();
return false;
}
/// parseDirectivePersonality
/// ::= .personality name
bool ARMAsmParser::parseDirectivePersonality(SMLoc L) {
+ bool HasExistingPersonality = UC.hasPersonality();
+
+ UC.recordPersonality(L);
+
// Check the ordering of unwind directives
- PersonalityLoc = L;
- if (!FnStartLoc.isValid()) {
+ if (!UC.hasFnStart()) {
Error(L, ".fnstart must precede .personality directive");
return false;
}
- if (CantUnwindLoc.isValid()) {
+ if (UC.cantUnwind()) {
Error(L, ".personality can't be used with .cantunwind directive");
- Error(CantUnwindLoc, ".cantunwind was specified here");
+ UC.emitCantUnwindLocNotes();
return false;
}
- if (HandlerDataLoc.isValid()) {
+ if (UC.hasHandlerData()) {
Error(L, ".personality must precede .handlerdata directive");
- Error(HandlerDataLoc, ".handlerdata was specified here");
+ UC.emitHandlerDataLocNotes();
+ return false;
+ }
+ if (HasExistingPersonality) {
+ Parser.eatToEndOfStatement();
+ Error(L, "multiple personality directives");
+ UC.emitPersonalityLocNotes();
return false;
}
/// parseDirectiveHandlerData
/// ::= .handlerdata
bool ARMAsmParser::parseDirectiveHandlerData(SMLoc L) {
+ UC.recordHandlerData(L);
+
// Check the ordering of unwind directives
- HandlerDataLoc = L;
- if (!FnStartLoc.isValid()) {
+ if (!UC.hasFnStart()) {
Error(L, ".fnstart must precede .personality directive");
return false;
}
- if (CantUnwindLoc.isValid()) {
+ if (UC.cantUnwind()) {
Error(L, ".handlerdata can't be used with .cantunwind directive");
- Error(CantUnwindLoc, ".cantunwind was specified here");
+ UC.emitCantUnwindLocNotes();
return false;
}
/// ::= .setfp fpreg, spreg [, offset]
bool ARMAsmParser::parseDirectiveSetFP(SMLoc L) {
// Check the ordering of unwind directives
- if (!FnStartLoc.isValid()) {
+ if (!UC.hasFnStart()) {
Error(L, ".fnstart must precede .setfp directive");
return false;
}
- if (HandlerDataLoc.isValid()) {
+ if (UC.hasHandlerData()) {
Error(L, ".setfp must precede .handlerdata directive");
return false;
}
// Parse fpreg
- SMLoc NewFPRegLoc = Parser.getTok().getLoc();
- int NewFPReg = tryParseRegister();
- if (NewFPReg == -1) {
- Error(NewFPRegLoc, "frame pointer register expected");
+ SMLoc FPRegLoc = Parser.getTok().getLoc();
+ int FPReg = tryParseRegister();
+ if (FPReg == -1) {
+ Error(FPRegLoc, "frame pointer register expected");
return false;
}
// Consume comma
- if (!Parser.getTok().is(AsmToken::Comma)) {
+ if (Parser.getTok().isNot(AsmToken::Comma)) {
Error(Parser.getTok().getLoc(), "comma expected");
return false;
}
Parser.Lex(); // skip comma
// Parse spreg
- SMLoc NewSPRegLoc = Parser.getTok().getLoc();
- int NewSPReg = tryParseRegister();
- if (NewSPReg == -1) {
- Error(NewSPRegLoc, "stack pointer register expected");
+ SMLoc SPRegLoc = Parser.getTok().getLoc();
+ int SPReg = tryParseRegister();
+ if (SPReg == -1) {
+ Error(SPRegLoc, "stack pointer register expected");
return false;
}
- if (NewSPReg != ARM::SP && NewSPReg != FPReg) {
- Error(NewSPRegLoc,
- "register should be either $sp or the latest fp register");
+ if (SPReg != ARM::SP && SPReg != UC.getFPReg()) {
+ Error(SPRegLoc, "register should be either $sp or the latest fp register");
return false;
}
// Update the frame pointer register
- FPReg = NewFPReg;
+ UC.saveFPReg(FPReg);
// Parse offset
int64_t Offset = 0;
Offset = CE->getValue();
}
- getTargetStreamer().emitSetFP(static_cast<unsigned>(NewFPReg),
- static_cast<unsigned>(NewSPReg), Offset);
+ getTargetStreamer().emitSetFP(static_cast<unsigned>(FPReg),
+ static_cast<unsigned>(SPReg), Offset);
return false;
}
/// ::= .pad offset
bool ARMAsmParser::parseDirectivePad(SMLoc L) {
// Check the ordering of unwind directives
- if (!FnStartLoc.isValid()) {
+ if (!UC.hasFnStart()) {
Error(L, ".fnstart must precede .pad directive");
return false;
}
- if (HandlerDataLoc.isValid()) {
+ if (UC.hasHandlerData()) {
Error(L, ".pad must precede .handlerdata directive");
return false;
}
/// ::= .vsave { registers }
bool ARMAsmParser::parseDirectiveRegSave(SMLoc L, bool IsVector) {
// Check the ordering of unwind directives
- if (!FnStartLoc.isValid()) {
+ if (!UC.hasFnStart()) {
Error(L, ".fnstart must precede .save or .vsave directives");
return false;
}
- if (HandlerDataLoc.isValid()) {
+ if (UC.hasHandlerData()) {
Error(L, ".save or .vsave must precede .handlerdata directive");
return false;
}
// Parse the register list
if (parseRegisterList(CO.Operands))
- return true;
+ return false;
ARMOperand *Op = (ARMOperand*)CO.Operands[0];
if (!IsVector && !Op->isRegList()) {
Error(L, ".save expects GPR registers");
/// parseDirectiveLtorg
/// ::= .ltorg | .pool
bool ARMAsmParser::parseDirectiveLtorg(SMLoc L) {
- MCStreamer &Streamer = getParser().getStreamer();
- const MCSection *Section = Streamer.getCurrentSection().first;
-
- if (ConstantPool *CP = getConstantPool(Section)) {
- if (!CP->empty())
- CP->emitEntries(Streamer);
- }
+ getTargetStreamer().emitCurrentConstantPool();
return false;
}
}
if (!Section) {
- getStreamer().InitToTextSection();
+ getStreamer().InitSections();
Section = getStreamer().getCurrentSection().first;
}
+ assert(Section && "must have section to emit alignment");
if (Section->UseCodeAlign())
- getStreamer().EmitCodeAlignment(2, 0);
+ getStreamer().EmitCodeAlignment(2);
else
- getStreamer().EmitValueToAlignment(2, 0, 1, 0);
+ getStreamer().EmitValueToAlignment(2);
+
+ return false;
+}
+
+/// parseDirectivePersonalityIndex
+/// ::= .personalityindex index
+bool ARMAsmParser::parseDirectivePersonalityIndex(SMLoc L) {
+ bool HasExistingPersonality = UC.hasPersonality();
+
+ UC.recordPersonalityIndex(L);
+
+ if (!UC.hasFnStart()) {
+ Parser.eatToEndOfStatement();
+ Error(L, ".fnstart must precede .personalityindex directive");
+ return false;
+ }
+ if (UC.cantUnwind()) {
+ Parser.eatToEndOfStatement();
+ Error(L, ".personalityindex cannot be used with .cantunwind");
+ UC.emitCantUnwindLocNotes();
+ return false;
+ }
+ if (UC.hasHandlerData()) {
+ Parser.eatToEndOfStatement();
+ Error(L, ".personalityindex must precede .handlerdata directive");
+ UC.emitHandlerDataLocNotes();
+ return false;
+ }
+ if (HasExistingPersonality) {
+ Parser.eatToEndOfStatement();
+ Error(L, "multiple personality directives");
+ UC.emitPersonalityLocNotes();
+ return false;
+ }
+
+ const MCExpr *IndexExpression;
+ SMLoc IndexLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(IndexExpression)) {
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(IndexExpression);
+ if (!CE) {
+ Parser.eatToEndOfStatement();
+ Error(IndexLoc, "index must be a constant number");
+ return false;
+ }
+ if (CE->getValue() < 0 ||
+ CE->getValue() >= ARM::EHABI::NUM_PERSONALITY_INDEX) {
+ Parser.eatToEndOfStatement();
+ Error(IndexLoc, "personality routine index should be in range [0-3]");
+ return false;
+ }
+
+ getTargetStreamer().emitPersonalityIndex(CE->getValue());
+ return false;
+}
+
+/// parseDirectiveUnwindRaw
+/// ::= .unwind_raw offset, opcode [, opcode...]
+bool ARMAsmParser::parseDirectiveUnwindRaw(SMLoc L) {
+ if (!UC.hasFnStart()) {
+ Parser.eatToEndOfStatement();
+ Error(L, ".fnstart must precede .unwind_raw directives");
+ return false;
+ }
+
+ int64_t StackOffset;
+
+ const MCExpr *OffsetExpr;
+ SMLoc OffsetLoc = getLexer().getLoc();
+ if (getLexer().is(AsmToken::EndOfStatement) ||
+ getParser().parseExpression(OffsetExpr)) {
+ Error(OffsetLoc, "expected expression");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
+ if (!CE) {
+ Error(OffsetLoc, "offset must be a constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ StackOffset = CE->getValue();
+
+ if (getLexer().isNot(AsmToken::Comma)) {
+ Error(getLexer().getLoc(), "expected comma");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+ Parser.Lex();
+
+ SmallVector<uint8_t, 16> Opcodes;
+ for (;;) {
+ const MCExpr *OE;
+
+ SMLoc OpcodeLoc = getLexer().getLoc();
+ if (getLexer().is(AsmToken::EndOfStatement) || Parser.parseExpression(OE)) {
+ Error(OpcodeLoc, "expected opcode expression");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCConstantExpr *OC = dyn_cast<MCConstantExpr>(OE);
+ if (!OC) {
+ Error(OpcodeLoc, "opcode value must be a constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const int64_t Opcode = OC->getValue();
+ if (Opcode & ~0xff) {
+ Error(OpcodeLoc, "invalid opcode");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ Opcodes.push_back(uint8_t(Opcode));
+
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ if (getLexer().isNot(AsmToken::Comma)) {
+ Error(getLexer().getLoc(), "unexpected token in directive");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ Parser.Lex();
+ }
+
+ getTargetStreamer().emitUnwindRaw(StackOffset, Opcodes);
+
+ Parser.Lex();
+ return false;
+}
+
+/// parseDirectiveTLSDescSeq
+/// ::= .tlsdescseq tls-variable
+bool ARMAsmParser::parseDirectiveTLSDescSeq(SMLoc L) {
+ if (getLexer().isNot(AsmToken::Identifier)) {
+ TokError("expected variable after '.tlsdescseq' directive");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ const MCSymbolRefExpr *SRE =
+ MCSymbolRefExpr::Create(Parser.getTok().getIdentifier(),
+ MCSymbolRefExpr::VK_ARM_TLSDESCSEQ, getContext());
+ Lex();
+
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ Error(Parser.getTok().getLoc(), "unexpected token");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ getTargetStreamer().AnnotateTLSDescriptorSequence(SRE);
+ return false;
+}
+
+/// parseDirectiveMovSP
+/// ::= .movsp reg [, #offset]
+bool ARMAsmParser::parseDirectiveMovSP(SMLoc L) {
+ if (!UC.hasFnStart()) {
+ Parser.eatToEndOfStatement();
+ Error(L, ".fnstart must precede .movsp directives");
+ return false;
+ }
+ if (UC.getFPReg() != ARM::SP) {
+ Parser.eatToEndOfStatement();
+ Error(L, "unexpected .movsp directive");
+ return false;
+ }
+
+ SMLoc SPRegLoc = Parser.getTok().getLoc();
+ int SPReg = tryParseRegister();
+ if (SPReg == -1) {
+ Parser.eatToEndOfStatement();
+ Error(SPRegLoc, "register expected");
+ return false;
+ }
+
+ if (SPReg == ARM::SP || SPReg == ARM::PC) {
+ Parser.eatToEndOfStatement();
+ Error(SPRegLoc, "sp and pc are not permitted in .movsp directive");
+ return false;
+ }
+
+ int64_t Offset = 0;
+ if (Parser.getTok().is(AsmToken::Comma)) {
+ Parser.Lex();
+
+ if (Parser.getTok().isNot(AsmToken::Hash)) {
+ Error(Parser.getTok().getLoc(), "expected #constant");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+ Parser.Lex();
+
+ const MCExpr *OffsetExpr;
+ SMLoc OffsetLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(OffsetExpr)) {
+ Parser.eatToEndOfStatement();
+ Error(OffsetLoc, "malformed offset expression");
+ return false;
+ }
+
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(OffsetExpr);
+ if (!CE) {
+ Parser.eatToEndOfStatement();
+ Error(OffsetLoc, "offset must be an immediate constant");
+ return false;
+ }
+
+ Offset = CE->getValue();
+ }
+
+ getTargetStreamer().emitMovSP(SPReg, Offset);
+ UC.saveFPReg(SPReg);
+
+ return false;
+}
+
+/// parseDirectiveObjectArch
+/// ::= .object_arch name
+bool ARMAsmParser::parseDirectiveObjectArch(SMLoc L) {
+ if (getLexer().isNot(AsmToken::Identifier)) {
+ Error(getLexer().getLoc(), "unexpected token");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ StringRef Arch = Parser.getTok().getString();
+ SMLoc ArchLoc = Parser.getTok().getLoc();
+ getLexer().Lex();
+
+ unsigned ID = StringSwitch<unsigned>(Arch)
+#define ARM_ARCH_NAME(NAME, ID, DEFAULT_CPU_NAME, DEFAULT_CPU_ARCH) \
+ .Case(NAME, ARM::ID)
+#define ARM_ARCH_ALIAS(NAME, ID) \
+ .Case(NAME, ARM::ID)
+#include "MCTargetDesc/ARMArchName.def"
+#undef ARM_ARCH_NAME
+#undef ARM_ARCH_ALIAS
+ .Default(ARM::INVALID_ARCH);
+
+ if (ID == ARM::INVALID_ARCH) {
+ Error(ArchLoc, "unknown architecture '" + Arch + "'");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ getTargetStreamer().emitObjectArch(ID);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ Error(getLexer().getLoc(), "unexpected token");
+ Parser.eatToEndOfStatement();
+ }
+
+ return false;
+}
+
+/// parseDirectiveAlign
+/// ::= .align
+bool ARMAsmParser::parseDirectiveAlign(SMLoc L) {
+ // NOTE: if this is not the end of the statement, fall back to the target
+ // agnostic handling for this directive which will correctly handle this.
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return true;
+
+ // '.align' is target specifically handled to mean 2**2 byte alignment.
+ if (getStreamer().getCurrentSection().first->UseCodeAlign())
+ getStreamer().EmitCodeAlignment(4, 0);
+ else
+ getStreamer().EmitValueToAlignment(4, 0, 1, 0);
+
+ return false;
+}
+
+/// parseDirectiveThumbSet
+/// ::= .thumb_set name, value
+bool ARMAsmParser::parseDirectiveThumbSet(SMLoc L) {
+ StringRef Name;
+ if (Parser.parseIdentifier(Name)) {
+ TokError("expected identifier after '.thumb_set'");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ if (getLexer().isNot(AsmToken::Comma)) {
+ TokError("expected comma after name '" + Name + "'");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+ Lex();
+
+ const MCExpr *Value;
+ if (Parser.parseExpression(Value)) {
+ TokError("missing expression");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ TokError("unexpected token");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+ Lex();
+
+ MCSymbol *Alias = getContext().GetOrCreateSymbol(Name);
+ if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Value)) {
+ MCSymbol *Sym = getContext().LookupSymbol(SRE->getSymbol().getName());
+ if (!Sym->isDefined()) {
+ getStreamer().EmitSymbolAttribute(Sym, MCSA_Global);
+ getStreamer().EmitAssignment(Alias, Value);
+ return false;
+ }
+
+ const MCObjectFileInfo::Environment Format =
+ getContext().getObjectFileInfo()->getObjectFileType();
+ switch (Format) {
+ case MCObjectFileInfo::IsCOFF: {
+ char Type = COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT;
+ getStreamer().EmitCOFFSymbolType(Type);
+ // .set values are always local in COFF
+ getStreamer().EmitSymbolAttribute(Alias, MCSA_Local);
+ break;
+ }
+ case MCObjectFileInfo::IsELF:
+ getStreamer().EmitSymbolAttribute(Alias, MCSA_ELF_TypeFunction);
+ break;
+ case MCObjectFileInfo::IsMachO:
+ break;
+ }
+ }
+
+ // FIXME: set the function as being a thumb function via the assembler
+ getStreamer().EmitThumbFunc(Alias);
+ getStreamer().EmitAssignment(Alias, Value);
return false;
}
#define GET_MATCHER_IMPLEMENTATION
#include "ARMGenAsmMatcher.inc"
+static const struct ExtMapEntry {
+ const char *Extension;
+ const unsigned ArchCheck;
+ const uint64_t Features;
+} Extensions[] = {
+ { "crc", Feature_HasV8, ARM::FeatureCRC },
+ { "crypto", Feature_HasV8,
+ ARM::FeatureCrypto | ARM::FeatureNEON | ARM::FeatureFPARMv8 },
+ { "fp", Feature_HasV8, ARM::FeatureFPARMv8 },
+ { "idiv", Feature_HasV7 | Feature_IsNotMClass,
+ ARM::FeatureHWDiv | ARM::FeatureHWDivARM },
+ // FIXME: iWMMXT not supported
+ { "iwmmxt", Feature_None, 0 },
+ // FIXME: iWMMXT2 not supported
+ { "iwmmxt2", Feature_None, 0 },
+ // FIXME: Maverick not supported
+ { "maverick", Feature_None, 0 },
+ { "mp", Feature_HasV7 | Feature_IsNotMClass, ARM::FeatureMP },
+ // FIXME: ARMv6-m OS Extensions feature not checked
+ { "os", Feature_None, 0 },
+ // FIXME: Also available in ARMv6-K
+ { "sec", Feature_HasV7, ARM::FeatureTrustZone },
+ { "simd", Feature_HasV8, ARM::FeatureNEON | ARM::FeatureFPARMv8 },
+ // FIXME: Only available in A-class, isel not predicated
+ { "virt", Feature_HasV7, ARM::FeatureVirtualization },
+ // FIXME: xscale not supported
+ { "xscale", Feature_None, 0 },
+};
+
+/// parseDirectiveArchExtension
+/// ::= .arch_extension [no]feature
+bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) {
+ if (getLexer().isNot(AsmToken::Identifier)) {
+ Error(getLexer().getLoc(), "unexpected token");
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ StringRef Extension = Parser.getTok().getString();
+ SMLoc ExtLoc = Parser.getTok().getLoc();
+ getLexer().Lex();
+
+ bool EnableFeature = true;
+ if (Extension.startswith_lower("no")) {
+ EnableFeature = false;
+ Extension = Extension.substr(2);
+ }
+
+ for (unsigned EI = 0, EE = array_lengthof(Extensions); EI != EE; ++EI) {
+ if (Extensions[EI].Extension != Extension)
+ continue;
+
+ unsigned FB = getAvailableFeatures();
+ if ((FB & Extensions[EI].ArchCheck) != Extensions[EI].ArchCheck) {
+ Error(ExtLoc, "architectural extension '" + Extension + "' is not "
+ "allowed for the current base architecture");
+ return false;
+ }
+
+ if (!Extensions[EI].Features)
+ report_fatal_error("unsupported architectural extension: " + Extension);
+
+ if (EnableFeature)
+ FB |= ComputeAvailableFeatures(Extensions[EI].Features);
+ else
+ FB &= ~ComputeAvailableFeatures(Extensions[EI].Features);
+
+ setAvailableFeatures(FB);
+ return false;
+ }
+
+ Error(ExtLoc, "unknown architectural extension: " + Extension);
+ Parser.eatToEndOfStatement();
+ return false;
+}
+
// Define this matcher function after the auto-generated include so we
// have the match class enum definitions.
unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand *AsmOp,
// If the kind is a token for a literal immediate, check if our asm
// operand matches. This is for InstAliases which have a fixed-value
// immediate in the syntax.
- if (Kind == MCK__35_0 && Op->isImm()) {
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm());
- if (!CE)
- return Match_InvalidOperand;
- if (CE->getValue() == 0)
+ switch (Kind) {
+ default: break;
+ case MCK__35_0:
+ if (Op->isImm())
+ if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op->getImm()))
+ if (CE->getValue() == 0)
+ return Match_Success;
+ break;
+ case MCK_ARMSOImm:
+ if (Op->isImm()) {
+ const MCExpr *SOExpr = Op->getImm();
+ int64_t Value;
+ if (!SOExpr->EvaluateAsAbsolute(Value))
+ return Match_Success;
+ assert((Value >= INT32_MIN && Value <= INT32_MAX) &&
+ "expression value must be representiable in 32 bits");
+ }
+ break;
+ case MCK_GPRPair:
+ if (Op->isReg() &&
+ MRI->getRegClass(ARM::GPRRegClassID).contains(Op->getReg()))
return Match_Success;
+ break;
}
return Match_InvalidOperand;
}
-
-void ARMAsmParser::finishParse() {
- // Dump contents of assembler constant pools.
- MCStreamer &Streamer = getParser().getStreamer();
- for (ConstantPoolMapTy::iterator CPI = ConstantPools.begin(),
- CPE = ConstantPools.end();
- CPI != CPE; ++CPI) {
- const MCSection *Section = CPI->first;
- ConstantPool &CP = CPI->second;
-
- // Dump non-empty assembler constant pools at the end of the section.
- if (!CP.empty()) {
- Streamer.SwitchSection(Section);
- CP.emitEntries(Streamer);
- }
- }
-}