Add support for parsing the writeback ("!") token.

llvm-svn: 119761
This commit is contained in:
Bill Wendling 2010-11-18 23:43:05 +00:00
parent 5a97bd873e
commit 2063b84297
2 changed files with 98 additions and 65 deletions

View File

@ -50,10 +50,10 @@ class ARMAsmParser : public TargetAsmParser {
bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
int TryParseRegister(); int TryParseRegister();
ARMOperand *TryParseRegisterWithWriteBack(); bool TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &);
ARMOperand *ParseRegisterList(); bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
ARMOperand *ParseMemory(); bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &);
ARMOperand *ParseOperand(); bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseMemoryOffsetReg(bool &Negative, bool ParseMemoryOffsetReg(bool &Negative,
bool &OffsetRegShifted, bool &OffsetRegShifted,
@ -127,7 +127,6 @@ class ARMOperand : public MCParsedAsmOperand {
struct { struct {
unsigned RegNum; unsigned RegNum;
bool Writeback;
} Reg; } Reg;
struct { struct {
@ -142,11 +141,11 @@ class ARMOperand : public MCParsedAsmOperand {
const MCExpr *ShiftAmount; // used when OffsetRegShifted is true const MCExpr *ShiftAmount; // used when OffsetRegShifted is true
enum ShiftType ShiftType; // used when OffsetRegShifted is true enum ShiftType ShiftType; // used when OffsetRegShifted is true
unsigned OffsetRegShifted : 1; // only used when OffsetIsReg is true unsigned OffsetRegShifted : 1; // only used when OffsetIsReg is true
unsigned Preindexed : 1; unsigned Preindexed : 1;
unsigned Postindexed : 1; unsigned Postindexed : 1;
unsigned OffsetIsReg : 1; unsigned OffsetIsReg : 1;
unsigned Negative : 1; // only used when OffsetIsReg is true unsigned Negative : 1; // only used when OffsetIsReg is true
unsigned Writeback : 1; unsigned Writeback : 1;
} Mem; } Mem;
}; };
@ -322,11 +321,9 @@ public:
return Op; return Op;
} }
static ARMOperand *CreateReg(unsigned RegNum, bool Writeback, SMLoc S, static ARMOperand *CreateReg(unsigned RegNum, SMLoc S, SMLoc E) {
SMLoc E) {
ARMOperand *Op = new ARMOperand(Register); ARMOperand *Op = new ARMOperand(Register);
Op->Reg.RegNum = RegNum; Op->Reg.RegNum = RegNum;
Op->Reg.Writeback = Writeback;
Op->StartLoc = S; Op->StartLoc = S;
Op->EndLoc = E; Op->EndLoc = E;
return Op; return Op;
@ -396,10 +393,10 @@ void ARMOperand::dump(raw_ostream &OS) const {
getImm()->print(OS); getImm()->print(OS);
break; break;
case Memory: case Memory:
OS << "<memory" << (!Mem.Writeback ? ">" : "!>"); OS << "<memory>";
break; break;
case Register: case Register:
OS << "<register " << getReg() << (!Reg.Writeback ? ">" : "!>"); OS << "<register " << getReg() << ">";
break; break;
case RegisterList: case RegisterList:
case DPRRegisterList: case DPRRegisterList:
@ -447,34 +444,35 @@ int ARMAsmParser::TryParseRegister() {
} }
/// Try to parse a register name. The token must be an Identifier when called, /// 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 /// If it's a register, an AsmOperand is created. Another AsmOperand is created
/// returned. Otherwise return -1. /// if there is a "writeback". 'true' if it's not a register.
/// ///
/// TODO this is likely to change to allow different register types and or to /// TODO this is likely to change to allow different register types and or to
/// parse for a specific register type. /// parse for a specific register type.
ARMOperand *ARMAsmParser::TryParseRegisterWithWriteBack() { bool ARMAsmParser::
TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc(); SMLoc S = Parser.getTok().getLoc();
int RegNo = TryParseRegister(); int RegNo = TryParseRegister();
if (RegNo == -1) if (RegNo == -1)
return 0; return true;
SMLoc E = Parser.getTok().getLoc(); Operands.push_back(ARMOperand::CreateReg(RegNo, S, Parser.getTok().getLoc()));
bool Writeback = false;
const AsmToken &ExclaimTok = Parser.getTok(); const AsmToken &ExclaimTok = Parser.getTok();
if (ExclaimTok.is(AsmToken::Exclaim)) { if (ExclaimTok.is(AsmToken::Exclaim)) {
E = ExclaimTok.getLoc(); Operands.push_back(ARMOperand::CreateToken(ExclaimTok.getString(),
Writeback = true; ExclaimTok.getLoc()));
Parser.Lex(); // Eat exclaim token Parser.Lex(); // Eat exclaim token
} }
return ARMOperand::CreateReg(RegNo, Writeback, S, E); return false;
} }
/// Parse a register list, return it if successful else return null. The first /// Parse a register list, return it if successful else return null. The first
/// token must be a '{' when called. /// token must be a '{' when called.
ARMOperand *ARMAsmParser::ParseRegisterList() { bool ARMAsmParser::
ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
assert(Parser.getTok().is(AsmToken::LCurly) && assert(Parser.getTok().is(AsmToken::LCurly) &&
"Token is not a Left Curly Brace"); "Token is not a Left Curly Brace");
SMLoc S = Parser.getTok().getLoc(); SMLoc S = Parser.getTok().getLoc();
@ -491,13 +489,13 @@ ARMOperand *ARMAsmParser::ParseRegisterList() {
SMLoc RegLoc = RegTok.getLoc(); SMLoc RegLoc = RegTok.getLoc();
if (RegTok.isNot(AsmToken::Identifier)) { if (RegTok.isNot(AsmToken::Identifier)) {
Error(RegLoc, "register expected"); Error(RegLoc, "register expected");
return 0; return true;
} }
int RegNum = TryParseRegister(); int RegNum = TryParseRegister();
if (RegNum == -1) { if (RegNum == -1) {
Error(RegLoc, "register expected"); Error(RegLoc, "register expected");
return 0; return true;
} }
if (IsRange) { if (IsRange) {
@ -518,7 +516,7 @@ ARMOperand *ARMAsmParser::ParseRegisterList() {
const AsmToken &RCurlyTok = Parser.getTok(); const AsmToken &RCurlyTok = Parser.getTok();
if (RCurlyTok.isNot(AsmToken::RCurly)) { if (RCurlyTok.isNot(AsmToken::RCurly)) {
Error(RCurlyTok.getLoc(), "'}' expected"); Error(RCurlyTok.getLoc(), "'}' expected");
return 0; return true;
} }
SMLoc E = RCurlyTok.getLoc(); SMLoc E = RCurlyTok.getLoc();
@ -540,7 +538,7 @@ ARMOperand *ARMAsmParser::ParseRegisterList() {
if (RegMap[Reg]) { if (RegMap[Reg]) {
Error(RegInfo.second, "register duplicated in register list"); Error(RegInfo.second, "register duplicated in register list");
return 0; return true;
} }
if (!EmittedWarning && Reg < HighRegNum) if (!EmittedWarning && Reg < HighRegNum)
@ -551,14 +549,17 @@ ARMOperand *ARMAsmParser::ParseRegisterList() {
HighRegNum = std::max(Reg, HighRegNum); HighRegNum = std::max(Reg, HighRegNum);
} }
return ARMOperand::CreateRegList(Registers, S, E); Operands.push_back(ARMOperand::CreateRegList(Registers, S, E));
return false;
} }
/// 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. /// or an error. The first token must be a '[' when called.
///
/// TODO Only preindexing and postindexing addressing are started, unindexed /// TODO Only preindexing and postindexing addressing are started, unindexed
/// with option, etc are still to do. /// with option, etc are still to do.
ARMOperand *ARMAsmParser::ParseMemory() { bool ARMAsmParser::
ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S, E; SMLoc S, E;
assert(Parser.getTok().is(AsmToken::LBrac) && assert(Parser.getTok().is(AsmToken::LBrac) &&
"Token is not a Left Bracket"); "Token is not a Left Bracket");
@ -568,12 +569,12 @@ ARMOperand *ARMAsmParser::ParseMemory() {
const AsmToken &BaseRegTok = Parser.getTok(); const AsmToken &BaseRegTok = Parser.getTok();
if (BaseRegTok.isNot(AsmToken::Identifier)) { if (BaseRegTok.isNot(AsmToken::Identifier)) {
Error(BaseRegTok.getLoc(), "register expected"); Error(BaseRegTok.getLoc(), "register expected");
return 0; return true;
} }
int BaseRegNum = TryParseRegister(); int BaseRegNum = TryParseRegister();
if (BaseRegNum == -1) { if (BaseRegNum == -1) {
Error(BaseRegTok.getLoc(), "register expected"); Error(BaseRegTok.getLoc(), "register expected");
return 0; return true;
} }
bool Preindexed = false; bool Preindexed = false;
@ -595,25 +596,34 @@ ARMOperand *ARMAsmParser::ParseMemory() {
const MCExpr *Offset; const MCExpr *Offset;
if (ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount, if (ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount,
Offset, OffsetIsReg, OffsetRegNum, E)) Offset, OffsetIsReg, OffsetRegNum, E))
return 0; return true;
const AsmToken &RBracTok = Parser.getTok(); const AsmToken &RBracTok = Parser.getTok();
if (RBracTok.isNot(AsmToken::RBrac)) { if (RBracTok.isNot(AsmToken::RBrac)) {
Error(RBracTok.getLoc(), "']' expected"); Error(RBracTok.getLoc(), "']' expected");
return 0; return true;
} }
E = RBracTok.getLoc(); E = RBracTok.getLoc();
Parser.Lex(); // Eat right bracket token. Parser.Lex(); // Eat right bracket token.
const AsmToken &ExclaimTok = Parser.getTok(); const AsmToken &ExclaimTok = Parser.getTok();
ARMOperand *WBOp = 0;
if (ExclaimTok.is(AsmToken::Exclaim)) { if (ExclaimTok.is(AsmToken::Exclaim)) {
E = ExclaimTok.getLoc(); WBOp = ARMOperand::CreateToken(ExclaimTok.getString(),
ExclaimTok.getLoc());
Writeback = true; Writeback = true;
Parser.Lex(); // Eat exclaim token Parser.Lex(); // Eat exclaim token
} }
return ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum,
OffsetRegShifted, ShiftType, ShiftAmount, Operands.push_back(ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset,
Preindexed, Postindexed, Negative, Writeback, OffsetRegNum, OffsetRegShifted,
S, E); ShiftType, ShiftAmount, Preindexed,
Postindexed, Negative, Writeback,
S, E));
if (WBOp)
Operands.push_back(WBOp);
return false;
} }
// The "[Rn" we have so far was not followed by a comma. // The "[Rn" we have so far was not followed by a comma.
else if (Tok.is(AsmToken::RBrac)) { else if (Tok.is(AsmToken::RBrac)) {
@ -629,27 +639,33 @@ ARMOperand *ARMAsmParser::ParseMemory() {
const MCExpr *Offset = 0; const MCExpr *Offset = 0;
const AsmToken &NextTok = Parser.getTok(); const AsmToken &NextTok = Parser.getTok();
if (NextTok.isNot(AsmToken::EndOfStatement)) { if (NextTok.isNot(AsmToken::EndOfStatement)) {
Postindexed = true; Postindexed = true;
Writeback = true; Writeback = true;
if (NextTok.isNot(AsmToken::Comma)) { if (NextTok.isNot(AsmToken::Comma)) {
Error(NextTok.getLoc(), "',' expected"); Error(NextTok.getLoc(), "',' expected");
return 0; return true;
} }
Parser.Lex(); // Eat comma token. Parser.Lex(); // Eat comma token.
if (ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, if (ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType,
ShiftAmount, Offset, OffsetIsReg, OffsetRegNum, ShiftAmount, Offset, OffsetIsReg, OffsetRegNum,
E)) E))
return 0; return true;
} }
return ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, Operands.push_back(ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset,
OffsetRegShifted, ShiftType, ShiftAmount, OffsetRegNum, OffsetRegShifted,
Preindexed, Postindexed, Negative, Writeback, ShiftType, ShiftAmount, Preindexed,
S, E); Postindexed, Negative, Writeback,
S, E));
return false;
} }
return 0; return true;
} }
/// Parse the offset of a memory operand after we have seen "[Rn," or "[Rn]," /// Parse the offset of a memory operand after we have seen "[Rn," or "[Rn],"
@ -760,28 +776,30 @@ bool ARMAsmParser::ParseShift(ShiftType &St, const MCExpr *&ShiftAmount,
/// Parse a arm instruction operand. For now this parses the operand regardless /// Parse a arm instruction operand. For now this parses the operand regardless
/// of the mnemonic. /// of the mnemonic.
ARMOperand *ARMAsmParser::ParseOperand() { bool ARMAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands){
SMLoc S, E; SMLoc S, E;
switch (getLexer().getKind()) { switch (getLexer().getKind()) {
default: default:
Error(Parser.getTok().getLoc(), "unexpected token in operand"); Error(Parser.getTok().getLoc(), "unexpected token in operand");
return 0; return true;
case AsmToken::Identifier: case AsmToken::Identifier: {
if (ARMOperand *Op = TryParseRegisterWithWriteBack()) if (!TryParseRegisterWithWriteBack(Operands))
return Op; return false;
// This was not a register so parse other operands that start with an // This was not a register so parse other operands that start with an
// identifier (like labels) as expressions and create them as immediates. // identifier (like labels) as expressions and create them as immediates.
const MCExpr *IdVal; const MCExpr *IdVal;
S = Parser.getTok().getLoc(); S = Parser.getTok().getLoc();
if (getParser().ParseExpression(IdVal)) if (getParser().ParseExpression(IdVal))
return 0; return true;
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
return ARMOperand::CreateImm(IdVal, S, E); Operands.push_back(ARMOperand::CreateImm(IdVal, S, E));
return false;
}
case AsmToken::LBrac: case AsmToken::LBrac:
return ParseMemory(); return ParseMemory(Operands);
case AsmToken::LCurly: case AsmToken::LCurly:
return ParseRegisterList(); return ParseRegisterList(Operands);
case AsmToken::Hash: case AsmToken::Hash:
// #42 -> immediate. // #42 -> immediate.
// TODO: ":lower16:" and ":upper16:" modifiers after # before immediate // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate
@ -789,9 +807,10 @@ ARMOperand *ARMAsmParser::ParseOperand() {
Parser.Lex(); Parser.Lex();
const MCExpr *ImmVal; const MCExpr *ImmVal;
if (getParser().ParseExpression(ImmVal)) if (getParser().ParseExpression(ImmVal))
return 0; return true;
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
return ARMOperand::CreateImm(ImmVal, S, E); Operands.push_back(ARMOperand::CreateImm(ImmVal, S, E));
return false;
} }
} }
@ -853,9 +872,7 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
// Read the remaining operands. // Read the remaining operands.
if (getLexer().isNot(AsmToken::EndOfStatement)) { if (getLexer().isNot(AsmToken::EndOfStatement)) {
// Read the first operand. // Read the first operand.
if (ARMOperand *Op = ParseOperand()) if (ParseOperand(Operands)) {
Operands.push_back(Op);
else {
Parser.EatToEndOfStatement(); Parser.EatToEndOfStatement();
return true; return true;
} }
@ -864,9 +881,7 @@ bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc,
Parser.Lex(); // Eat the comma. Parser.Lex(); // Eat the comma.
// Parse and remember the operand. // Parse and remember the operand.
if (ARMOperand *Op = ParseOperand()) if (ParseOperand(Operands)) {
Operands.push_back(Op);
else {
Parser.EatToEndOfStatement(); Parser.EatToEndOfStatement();
return true; return true;
} }

View File

@ -33,3 +33,21 @@
stmib r2, {r1,r3-r6,sp} stmib r2, {r1,r3-r6,sp}
stmda r2, {r1,r3-r6,sp} stmda r2, {r1,r3-r6,sp}
stmdb r2, {r1,r3-r6,sp} stmdb r2, {r1,r3-r6,sp}
@ CHECK: ldmia r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0xb2,0xe8]
@ CHECK: ldmib r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0xb2,0xe9]
@ CHECK: ldmda r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0x32,0xe8]
@ CHECK: ldmdb r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0x32,0xe9]
ldmia r2!, {r1,r3-r6,sp}
ldmib r2!, {r1,r3-r6,sp}
ldmda r2!, {r1,r3-r6,sp}
ldmdb r2!, {r1,r3-r6,sp}
@ CHECK: stmia r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0xa2,0xe8]
@ CHECK: stmib r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0xa2,0xe9]
@ CHECK: stmda r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0x22,0xe8]
@ CHECK: stmdb r2!, {r1, r3, r4, r5, r6, sp} @ encoding: [0x7a,0x20,0x22,0xe9]
stmia r2!, {r1,r3-r6,sp}
stmib r2!, {r1,r3-r6,sp}
stmda r2!, {r1,r3-r6,sp}
stmdb r2!, {r1,r3-r6,sp}