Updates to the ARM target assembler for llvm-mc per review comments from

Daniel Dunbar.
- Reordered the fields in the ARMOperand Mem struct to make the struct smaller.
Making bool's into 1 bit fields and put the MCExpr* fields adjacent to each
other.
- Fixed a number of places in ARMAsmParser.cpp so they have doxygen comments.
- Change the name of ARMAsmParser::ParseRegister() to MaybeParseRegister and
added the bool ParseWriteBack parameter.
- Changed ARMAsmParser::ParseMemory() to call MaybeParseRegister().
- Added ARMAsmParser::ParseMemoryOffsetReg to factor out parsing the offset of a
memory operand.  And use it for both parsing both preindexed and post indexing
addressing forms in ARMAsmParser::ParseMemory.
- Changed the first argument to ParseShift() to a reference.
- Changed ParseShift() to check for Rrx first and return to reduce nesting.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85632 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Kevin Enderby 2009-10-30 22:55:57 +00:00
parent 5e8e2d7ad9
commit 9c41fa87ea

View File

@ -44,13 +44,21 @@ private:
bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
bool ParseRegister(ARMOperand &Op); bool MaybeParseRegister(ARMOperand &Op, bool ParseWriteBack);
bool ParseRegisterList(ARMOperand &Op); bool ParseRegisterList(ARMOperand &Op);
bool ParseMemory(ARMOperand &Op); bool ParseMemory(ARMOperand &Op);
bool ParseShift(enum ShiftType *St, const MCExpr *&ShiftAmount); bool ParseMemoryOffsetReg(bool &Negative,
bool &OffsetRegShifted,
enum ShiftType &ShiftType,
const MCExpr *&ShiftAmount,
const MCExpr *&Offset,
bool &OffsetIsReg,
int OffsetRegNum);
bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount);
bool ParseOperand(ARMOperand &Op); bool ParseOperand(ARMOperand &Op);
@ -123,16 +131,17 @@ struct ARMOperand {
// This is for all forms of ARM address expressions // This is for all forms of ARM address expressions
struct { struct {
unsigned BaseRegNum; unsigned BaseRegNum;
bool OffsetIsReg;
const MCExpr *Offset; // used when OffsetIsReg is false
unsigned OffsetRegNum; // used when OffsetIsReg is true unsigned OffsetRegNum; // used when OffsetIsReg is true
bool OffsetRegShifted; // only used when OffsetIsReg is true const MCExpr *Offset; // used when OffsetIsReg is false
enum ShiftType ShiftType; // used when OffsetRegShifted is true
const MCExpr *ShiftAmount; // used when OffsetRegShifted is true const MCExpr *ShiftAmount; // used when OffsetRegShifted is true
bool Preindexed; enum ShiftType ShiftType; // used when OffsetRegShifted is true
bool Postindexed; unsigned
bool Negative; // only used when OffsetIsReg is true OffsetRegShifted : 1, // only used when OffsetIsReg is true
bool Writeback; Preindexed : 1,
Postindexed : 1,
OffsetIsReg : 1,
Negative : 1, // only used when OffsetIsReg is true
Writeback : 1;
} Mem; } Mem;
}; };
@ -208,12 +217,12 @@ struct ARMOperand {
} // end anonymous namespace. } // end anonymous namespace.
// 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 a Reg operand is created, the token is eaten /// 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. /// 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 /// 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.
bool ARMAsmParser::ParseRegister(ARMOperand &Op) { bool ARMAsmParser::MaybeParseRegister(ARMOperand &Op, bool ParseWriteBack) {
const AsmToken &Tok = getLexer().getTok(); const AsmToken &Tok = getLexer().getTok();
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
@ -227,10 +236,12 @@ bool ARMAsmParser::ParseRegister(ARMOperand &Op) {
getLexer().Lex(); // Eat identifier token. getLexer().Lex(); // Eat identifier token.
bool Writeback = false; bool Writeback = false;
const AsmToken &ExclaimTok = getLexer().getTok(); if (ParseWriteBack) {
if (ExclaimTok.is(AsmToken::Exclaim)) { const AsmToken &ExclaimTok = getLexer().getTok();
Writeback = true; if (ExclaimTok.is(AsmToken::Exclaim)) {
getLexer().Lex(); // Eat exclaim token Writeback = true;
getLexer().Lex(); // Eat exclaim token
}
} }
Op = ARMOperand::CreateReg(RegNum, Writeback); Op = ARMOperand::CreateReg(RegNum, Writeback);
@ -238,8 +249,8 @@ bool ARMAsmParser::ParseRegister(ARMOperand &Op) {
return false; return false;
} }
// Parse a register list, return false if successful else return true or an /// Parse a register list, return false if successful else return true or an
// error. The first token must be a '{' when called. /// error. The first token must be a '{' when called.
bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) { bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) {
assert(getLexer().getTok().is(AsmToken::LCurly) && assert(getLexer().getTok().is(AsmToken::LCurly) &&
"Token is not an Left Curly Brace"); "Token is not an Left Curly Brace");
@ -285,10 +296,10 @@ bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) {
return false; 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.
bool ARMAsmParser::ParseMemory(ARMOperand &Op) { bool ARMAsmParser::ParseMemory(ARMOperand &Op) {
assert(getLexer().getTok().is(AsmToken::LBrac) && assert(getLexer().getTok().is(AsmToken::LBrac) &&
"Token is not an Left Bracket"); "Token is not an Left Bracket");
@ -297,10 +308,9 @@ bool ARMAsmParser::ParseMemory(ARMOperand &Op) {
const AsmToken &BaseRegTok = getLexer().getTok(); const AsmToken &BaseRegTok = getLexer().getTok();
if (BaseRegTok.isNot(AsmToken::Identifier)) if (BaseRegTok.isNot(AsmToken::Identifier))
return Error(BaseRegTok.getLoc(), "register expected"); return Error(BaseRegTok.getLoc(), "register expected");
int BaseRegNum = MatchRegisterName(BaseRegTok.getString()); if (MaybeParseRegister(Op, false))
if (BaseRegNum == -1)
return Error(BaseRegTok.getLoc(), "register expected"); return Error(BaseRegTok.getLoc(), "register expected");
getLexer().Lex(); // Eat identifier token. int BaseRegNum = Op.getReg();
bool Preindexed = false; bool Preindexed = false;
bool Postindexed = false; bool Postindexed = false;
@ -308,55 +318,20 @@ bool ARMAsmParser::ParseMemory(ARMOperand &Op) {
bool Negative = false; bool Negative = false;
bool Writeback = false; bool Writeback = false;
// First look for preindexed address forms: // First look for preindexed address forms, that is after the "[Rn" we now
// [Rn, +/-Rm] // have to see if the next token is a comma.
// [Rn, #offset]
// [Rn, +/-Rm, shift]
// that is after the "[Rn" we now have see if the next token is a comma.
const AsmToken &Tok = getLexer().getTok(); const AsmToken &Tok = getLexer().getTok();
if (Tok.is(AsmToken::Comma)) { if (Tok.is(AsmToken::Comma)) {
Preindexed = true; Preindexed = true;
getLexer().Lex(); // Eat comma token. getLexer().Lex(); // Eat comma token.
int OffsetRegNum;
const AsmToken &NextTok = getLexer().getTok(); bool OffsetRegShifted;
if (NextTok.is(AsmToken::Plus))
getLexer().Lex(); // Eat plus token.
else if (NextTok.is(AsmToken::Minus)) {
Negative = true;
getLexer().Lex(); // Eat minus token
}
// See if there is a register following the "[Rn," we have so far.
const AsmToken &OffsetRegTok = getLexer().getTok();
int OffsetRegNum = MatchRegisterName(OffsetRegTok.getString());
bool OffsetRegShifted = false;
enum ShiftType ShiftType; enum ShiftType ShiftType;
const MCExpr *ShiftAmount; const MCExpr *ShiftAmount;
const MCExpr *Offset; const MCExpr *Offset;
if (OffsetRegNum != -1) { if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount,
OffsetIsReg = true; Offset, OffsetIsReg, OffsetRegNum))
getLexer().Lex(); // Eat identifier token for the offset register. return true;
// Look for a comma then a shift
const AsmToken &Tok = getLexer().getTok();
if (Tok.is(AsmToken::Comma)) {
getLexer().Lex(); // Eat comma token.
const AsmToken &Tok = getLexer().getTok();
if (ParseShift(&ShiftType, ShiftAmount))
return Error(Tok.getLoc(), "shift expected");
OffsetRegShifted = true;
}
}
else { // "[Rn," we have so far was not followed by "Rm"
// Look for #offset following the "[Rn,"
const AsmToken &HashTok = getLexer().getTok();
if (HashTok.isNot(AsmToken::Hash))
return Error(HashTok.getLoc(), "'#' expected");
getLexer().Lex(); // Eat hash token.
if (getParser().ParseExpression(Offset))
return true;
}
const AsmToken &RBracTok = getLexer().getTok(); const AsmToken &RBracTok = getLexer().getTok();
if (RBracTok.isNot(AsmToken::RBrac)) if (RBracTok.isNot(AsmToken::RBrac))
return Error(RBracTok.getLoc(), "']' expected"); return Error(RBracTok.getLoc(), "']' expected");
@ -374,11 +349,8 @@ bool ARMAsmParser::ParseMemory(ARMOperand &Op) {
} }
// 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)) {
// This is a post indexing addressing forms: // This is a post indexing addressing forms, that is a ']' follows after
// [Rn], #offset // the "[Rn".
// [Rn], +/-Rm
// [Rn], +/-Rm, shift
// that is a ']' follows after the "[Rn".
Postindexed = true; Postindexed = true;
Writeback = true; Writeback = true;
getLexer().Lex(); // Eat right bracket token. getLexer().Lex(); // Eat right bracket token.
@ -394,42 +366,9 @@ bool ARMAsmParser::ParseMemory(ARMOperand &Op) {
if (NextTok.isNot(AsmToken::Comma)) if (NextTok.isNot(AsmToken::Comma))
return Error(NextTok.getLoc(), "',' expected"); return Error(NextTok.getLoc(), "',' expected");
getLexer().Lex(); // Eat comma token. getLexer().Lex(); // Eat comma token.
if(ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType,
const AsmToken &PlusMinusTok = getLexer().getTok(); ShiftAmount, Offset, OffsetIsReg, OffsetRegNum))
if (PlusMinusTok.is(AsmToken::Plus)) return true;
getLexer().Lex(); // Eat plus token.
else if (PlusMinusTok.is(AsmToken::Minus)) {
Negative = true;
getLexer().Lex(); // Eat minus token
}
// See if there is a register following the "[Rn]," we have so far.
const AsmToken &OffsetRegTok = getLexer().getTok();
OffsetRegNum = MatchRegisterName(OffsetRegTok.getString());
if (OffsetRegNum != -1) {
OffsetIsReg = true;
getLexer().Lex(); // Eat identifier token for the offset register.
// Look for a comma then a shift
const AsmToken &Tok = getLexer().getTok();
if (Tok.is(AsmToken::Comma)) {
getLexer().Lex(); // Eat comma token.
const AsmToken &Tok = getLexer().getTok();
if (ParseShift(&ShiftType, ShiftAmount))
return Error(Tok.getLoc(), "shift expected");
OffsetRegShifted = true;
}
}
else { // "[Rn]," we have so far was not followed by "Rm"
// Look for #offset following the "[Rn],"
const AsmToken &HashTok = getLexer().getTok();
if (HashTok.isNot(AsmToken::Hash))
return Error(HashTok.getLoc(), "'#' expected");
getLexer().Lex(); // Eat hash token.
if (getParser().ParseExpression(Offset))
return true;
}
} }
Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum, Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum,
@ -441,45 +380,105 @@ bool ARMAsmParser::ParseMemory(ARMOperand &Op) {
return true; return true;
} }
/// ParseShift as one of these two: /// Parse the offset of a memory operand after we have seen "[Rn," or "[Rn],"
/// ( lsl | lsr | asr | ror ) , # shift_amount /// we will parse the following (were +/- means that a plus or minus is
/// rrx /// optional):
/// and returns true if it parses a shift otherwise it returns false. /// +/-Rm
bool ARMAsmParser::ParseShift(ShiftType *St, const MCExpr *&ShiftAmount) { /// +/-Rm, shift
const AsmToken &Tok = getLexer().getTok(); /// #offset
if (Tok.isNot(AsmToken::Identifier)) /// we return false on success or an error otherwise.
return true; bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative,
const StringRef &ShiftName = Tok.getString(); bool &OffsetRegShifted,
if (ShiftName == "lsl" || ShiftName == "LSL") enum ShiftType &ShiftType,
*St = Lsl; const MCExpr *&ShiftAmount,
else if (ShiftName == "lsr" || ShiftName == "LSR") const MCExpr *&Offset,
*St = Lsr; bool &OffsetIsReg,
else if (ShiftName == "asr" || ShiftName == "ASR") int OffsetRegNum) {
*St = Asr; ARMOperand Op;
else if (ShiftName == "ror" || ShiftName == "ROR") Negative = false;
*St = Ror; OffsetRegShifted = false;
else if (ShiftName == "rrx" || ShiftName == "RRX") OffsetIsReg = false;
*St = Rrx; OffsetRegNum = -1;
else const AsmToken &NextTok = getLexer().getTok();
return true; if (NextTok.is(AsmToken::Plus))
getLexer().Lex(); // Eat shift type token. getLexer().Lex(); // Eat plus token.
else if (NextTok.is(AsmToken::Minus)) {
Negative = true;
getLexer().Lex(); // Eat minus token
}
// See if there is a register following the "[Rn," or "[Rn]," we have so far.
const AsmToken &OffsetRegTok = getLexer().getTok();
if (OffsetRegTok.is(AsmToken::Identifier)) {
OffsetIsReg = !MaybeParseRegister(Op, false);
if (OffsetIsReg)
OffsetRegNum = Op.getReg();
}
// 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
const AsmToken &Tok = getLexer().getTok();
if (Tok.is(AsmToken::Comma)) {
getLexer().Lex(); // Eat comma token.
// For all but a Rotate right there must be a '#' and a shift amount const AsmToken &Tok = getLexer().getTok();
if (*St != Rrx) { if (ParseShift(ShiftType, ShiftAmount))
// Look for # following the shift type return Error(Tok.getLoc(), "shift expected");
OffsetRegShifted = true;
}
}
else { // the "[Rn," or "[Rn,]" we have so far was not followed by "Rm"
// Look for #offset following the "[Rn," or "[Rn],"
const AsmToken &HashTok = getLexer().getTok(); const AsmToken &HashTok = getLexer().getTok();
if (HashTok.isNot(AsmToken::Hash)) if (HashTok.isNot(AsmToken::Hash))
return Error(HashTok.getLoc(), "'#' expected"); return Error(HashTok.getLoc(), "'#' expected");
getLexer().Lex(); // Eat hash token. getLexer().Lex(); // Eat hash token.
if (getParser().ParseExpression(ShiftAmount)) if (getParser().ParseExpression(Offset))
return true; return true;
} }
return false;
}
/// ParseShift as one of these two:
/// ( 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) {
const AsmToken &Tok = getLexer().getTok();
if (Tok.isNot(AsmToken::Identifier))
return true;
const StringRef &ShiftName = Tok.getString();
if (ShiftName == "lsl" || ShiftName == "LSL")
St = Lsl;
else if (ShiftName == "lsr" || ShiftName == "LSR")
St = Lsr;
else if (ShiftName == "asr" || ShiftName == "ASR")
St = Asr;
else if (ShiftName == "ror" || ShiftName == "ROR")
St = Ror;
else if (ShiftName == "rrx" || ShiftName == "RRX")
St = Rrx;
else
return true;
getLexer().Lex(); // Eat shift type token.
// Rrx stands alone.
if (St == Rrx)
return false;
// Otherwise, there must be a '#' and a shift amount.
const AsmToken &HashTok = getLexer().getTok();
if (HashTok.isNot(AsmToken::Hash))
return Error(HashTok.getLoc(), "'#' expected");
getLexer().Lex(); // Eat hash token.
if (getParser().ParseExpression(ShiftAmount))
return true;
return false; return false;
} }
// A hack to allow some testing, to be replaced by a real table gen version. /// A hack to allow some testing, to be replaced by a real table gen version.
int ARMAsmParser::MatchRegisterName(const StringRef &Name) { int ARMAsmParser::MatchRegisterName(const StringRef &Name) {
if (Name == "r0" || Name == "R0") if (Name == "r0" || Name == "R0")
return 0; return 0;
@ -518,7 +517,7 @@ int ARMAsmParser::MatchRegisterName(const StringRef &Name) {
return -1; return -1;
} }
// A hack to allow some testing, to be replaced by a real table gen version. /// A hack to allow some testing, to be replaced by a real table gen version.
bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands, bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands,
MCInst &Inst) { MCInst &Inst) {
struct ARMOperand Op0 = Operands[0]; struct ARMOperand Op0 = Operands[0];
@ -549,12 +548,12 @@ bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands,
return true; return true;
} }
// 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.
bool ARMAsmParser::ParseOperand(ARMOperand &Op) { bool ARMAsmParser::ParseOperand(ARMOperand &Op) {
switch (getLexer().getKind()) { switch (getLexer().getKind()) {
case AsmToken::Identifier: case AsmToken::Identifier:
if (!ParseRegister(Op)) if (!MaybeParseRegister(Op, true))
return false; 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.
@ -581,7 +580,7 @@ bool ARMAsmParser::ParseOperand(ARMOperand &Op) {
} }
} }
// Parse an arm instruction mnemonic followed by its operands. /// Parse an arm instruction mnemonic followed by its operands.
bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) { bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) {
SmallVector<ARMOperand, 7> Operands; SmallVector<ARMOperand, 7> Operands;
@ -739,7 +738,7 @@ bool ARMAsmParser::ParseDirectiveCode(SMLoc L) {
return false; return false;
} }
// Force static initialization. /// Force static initialization.
extern "C" void LLVMInitializeARMAsmParser() { extern "C" void LLVMInitializeARMAsmParser() {
RegisterAsmParser<ARMAsmParser> X(TheARMTarget); RegisterAsmParser<ARMAsmParser> X(TheARMTarget);
RegisterAsmParser<ARMAsmParser> Y(TheThumbTarget); RegisterAsmParser<ARMAsmParser> Y(TheThumbTarget);