X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FAsmParser%2FARMAsmParser.cpp;h=b41b71d4b0a842d9299b24207aa5af7973771fe0;hb=d68fd9c79eeb30980c18dc3f74b2da839bb259f3;hp=129c09d2bd463b47cb182c2203826bebc16671b5;hpb=58c86910b31c569a5709466c82e2fabae2014a56;p=oota-llvm.git diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 129c09d2bd4..b41b71d4b0a 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -8,24 +8,24 @@ //===----------------------------------------------------------------------===// #include "ARM.h" +#include "ARMAddressingModes.h" +#include "ARMSubtarget.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetAsmParser.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" using namespace llvm; -namespace { -struct ARMOperand; - // The shift types for register controlled shifts in arm memory addressing enum ShiftType { Lsl, @@ -35,8 +35,12 @@ enum ShiftType { Rrx }; +namespace { + struct ARMOperand; + class ARMAsmParser : public TargetAsmParser { MCAsmParser &Parser; + TargetMachine &TM; private: MCAsmParser &getParser() const { return Parser; } @@ -47,11 +51,10 @@ private: bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } - bool MaybeParseRegister(OwningPtr &Op, bool ParseWriteBack); - - bool ParseRegisterList(OwningPtr &Op); - - bool ParseMemory(OwningPtr &Op); + int TryParseRegister(); + ARMOperand *TryParseRegisterWithWriteBack(); + ARMOperand *ParseRegisterList(); + ARMOperand *ParseMemory(); bool ParseMemoryOffsetReg(bool &Negative, bool &OffsetRegShifted, @@ -64,7 +67,7 @@ private: bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount, SMLoc &E); - bool ParseOperand(OwningPtr &Op); + ARMOperand *ParseOperand(); bool ParseDirectiveWord(unsigned Size, SMLoc L); @@ -76,49 +79,55 @@ private: bool ParseDirectiveSyntax(SMLoc L); - // TODO - For now hacked versions of the next two are in here in this file to - // allow some parser testing until the table gen versions are implemented. + bool MatchAndEmitInstruction(SMLoc IDLoc, + SmallVectorImpl &Operands, + MCStreamer &Out); /// @name Auto-generated Match Functions /// { - bool MatchInstruction(const SmallVectorImpl &Operands, - MCInst &Inst); - /// MatchRegisterName - Match the given string to a register name and return - /// its register number, or -1 if there is no match. To allow return values - /// to be used directly in register lists, arm registers have values between - /// 0 and 15. - int MatchRegisterName(const StringRef &Name); +#define GET_ASSEMBLER_HEADER +#include "ARMGenAsmMatcher.inc" /// } public: - ARMAsmParser(const Target &T, MCAsmParser &_Parser) - : TargetAsmParser(T), Parser(_Parser) {} + ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM) + : TargetAsmParser(T), Parser(_Parser), TM(_TM) { + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures( + &TM.getSubtarget())); + } - virtual bool ParseInstruction(const StringRef &Name, SMLoc NameLoc, + virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands); virtual bool ParseDirective(AsmToken DirectiveID); }; - +} // end anonymous namespace + +namespace { + /// ARMOperand - Instances of this class represent a parsed ARM machine /// instruction. struct ARMOperand : public MCParsedAsmOperand { -private: - ARMOperand() {} public: enum KindTy { - Token, - Register, + CondCode, Immediate, - Memory + Memory, + Register, + Token } Kind; SMLoc StartLoc, EndLoc; union { + struct { + ARMCC::CondCodes Val; + } CC; + struct { const char *Data; unsigned Length; @@ -132,7 +141,7 @@ public: struct { const MCExpr *Val; } Imm; - + // This is for all forms of ARM address expressions struct { unsigned BaseRegNum; @@ -150,17 +159,17 @@ public: } Mem; }; - - ARMOperand(KindTy K, SMLoc S, SMLoc E) - : Kind(K), StartLoc(S), EndLoc(E) {} - + ARMOperand(const ARMOperand &o) : MCParsedAsmOperand() { Kind = o.Kind; StartLoc = o.StartLoc; EndLoc = o.EndLoc; switch (Kind) { + case CondCode: + CC = o.CC; + break; case Token: - Tok = o.Tok; + Tok = o.Tok; break; case Register: Reg = o.Reg; @@ -173,12 +182,17 @@ public: break; } } - + /// getStartLoc - Get the location of the first token of this operand. SMLoc getStartLoc() const { return StartLoc; } /// getEndLoc - Get the location of the last token of this operand. SMLoc getEndLoc() const { return EndLoc; } + ARMCC::CondCodes getCondCode() const { + assert(Kind == CondCode && "Invalid access!"); + return CC.Val; + } + StringRef getToken() const { assert(Kind == Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); @@ -194,55 +208,125 @@ public: return Imm.Val; } - bool isToken() const {return Kind == Token; } - + bool isCondCode() const { return Kind == CondCode; } + bool isImm() const { return Kind == Immediate; } bool isReg() const { return Kind == Register; } + bool isToken() const { return Kind == Token; } + bool isMemory() const { return Kind == Memory; } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediates when possible. Null MCExpr = 0. + if (Expr == 0) + Inst.addOperand(MCOperand::CreateImm(0)); + else if (const MCConstantExpr *CE = dyn_cast(Expr)) + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + else + Inst.addOperand(MCOperand::CreateExpr(Expr)); + } + + void addCondCodeOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode()))); + // FIXME: What belongs here? + Inst.addOperand(MCOperand::CreateReg(0)); + } void addRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(getReg())); } - static void CreateToken(OwningPtr &Op, StringRef Str, - SMLoc S) { - Op.reset(new ARMOperand); - Op->Kind = Token; + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + + bool isMemMode5() const { + if (!isMemory() || Mem.OffsetIsReg || Mem.OffsetRegShifted || + Mem.Writeback || Mem.Negative) + return false; + // If there is an offset expression, make sure it's valid. + if (!Mem.Offset) + return true; + const MCConstantExpr *CE = dyn_cast(Mem.Offset); + if (!CE) + return false; + // The offset must be a multiple of 4 in the range 0-1020. + int64_t Value = CE->getValue(); + return ((Value & 0x3) == 0 && Value <= 1020 && Value >= -1020); + } + + void addMemMode5Operands(MCInst &Inst, unsigned N) const { + assert(N == 2 && isMemMode5() && "Invalid number of operands!"); + + Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + assert(!Mem.OffsetIsReg && "invalid mode 5 operand"); + + // FIXME: #-0 is encoded differently than #0. Does the parser preserve + // the difference? + if (Mem.Offset) { + const MCConstantExpr *CE = dyn_cast(Mem.Offset); + assert(CE && "Non-constant mode 5 offset operand!"); + + // The MCInst offset operand doesn't include the low two bits (like + // the instruction encoding). + int64_t Offset = CE->getValue() / 4; + if (Offset >= 0) + Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::add, + Offset))); + else + Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::sub, + -Offset))); + } else { + Inst.addOperand(MCOperand::CreateImm(0)); + } + } + + virtual void dump(raw_ostream &OS) const; + + static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) { + ARMOperand *Op = new ARMOperand(CondCode); + Op->CC.Val = CC; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static ARMOperand *CreateToken(StringRef Str, SMLoc S) { + ARMOperand *Op = new ARMOperand(Token); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; Op->EndLoc = S; + return Op; } - static void CreateReg(OwningPtr &Op, unsigned RegNum, - bool Writeback, SMLoc S, SMLoc E) { - Op.reset(new ARMOperand); - Op->Kind = Register; + static ARMOperand *CreateReg(unsigned RegNum, bool Writeback, SMLoc S, + SMLoc E) { + ARMOperand *Op = new ARMOperand(Register); Op->Reg.RegNum = RegNum; Op->Reg.Writeback = Writeback; - Op->StartLoc = S; Op->EndLoc = E; + return Op; } - static void CreateImm(OwningPtr &Op, const MCExpr *Val, - SMLoc S, SMLoc E) { - Op.reset(new ARMOperand); - Op->Kind = Immediate; + static ARMOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(Immediate); Op->Imm.Val = Val; - Op->StartLoc = S; Op->EndLoc = E; + return Op; } - static void CreateMem(OwningPtr &Op, - unsigned BaseRegNum, bool OffsetIsReg, - const MCExpr *Offset, unsigned OffsetRegNum, - bool OffsetRegShifted, enum ShiftType ShiftType, - const MCExpr *ShiftAmount, bool Preindexed, - bool Postindexed, bool Negative, bool Writeback, - SMLoc S, SMLoc E) { - Op.reset(new ARMOperand); - Op->Kind = Memory; + static ARMOperand *CreateMem(unsigned BaseRegNum, bool OffsetIsReg, + const MCExpr *Offset, unsigned OffsetRegNum, + bool OffsetRegShifted, enum ShiftType ShiftType, + const MCExpr *ShiftAmount, bool Preindexed, + bool Postindexed, bool Negative, bool Writeback, + SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(Memory); Op->Mem.BaseRegNum = BaseRegNum; Op->Mem.OffsetIsReg = OffsetIsReg; Op->Mem.Offset = Offset; @@ -254,57 +338,90 @@ public: Op->Mem.Postindexed = Postindexed; Op->Mem.Negative = Negative; Op->Mem.Writeback = Writeback; - + Op->StartLoc = S; Op->EndLoc = E; + return Op; } + +private: + ARMOperand(KindTy K) : Kind(K) {} }; } // end anonymous namespace. +void ARMOperand::dump(raw_ostream &OS) const { + switch (Kind) { + case CondCode: + OS << ARMCondCodeToString(getCondCode()); + break; + case Immediate: + getImm()->print(OS); + break; + case Memory: + OS << ""; + break; + case Register: + OS << ""; + break; + case Token: + OS << "'" << getToken() << "'"; + break; + } +} + +/// @name Auto-generated Match Functions +/// { + +static unsigned MatchRegisterName(StringRef Name); + +/// } + /// Try to parse a register name. The token must be an Identifier when called, -/// and if it is a register name a Reg operand is created, the token is eaten -/// and false is returned. Else true is returned and no token is eaten. -/// TODO this is likely to change to allow different register types and or to -/// parse for a specific register type. -bool ARMAsmParser::MaybeParseRegister - (OwningPtr &Op, bool ParseWriteBack) { - SMLoc S, E; +/// and if it is a register name the token is eaten and the register number is +/// returned. Otherwise return -1. +/// +int ARMAsmParser::TryParseRegister() { const AsmToken &Tok = Parser.getTok(); assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); // FIXME: Validate register for the current architecture; we have to do // validation later, so maybe there is no need for this here. - int RegNum; - - RegNum = MatchRegisterName(Tok.getString()); - if (RegNum == -1) - return true; - - S = Tok.getLoc(); - + unsigned RegNum = MatchRegisterName(Tok.getString()); + if (RegNum == 0) + return -1; Parser.Lex(); // Eat identifier token. - - E = Parser.getTok().getLoc(); + return RegNum; +} + + +/// Try to parse a register name. The token must be an Identifier when called, +/// and if it is a register name the token is eaten and the register number is +/// returned. Otherwise return -1. +/// +/// TODO this is likely to change to allow different register types and or to +/// parse for a specific register type. +ARMOperand *ARMAsmParser::TryParseRegisterWithWriteBack() { + SMLoc S = Parser.getTok().getLoc(); + int RegNo = TryParseRegister(); + if (RegNo == -1) return 0; + + SMLoc E = Parser.getTok().getLoc(); bool Writeback = false; - if (ParseWriteBack) { - const AsmToken &ExclaimTok = Parser.getTok(); - if (ExclaimTok.is(AsmToken::Exclaim)) { - E = ExclaimTok.getLoc(); - Writeback = true; - Parser.Lex(); // Eat exclaim token - } + const AsmToken &ExclaimTok = Parser.getTok(); + if (ExclaimTok.is(AsmToken::Exclaim)) { + E = ExclaimTok.getLoc(); + Writeback = true; + Parser.Lex(); // Eat exclaim token } - ARMOperand::CreateReg(Op, RegNum, Writeback, S, E); - - return false; + return ARMOperand::CreateReg(RegNo, Writeback, S, E); } -/// Parse a register list, return false if successful else return true or an -/// error. The first token must be a '{' when called. -bool ARMAsmParser::ParseRegisterList(OwningPtr &Op) { +/// Parse a register list, return it if successful else return null. The first +/// token must be a '{' when called. +ARMOperand *ARMAsmParser::ParseRegisterList() { SMLoc S, E; assert(Parser.getTok().is(AsmToken::LCurly) && "Token is not an Left Curly Brace"); @@ -313,12 +430,16 @@ bool ARMAsmParser::ParseRegisterList(OwningPtr &Op) { const AsmToken &RegTok = Parser.getTok(); SMLoc RegLoc = RegTok.getLoc(); - if (RegTok.isNot(AsmToken::Identifier)) - return Error(RegLoc, "register expected"); - int RegNum = MatchRegisterName(RegTok.getString()); - if (RegNum == -1) - return Error(RegLoc, "register expected"); - Parser.Lex(); // Eat identifier token. + if (RegTok.isNot(AsmToken::Identifier)) { + Error(RegLoc, "register expected"); + return 0; + } + int RegNum = TryParseRegister(); + if (RegNum == -1) { + Error(RegLoc, "register expected"); + return 0; + } + unsigned RegList = 1 << RegNum; int HighRegNum = RegNum; @@ -328,11 +449,15 @@ bool ARMAsmParser::ParseRegisterList(OwningPtr &Op) { const AsmToken &RegTok = Parser.getTok(); SMLoc RegLoc = RegTok.getLoc(); - if (RegTok.isNot(AsmToken::Identifier)) - return Error(RegLoc, "register expected"); - int RegNum = MatchRegisterName(RegTok.getString()); - if (RegNum == -1) - return Error(RegLoc, "register expected"); + if (RegTok.isNot(AsmToken::Identifier)) { + Error(RegLoc, "register expected"); + return 0; + } + int RegNum = TryParseRegister(); + if (RegNum == -1) { + Error(RegLoc, "register expected"); + return 0; + } if (RegList & (1 << RegNum)) Warning(RegLoc, "register duplicated in register list"); @@ -340,23 +465,25 @@ bool ARMAsmParser::ParseRegisterList(OwningPtr &Op) { Warning(RegLoc, "register not in ascending order in register list"); RegList |= 1 << RegNum; HighRegNum = RegNum; - - Parser.Lex(); // Eat identifier token. } const AsmToken &RCurlyTok = Parser.getTok(); - if (RCurlyTok.isNot(AsmToken::RCurly)) - return Error(RCurlyTok.getLoc(), "'}' expected"); + if (RCurlyTok.isNot(AsmToken::RCurly)) { + Error(RCurlyTok.getLoc(), "'}' expected"); + return 0; + } E = RCurlyTok.getLoc(); Parser.Lex(); // Eat left curly brace token. - return false; + // FIXME: Need to return an operand! + Error(E, "FIXME: register list parsing not implemented"); + return 0; } /// Parse an arm memory expression, return false if successful else return true /// or an error. The first token must be a '[' when called. /// TODO Only preindexing and postindexing addressing are started, unindexed /// with option, etc are still to do. -bool ARMAsmParser::ParseMemory(OwningPtr &Op) { +ARMOperand *ARMAsmParser::ParseMemory() { SMLoc S, E; assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not an Left Bracket"); @@ -364,11 +491,15 @@ bool ARMAsmParser::ParseMemory(OwningPtr &Op) { Parser.Lex(); // Eat left bracket token. const AsmToken &BaseRegTok = Parser.getTok(); - if (BaseRegTok.isNot(AsmToken::Identifier)) - return Error(BaseRegTok.getLoc(), "register expected"); - if (MaybeParseRegister(Op, false)) - return Error(BaseRegTok.getLoc(), "register expected"); - int BaseRegNum = Op->getReg(); + if (BaseRegTok.isNot(AsmToken::Identifier)) { + Error(BaseRegTok.getLoc(), "register expected"); + return 0; + } + int BaseRegNum = TryParseRegister(); + if (BaseRegNum == -1) { + Error(BaseRegTok.getLoc(), "register expected"); + return 0; + } bool Preindexed = false; bool Postindexed = false; @@ -387,12 +518,14 @@ bool ARMAsmParser::ParseMemory(OwningPtr &Op) { enum ShiftType ShiftType; const MCExpr *ShiftAmount; const MCExpr *Offset; - if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount, - Offset, OffsetIsReg, OffsetRegNum, E)) - return true; + if (ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount, + Offset, OffsetIsReg, OffsetRegNum, E)) + return 0; const AsmToken &RBracTok = Parser.getTok(); - if (RBracTok.isNot(AsmToken::RBrac)) - return Error(RBracTok.getLoc(), "']' expected"); + if (RBracTok.isNot(AsmToken::RBrac)) { + Error(RBracTok.getLoc(), "']' expected"); + return 0; + } E = RBracTok.getLoc(); Parser.Lex(); // Eat right bracket token. @@ -402,17 +535,15 @@ bool ARMAsmParser::ParseMemory(OwningPtr &Op) { Writeback = true; Parser.Lex(); // Eat exclaim token } - ARMOperand::CreateMem(Op, BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, - OffsetRegShifted, ShiftType, ShiftAmount, - Preindexed, Postindexed, Negative, Writeback, S, E); - return false; + return ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, + OffsetRegShifted, ShiftType, ShiftAmount, + Preindexed, Postindexed, Negative, Writeback, + S, E); } // The "[Rn" we have so far was not followed by a comma. else if (Tok.is(AsmToken::RBrac)) { - // This is a post indexing addressing forms, that is a ']' follows after - // the "[Rn". - Postindexed = true; - Writeback = true; + // If there's anything other than the right brace, this is a post indexing + // addressing form. E = Tok.getLoc(); Parser.Lex(); // Eat right bracket token. @@ -420,26 +551,30 @@ bool ARMAsmParser::ParseMemory(OwningPtr &Op) { bool OffsetRegShifted = false; enum ShiftType ShiftType; const MCExpr *ShiftAmount; - const MCExpr *Offset; + const MCExpr *Offset = 0; const AsmToken &NextTok = Parser.getTok(); if (NextTok.isNot(AsmToken::EndOfStatement)) { - if (NextTok.isNot(AsmToken::Comma)) - return Error(NextTok.getLoc(), "',' expected"); + Postindexed = true; + Writeback = true; + if (NextTok.isNot(AsmToken::Comma)) { + Error(NextTok.getLoc(), "',' expected"); + return 0; + } Parser.Lex(); // Eat comma token. - if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, - ShiftAmount, Offset, OffsetIsReg, OffsetRegNum, - E)) - return true; + if (ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, + ShiftAmount, Offset, OffsetIsReg, OffsetRegNum, + E)) + return 0; } - ARMOperand::CreateMem(Op, BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, - OffsetRegShifted, ShiftType, ShiftAmount, - Preindexed, Postindexed, Negative, Writeback, S, E); - return false; + return ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, + OffsetRegShifted, ShiftType, ShiftAmount, + Preindexed, Postindexed, Negative, Writeback, + S, E); } - return true; + return 0; } /// Parse the offset of a memory operand after we have seen "[Rn," or "[Rn]," @@ -457,7 +592,6 @@ bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative, bool &OffsetIsReg, int &OffsetRegNum, SMLoc &E) { - OwningPtr Op; Negative = false; OffsetRegShifted = false; OffsetIsReg = false; @@ -473,12 +607,14 @@ bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative, // See if there is a register following the "[Rn," or "[Rn]," we have so far. const AsmToken &OffsetRegTok = Parser.getTok(); if (OffsetRegTok.is(AsmToken::Identifier)) { - OffsetIsReg = !MaybeParseRegister(Op, false); - if (OffsetIsReg) { - E = Op->getEndLoc(); - OffsetRegNum = Op->getReg(); + SMLoc CurLoc = OffsetRegTok.getLoc(); + OffsetRegNum = TryParseRegister(); + if (OffsetRegNum != -1) { + OffsetIsReg = true; + E = CurLoc; } } + // If we parsed a register as the offset then their can be a shift after that if (OffsetRegNum != -1) { // Look for a comma then a shift @@ -488,7 +624,7 @@ bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative, const AsmToken &Tok = Parser.getTok(); if (ParseShift(ShiftType, ShiftAmount, E)) - return Error(Tok.getLoc(), "shift expected"); + return Error(Tok.getLoc(), "shift expected"); OffsetRegShifted = true; } } @@ -497,7 +633,7 @@ bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative, const AsmToken &HashTok = Parser.getTok(); if (HashTok.isNot(AsmToken::Hash)) return Error(HashTok.getLoc(), "'#' expected"); - + Parser.Lex(); // Eat hash token. if (getParser().ParseExpression(Offset)) @@ -511,13 +647,12 @@ bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative, /// ( lsl | lsr | asr | ror ) , # shift_amount /// rrx /// and returns true if it parses a shift otherwise it returns false. -bool ARMAsmParser::ParseShift(ShiftType &St, - const MCExpr *&ShiftAmount, +bool ARMAsmParser::ParseShift(ShiftType &St, const MCExpr *&ShiftAmount, SMLoc &E) { const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return true; - const StringRef &ShiftName = Tok.getString(); + StringRef ShiftName = Tok.getString(); if (ShiftName == "lsl" || ShiftName == "LSL") St = Lsl; else if (ShiftName == "lsr" || ShiftName == "LSR") @@ -548,99 +683,28 @@ bool ARMAsmParser::ParseShift(ShiftType &St, return false; } -/// A hack to allow some testing, to be replaced by a real table gen version. -int ARMAsmParser::MatchRegisterName(const StringRef &Name) { - if (Name == "r0" || Name == "R0") - return 0; - else if (Name == "r1" || Name == "R1") - return 1; - else if (Name == "r2" || Name == "R2") - return 2; - else if (Name == "r3" || Name == "R3") - return 3; - else if (Name == "r3" || Name == "R3") - return 3; - else if (Name == "r4" || Name == "R4") - return 4; - else if (Name == "r5" || Name == "R5") - return 5; - else if (Name == "r6" || Name == "R6") - return 6; - else if (Name == "r7" || Name == "R7") - return 7; - else if (Name == "r8" || Name == "R8") - return 8; - else if (Name == "r9" || Name == "R9") - return 9; - else if (Name == "r10" || Name == "R10") - return 10; - else if (Name == "r11" || Name == "R11" || Name == "fp") - return 11; - else if (Name == "r12" || Name == "R12" || Name == "ip") - return 12; - else if (Name == "r13" || Name == "R13" || Name == "sp") - return 13; - else if (Name == "r14" || Name == "R14" || Name == "lr") - return 14; - else if (Name == "r15" || Name == "R15" || Name == "pc") - return 15; - return -1; -} - -/// A hack to allow some testing, to be replaced by a real table gen version. -bool ARMAsmParser:: -MatchInstruction(const SmallVectorImpl &Operands, - MCInst &Inst) { - ARMOperand &Op0 = *(ARMOperand*)Operands[0]; - assert(Op0.Kind == ARMOperand::Token && "First operand not a Token"); - const StringRef &Mnemonic = Op0.getToken(); - if (Mnemonic == "add" || - Mnemonic == "stmfd" || - Mnemonic == "str" || - Mnemonic == "ldmfd" || - Mnemonic == "ldr" || - Mnemonic == "mov" || - Mnemonic == "sub" || - Mnemonic == "bl" || - Mnemonic == "push" || - Mnemonic == "blx" || - Mnemonic == "pop") { - // Hard-coded to a valid instruction, till we have a real matcher. - Inst = MCInst(); - Inst.setOpcode(ARM::MOVr); - Inst.addOperand(MCOperand::CreateReg(2)); - Inst.addOperand(MCOperand::CreateReg(2)); - Inst.addOperand(MCOperand::CreateImm(0)); - Inst.addOperand(MCOperand::CreateImm(0)); - Inst.addOperand(MCOperand::CreateReg(0)); - return false; - } - - return true; -} - /// Parse a arm instruction operand. For now this parses the operand regardless /// of the mnemonic. -bool ARMAsmParser::ParseOperand(OwningPtr &Op) { +ARMOperand *ARMAsmParser::ParseOperand() { SMLoc S, E; - + switch (getLexer().getKind()) { case AsmToken::Identifier: - if (!MaybeParseRegister(Op, true)) - return false; + if (ARMOperand *Op = TryParseRegisterWithWriteBack()) + return Op; + // This was not a register so parse other operands that start with an // identifier (like labels) as expressions and create them as immediates. const MCExpr *IdVal; S = Parser.getTok().getLoc(); if (getParser().ParseExpression(IdVal)) - return true; + return 0; E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - ARMOperand::CreateImm(Op, IdVal, S, E); - return false; + return ARMOperand::CreateImm(IdVal, S, E); case AsmToken::LBrac: - return ParseMemory(Op); + return ParseMemory(); case AsmToken::LCurly: - return ParseRegisterList(Op); + return ParseRegisterList(); case AsmToken::Hash: // #42 -> immediate. // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate @@ -648,41 +712,136 @@ bool ARMAsmParser::ParseOperand(OwningPtr &Op) { Parser.Lex(); const MCExpr *ImmVal; if (getParser().ParseExpression(ImmVal)) - return true; + return 0; E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - ARMOperand::CreateImm(Op, ImmVal, S, E); - return false; + return ARMOperand::CreateImm(ImmVal, S, E); default: - return Error(Parser.getTok().getLoc(), "unexpected token in operand"); + Error(Parser.getTok().getLoc(), "unexpected token in operand"); + return 0; } } /// Parse an arm instruction mnemonic followed by its operands. -bool ARMAsmParser::ParseInstruction(const StringRef &Name, SMLoc NameLoc, +bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands) { - OwningPtr Op; - ARMOperand::CreateToken(Op, Name, NameLoc); - - Operands.push_back(Op.take()); + // Create the leading tokens for the mnemonic, split by '.' characters. + size_t Start = 0, Next = Name.find('.'); + StringRef Head = Name.slice(Start, Next); + + // Determine the predicate, if any. + // + // FIXME: We need a way to check whether a prefix supports predication, + // otherwise we will end up with an ambiguity for instructions that happen to + // end with a predicate name. + // FIXME: Likewise, some arithmetic instructions have an 's' prefix which + // indicates to update the condition codes. Those instructions have an + // additional immediate operand which encodes the prefix as reg0 or CPSR. + // Just checking for a suffix of 's' definitely creates ambiguities; e.g, + // the SMMLS instruction. + unsigned CC = StringSwitch(Head.substr(Head.size()-2)) + .Case("eq", ARMCC::EQ) + .Case("ne", ARMCC::NE) + .Case("hs", ARMCC::HS) + .Case("lo", ARMCC::LO) + .Case("mi", ARMCC::MI) + .Case("pl", ARMCC::PL) + .Case("vs", ARMCC::VS) + .Case("vc", ARMCC::VC) + .Case("hi", ARMCC::HI) + .Case("ls", ARMCC::LS) + .Case("ge", ARMCC::GE) + .Case("lt", ARMCC::LT) + .Case("gt", ARMCC::GT) + .Case("le", ARMCC::LE) + .Case("al", ARMCC::AL) + .Default(~0U); + + if (CC == ~0U || + (CC == ARMCC::LS && (Head == "vmls" || Head == "vnmls"))) { + CC = ARMCC::AL; + } else { + Head = Head.slice(0, Head.size() - 2); + } - if (getLexer().isNot(AsmToken::EndOfStatement)) { + Operands.push_back(ARMOperand::CreateToken(Head, NameLoc)); + // FIXME: Should only add this operand for predicated instructions + Operands.push_back(ARMOperand::CreateCondCode(ARMCC::CondCodes(CC), NameLoc)); + // Add the remaining tokens in the mnemonic. + while (Next != StringRef::npos) { + Start = Next; + Next = Name.find('.', Start + 1); + Head = Name.slice(Start, Next); + + Operands.push_back(ARMOperand::CreateToken(Head, NameLoc)); + } + + // Read the remaining operands. + if (getLexer().isNot(AsmToken::EndOfStatement)) { // Read the first operand. - OwningPtr Op; - if (ParseOperand(Op)) return true; - Operands.push_back(Op.take()); + if (ARMOperand *Op = ParseOperand()) + Operands.push_back(Op); + else { + Parser.EatToEndOfStatement(); + return true; + } while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. // Parse and remember the operand. - if (ParseOperand(Op)) return true; - Operands.push_back(Op.take()); + if (ARMOperand *Op = ParseOperand()) + Operands.push_back(Op); + else { + Parser.EatToEndOfStatement(); + return true; + } } } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + Parser.EatToEndOfStatement(); + return TokError("unexpected token in argument list"); + } + Parser.Lex(); // Consume the EndOfStatement return false; } +bool ARMAsmParser:: +MatchAndEmitInstruction(SMLoc IDLoc, + SmallVectorImpl &Operands, + MCStreamer &Out) { + MCInst Inst; + unsigned ErrorInfo; + switch (MatchInstructionImpl(Operands, Inst, ErrorInfo)) { + case Match_Success: + Out.EmitInstruction(Inst); + return false; + + case Match_MissingFeature: + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = ((ARMOperand*)Operands[ErrorInfo])->getStartLoc(); + if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_MnemonicFail: + return Error(IDLoc, "unrecognized instruction mnemonic"); + } + + llvm_unreachable("Implement any new match types added!"); +} + + + /// ParseDirective parses the arm specific directives bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getIdentifier(); @@ -712,7 +871,7 @@ bool ARMAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { if (getLexer().is(AsmToken::EndOfStatement)) break; - + // FIXME: Improve diagnostic. if (getLexer().isNot(AsmToken::Comma)) return Error(L, "unexpected token in directive"); @@ -742,16 +901,16 @@ bool ARMAsmParser::ParseDirectiveThumb(SMLoc L) { bool ARMAsmParser::ParseDirectiveThumbFunc(SMLoc L) { const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String)) - return Error(L, "unexpected token in .syntax directive"); - StringRef ATTRIBUTE_UNUSED SymbolName = Parser.getTok().getIdentifier(); + return Error(L, "unexpected token in .thumb_func directive"); + StringRef Name = Tok.getString(); Parser.Lex(); // Consume the identifier token. - if (getLexer().isNot(AsmToken::EndOfStatement)) return Error(L, "unexpected token in directive"); Parser.Lex(); - // TODO: mark symbol as a thumb symbol - // getParser().getStreamer().Emit???(); + // Mark symbol as a thumb symbol. + MCSymbol *Func = getParser().getContext().GetOrCreateSymbol(Name); + getParser().getStreamer().EmitThumbFunc(Func); return false; } @@ -761,7 +920,7 @@ bool ARMAsmParser::ParseDirectiveSyntax(SMLoc L) { const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return Error(L, "unexpected token in .syntax directive"); - const StringRef &Mode = Tok.getString(); + StringRef Mode = Tok.getString(); if (Mode == "unified" || Mode == "UNIFIED") Parser.Lex(); else if (Mode == "divided" || Mode == "DIVIDED") @@ -796,8 +955,11 @@ bool ARMAsmParser::ParseDirectiveCode(SMLoc L) { return Error(Parser.getTok().getLoc(), "unexpected token in directive"); Parser.Lex(); - // TODO tell the MC streamer the mode - // getParser().getStreamer().Emit???(); + if (Val == 16) + getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); + else + getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32); + return false; } @@ -809,3 +971,7 @@ extern "C" void LLVMInitializeARMAsmParser() { RegisterAsmParser Y(TheThumbTarget); LLVMInitializeARMAsmLexer(); } + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "ARMGenAsmMatcher.inc"