X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FAsmParser%2FARMAsmParser.cpp;h=12225b00ed0556c03541b6c73900be24f6f1253e;hb=5fa22a19750c082ff161db1702ebe96dd2a787e7;hp=857352bfea1c9ad0eb6c3515b627bc8fff0f3c8c;hpb=da54c6dd4f4e54d654722390311bdab502badc3a;p=oota-llvm.git diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 857352bfea1..12225b00ed0 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -8,10 +8,12 @@ //===----------------------------------------------------------------------===// #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" @@ -34,24 +36,24 @@ enum ShiftType { }; namespace { - struct ARMOperand; + +class ARMOperand; class ARMAsmParser : public TargetAsmParser { MCAsmParser &Parser; TargetMachine &TM; -private: MCAsmParser &getParser() const { return Parser; } - MCAsmLexer &getLexer() const { return Parser.getLexer(); } void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); } - bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } - ARMOperand *MaybeParseRegister(bool ParseWriteBack); + int TryParseRegister(); + ARMOperand *TryParseRegisterWithWriteBack(); ARMOperand *ParseRegisterList(); ARMOperand *ParseMemory(); + ARMOperand *ParseOperand(); bool ParseMemoryOffsetReg(bool &Negative, bool &OffsetRegShifted, @@ -61,19 +63,11 @@ private: bool &OffsetIsReg, int &OffsetRegNum, SMLoc &E); - bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount, SMLoc &E); - - ARMOperand *ParseOperand(); - bool ParseDirectiveWord(unsigned Size, SMLoc L); - bool ParseDirectiveThumb(SMLoc L); - bool ParseDirectiveThumbFunc(SMLoc L); - bool ParseDirectiveCode(SMLoc L); - bool ParseDirectiveSyntax(SMLoc L); bool MatchAndEmitInstruction(SMLoc IDLoc, @@ -88,14 +82,16 @@ private: /// } - public: ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM) - : TargetAsmParser(T), Parser(_Parser), TM(_TM) {} + : TargetAsmParser(T), Parser(_Parser), TM(_TM) { + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures( + &TM.getSubtarget())); + } virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands); - virtual bool ParseDirective(AsmToken DirectiveID); }; } // end anonymous namespace @@ -104,13 +100,13 @@ namespace { /// ARMOperand - Instances of this class represent a parsed ARM machine /// instruction. -struct ARMOperand : public MCParsedAsmOperand { -public: +class ARMOperand : public MCParsedAsmOperand { enum KindTy { CondCode, Immediate, Memory, Register, + RegisterList, Token } Kind; @@ -131,6 +127,10 @@ public: bool Writeback; } Reg; + struct { + SmallVector *Registers; + } RegList; + struct { const MCExpr *Val; } Imm; @@ -138,21 +138,21 @@ public: // This is for all forms of ARM address expressions struct { unsigned BaseRegNum; - unsigned OffsetRegNum; // used when OffsetIsReg is true - const MCExpr *Offset; // used when OffsetIsReg is false - const MCExpr *ShiftAmount; // used when OffsetRegShifted is true - enum ShiftType ShiftType; // used when OffsetRegShifted is true - unsigned - OffsetRegShifted : 1, // only used when OffsetIsReg is true - Preindexed : 1, - Postindexed : 1, - OffsetIsReg : 1, - Negative : 1, // only used when OffsetIsReg is true - Writeback : 1; + unsigned OffsetRegNum; // used when OffsetIsReg is true + const MCExpr *Offset; // used when OffsetIsReg is false + const MCExpr *ShiftAmount; // used when OffsetRegShifted is true + enum ShiftType ShiftType; // used when OffsetRegShifted is true + unsigned OffsetRegShifted : 1; // only used when OffsetIsReg is true + unsigned Preindexed : 1; + unsigned Postindexed : 1; + unsigned OffsetIsReg : 1; + unsigned Negative : 1; // only used when OffsetIsReg is true + unsigned Writeback : 1; } Mem; - }; + ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} +public: ARMOperand(const ARMOperand &o) : MCParsedAsmOperand() { Kind = o.Kind; StartLoc = o.StartLoc; @@ -167,6 +167,9 @@ public: case Register: Reg = o.Reg; break; + case RegisterList: + RegList = o.RegList; + break; case Immediate: Imm = o.Imm; break; @@ -175,6 +178,10 @@ public: break; } } + ~ARMOperand() { + if (isRegList()) + delete RegList.Registers; + } /// getStartLoc - Get the location of the first token of this operand. SMLoc getStartLoc() const { return StartLoc; } @@ -196,6 +203,11 @@ public: return Reg.RegNum; } + const SmallVectorImpl &getRegList() const { + assert(Kind == RegisterList && "Invalid access!"); + return *RegList.Registers; + } + const MCExpr *getImm() const { assert(Kind == Immediate && "Invalid access!"); return Imm.Val; @@ -204,8 +216,23 @@ public: bool isCondCode() const { return Kind == CondCode; } bool isImm() const { return Kind == Immediate; } bool isReg() const { return Kind == Register; } + bool isRegList() const { return Kind == RegisterList; } bool isToken() const { return Kind == Token; } bool isMemory() const { return Kind == Memory; } + 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 addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediates when possible. Null MCExpr = 0. @@ -229,27 +256,43 @@ public: Inst.addOperand(MCOperand::CreateReg(getReg())); } - void addImmOperands(MCInst &Inst, unsigned N) const { + void addRegListOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - addExpr(Inst, getImm()); + const SmallVectorImpl &RegList = getRegList(); + for (SmallVectorImpl::const_iterator + I = RegList.begin(), E = RegList.end(); I != E; ++I) + Inst.addOperand(MCOperand::CreateReg(*I)); } - - bool isMemMode5() const { - if (!isMemory() || Mem.OffsetIsReg || Mem.OffsetRegShifted || - Mem.Preindexed || Mem.Negative || Mem.Postindexed || - Mem.Writeback) - return false; - - return true; + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); } 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"); - addExpr(Inst, Mem.Offset); + 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; @@ -281,6 +324,20 @@ public: return Op; } + static ARMOperand * + CreateRegList(const SmallVectorImpl > &Regs, + SMLoc S, SMLoc E) { + ARMOperand *Op = new ARMOperand(RegisterList); + Op->RegList.Registers = new SmallVector(); + for (SmallVectorImpl >::const_iterator + I = Regs.begin(), E = Regs.end(); I != E; ++I) + Op->RegList.Registers->push_back(I->first); + std::sort(Op->RegList.Registers->begin(), Op->RegList.Registers->end()); + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + static ARMOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { ARMOperand *Op = new ARMOperand(Immediate); Op->Imm.Val = Val; @@ -312,9 +369,6 @@ public: Op->EndLoc = E; return Op; } - -private: - ARMOperand(KindTy K) : Kind(K) {} }; } // end anonymous namespace. @@ -333,6 +387,19 @@ void ARMOperand::dump(raw_ostream &OS) const { case Register: OS << ""; break; + case RegisterList: { + OS << " &RegList = getRegList(); + for (SmallVectorImpl::const_iterator + I = RegList.begin(), E = RegList.end(); I != E; ) { + OS << *I; + if (++I < E) OS << ", "; + } + + OS << ">"; + break; + } case Token: OS << "'" << getToken() << "'"; break; @@ -347,71 +414,62 @@ 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 the token is eaten and a Reg operand is created -/// and returned. Otherwise return null. +/// 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::MaybeParseRegister(bool ParseWriteBack) { - SMLoc S, E; +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 0; + unsigned RegNum = MatchRegisterName(Tok.getString()); + if (RegNum == 0) + return -1; + Parser.Lex(); // Eat identifier token. + return RegNum; +} - S = Tok.getLoc(); - Parser.Lex(); // Eat identifier token. +/// 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; - E = Parser.getTok().getLoc(); + 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 } - return ARMOperand::CreateReg(RegNum, Writeback, S, E); + return ARMOperand::CreateReg(RegNo, Writeback, S, E); } /// 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"); - S = Parser.getTok().getLoc(); - Parser.Lex(); // Eat left curly brace token. + "Token is not a Left Curly Brace"); + SMLoc S = Parser.getTok().getLoc(); - const AsmToken &RegTok = Parser.getTok(); - SMLoc RegLoc = RegTok.getLoc(); - if (RegTok.isNot(AsmToken::Identifier)) { - Error(RegLoc, "register expected"); - return 0; - } - int RegNum = MatchRegisterName(RegTok.getString()); - if (RegNum == -1) { - Error(RegLoc, "register expected"); - return 0; - } + // Read the rest of the registers in the list. + unsigned PrevRegNum = 0; + SmallVector, 32> Registers; - Parser.Lex(); // Eat identifier token. - unsigned RegList = 1 << RegNum; - - int HighRegNum = RegNum; - // TODO ranges like "{Rn-Rm}" - while (Parser.getTok().is(AsmToken::Comma)) { - Parser.Lex(); // Eat comma token. + do { + bool IsRange = Parser.getTok().is(AsmToken::Minus); + Parser.Lex(); // Eat non-identifier token. const AsmToken &RegTok = Parser.getTok(); SMLoc RegLoc = RegTok.getLoc(); @@ -419,42 +477,72 @@ ARMOperand *ARMAsmParser::ParseRegisterList() { Error(RegLoc, "register expected"); return 0; } - int RegNum = MatchRegisterName(RegTok.getString()); + + int RegNum = TryParseRegister(); if (RegNum == -1) { Error(RegLoc, "register expected"); return 0; } - if (RegList & (1 << RegNum)) - Warning(RegLoc, "register duplicated in register list"); - else if (RegNum <= HighRegNum) - Warning(RegLoc, "register not in ascending order in register list"); - RegList |= 1 << RegNum; - HighRegNum = RegNum; + if (IsRange) { + int Reg = PrevRegNum; + do { + ++Reg; + Registers.push_back(std::make_pair(Reg, RegLoc)); + } while (Reg != RegNum); + } else { + Registers.push_back(std::make_pair(RegNum, RegLoc)); + } - Parser.Lex(); // Eat identifier token. - } + PrevRegNum = RegNum; + } while (Parser.getTok().is(AsmToken::Comma) || + Parser.getTok().is(AsmToken::Minus)); + + // Process the right curly brace of the list. const AsmToken &RCurlyTok = Parser.getTok(); if (RCurlyTok.isNot(AsmToken::RCurly)) { Error(RCurlyTok.getLoc(), "'}' expected"); return 0; } - E = RCurlyTok.getLoc(); - Parser.Lex(); // Eat left curly brace token. - // FIXME: Need to return an operand! - Error(E, "FIXME: register list parsing not implemented"); - return 0; + SMLoc E = RCurlyTok.getLoc(); + Parser.Lex(); // Eat right curly brace token. + + // Verify the register list. + SmallVectorImpl >::const_iterator + RI = Registers.begin(), RE = Registers.end(); + + unsigned HighRegNum = RI->first; + DenseMap RegMap; + RegMap[RI->first] = true; + + for (++RI; RI != RE; ++RI) { + const std::pair &RegInfo = *RI; + + if (RegMap[RegInfo.first]) { + Error(RegInfo.second, "register duplicated in register list"); + return 0; + } + + if (RegInfo.first < HighRegNum) + Warning(RegInfo.second, + "register not in ascending order in register list"); + + RegMap[RegInfo.first] = true; + HighRegNum = std::max(RegInfo.first, HighRegNum); + } + + return ARMOperand::CreateRegList(Registers, S, E); } -/// Parse an arm memory expression, return false if successful else return true +/// 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. ARMOperand *ARMAsmParser::ParseMemory() { SMLoc S, E; assert(Parser.getTok().is(AsmToken::LBrac) && - "Token is not an Left Bracket"); + "Token is not a Left Bracket"); S = Parser.getTok().getLoc(); Parser.Lex(); // Eat left bracket token. @@ -463,11 +551,8 @@ ARMOperand *ARMAsmParser::ParseMemory() { Error(BaseRegTok.getLoc(), "register expected"); return 0; } - int BaseRegNum = 0; - if (ARMOperand *Op = MaybeParseRegister(false)) { - BaseRegNum = Op->getReg(); - delete Op; - } else { + int BaseRegNum = TryParseRegister(); + if (BaseRegNum == -1) { Error(BaseRegTok.getLoc(), "register expected"); return 0; } @@ -513,10 +598,8 @@ ARMOperand *ARMAsmParser::ParseMemory() { } // 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. @@ -528,6 +611,8 @@ ARMOperand *ARMAsmParser::ParseMemory() { const AsmToken &NextTok = Parser.getTok(); if (NextTok.isNot(AsmToken::EndOfStatement)) { + Postindexed = true; + Writeback = true; if (NextTok.isNot(AsmToken::Comma)) { Error(NextTok.getLoc(), "',' expected"); return 0; @@ -578,14 +663,15 @@ 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)) { - if (ARMOperand *Op = MaybeParseRegister(false)) { + SMLoc CurLoc = OffsetRegTok.getLoc(); + OffsetRegNum = TryParseRegister(); + if (OffsetRegNum != -1) { OffsetIsReg = true; - E = Op->getEndLoc(); - OffsetRegNum = Op->getReg(); - delete Op; + E = CurLoc; } } - // If we parsed a register as the offset then their can be a shift after that + + // If we parsed a register as the offset then there can be a shift after that. if (OffsetRegNum != -1) { // Look for a comma then a shift const AsmToken &Tok = Parser.getTok(); @@ -657,10 +743,12 @@ bool ARMAsmParser::ParseShift(ShiftType &St, const MCExpr *&ShiftAmount, /// of the mnemonic. ARMOperand *ARMAsmParser::ParseOperand() { SMLoc S, E; - switch (getLexer().getKind()) { + default: + Error(Parser.getTok().getLoc(), "unexpected token in operand"); + return 0; case AsmToken::Identifier: - if (ARMOperand *Op = MaybeParseRegister(true)) + if (ARMOperand *Op = TryParseRegisterWithWriteBack()) return Op; // This was not a register so parse other operands that start with an @@ -685,9 +773,6 @@ ARMOperand *ARMAsmParser::ParseOperand() { return 0; E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); return ARMOperand::CreateImm(ImmVal, S, E); - default: - Error(Parser.getTok().getLoc(), "unexpected token in operand"); - return 0; } } @@ -703,6 +788,11 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, // 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) @@ -721,12 +811,15 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, .Case("al", ARMCC::AL) .Default(~0U); - if (CC != ~0U) - Head = Head.slice(0, Head.size() - 2); - else + if (CC == ~0U || + (CC == ARMCC::LS && (Head == "vmls" || Head == "vnmls"))) { CC = ARMCC::AL; + } else { + Head = Head.slice(0, Head.size() - 2); + } 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. @@ -765,6 +858,7 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, Parser.EatToEndOfStatement(); return TokError("unexpected token in argument list"); } + Parser.Lex(); // Consume the EndOfStatement return false; } @@ -779,7 +873,6 @@ MatchAndEmitInstruction(SMLoc IDLoc, case Match_Success: Out.EmitInstruction(Inst); return false; - case Match_MissingFeature: Error(IDLoc, "instruction requires a CPU feature not currently enabled"); return true; @@ -800,10 +893,9 @@ MatchAndEmitInstruction(SMLoc IDLoc, } llvm_unreachable("Implement any new match types added!"); + return true; } - - /// ParseDirective parses the arm specific directives bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) { StringRef IDVal = DirectiveID.getIdentifier(); @@ -863,15 +955,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"); + 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; } @@ -916,8 +1009,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; }