Add support to the ARM asm parser for the register-shifted-register forms of basic instructions like ADD. More work left to be done to support other instances of shifter ops in the ISA.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@127917 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Owen Anderson 2011-03-18 22:50:18 +00:00
parent 31649e61bc
commit 0082830cb2
3 changed files with 96 additions and 26 deletions

View File

@ -381,11 +381,17 @@ def rot_imm : Operand<i32>, PatLeaf<(i32 imm), [{
let EncoderMethod = "getRotImmOpValue";
}
def ShifterAsmOperand : AsmOperandClass {
let Name = "Shifter";
let SuperClasses = [];
}
// shift_imm: An integer that encodes a shift amount and the type of shift
// (currently either asr or lsl) using the same encoding used for the
// immediates in so_reg operands.
def shift_imm : Operand<i32> {
let PrintMethod = "printShiftImmOperand";
let ParserMatchClass = ShifterAsmOperand;
}
// shifter_operand operands: so_reg and so_imm.
@ -394,14 +400,14 @@ def so_reg : Operand<i32>, // reg reg imm
[shl,srl,sra,rotr]> {
let EncoderMethod = "getSORegOpValue";
let PrintMethod = "printSORegOperand";
let MIOperandInfo = (ops GPR, GPR, i32imm);
let MIOperandInfo = (ops GPR, GPR, shift_imm);
}
def shift_so_reg : Operand<i32>, // reg reg imm
ComplexPattern<i32, 3, "SelectShiftShifterOperandReg",
[shl,srl,sra,rotr]> {
let EncoderMethod = "getSORegOpValue";
let PrintMethod = "printSORegOperand";
let MIOperandInfo = (ops GPR, GPR, i32imm);
let MIOperandInfo = (ops GPR, GPR, shift_imm);
}
// so_imm - Match a 32-bit shifter_operand immediate operand, which is an

View File

@ -29,15 +29,6 @@
#include "llvm/ADT/Twine.h"
using namespace llvm;
/// Shift types used for register controlled shifts in ARM memory addressing.
enum ShiftType {
Lsl,
Lsr,
Asr,
Ror,
Rrx
};
namespace {
class ARMOperand;
@ -55,6 +46,7 @@ class ARMAsmParser : public TargetAsmParser {
int TryParseRegister();
virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
bool TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &);
bool TryParseShiftRegister(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &, StringRef Mnemonic);
@ -65,13 +57,14 @@ class ARMAsmParser : public TargetAsmParser {
bool ParseMemoryOffsetReg(bool &Negative,
bool &OffsetRegShifted,
enum ShiftType &ShiftType,
enum ARM_AM::ShiftOpc &ShiftType,
const MCExpr *&ShiftAmount,
const MCExpr *&Offset,
bool &OffsetIsReg,
int &OffsetRegNum,
SMLoc &E);
bool ParseShift(enum ShiftType &St, const MCExpr *&ShiftAmount, SMLoc &E);
bool ParseShift(enum ARM_AM::ShiftOpc &St,
const MCExpr *&ShiftAmount, SMLoc &E);
bool ParseDirectiveWord(unsigned Size, SMLoc L);
bool ParseDirectiveThumb(SMLoc L);
bool ParseDirectiveThumbFunc(SMLoc L);
@ -136,6 +129,7 @@ class ARMOperand : public MCParsedAsmOperand {
RegisterList,
DPRRegisterList,
SPRRegisterList,
Shifter,
Token
} Kind;
@ -184,7 +178,7 @@ class ARMOperand : public MCParsedAsmOperand {
const MCExpr *Value; ///< Offset value, when !OffsetIsReg.
} Offset;
const MCExpr *ShiftAmount; // used when OffsetRegShifted is true
enum ShiftType ShiftType; // used when OffsetRegShifted is true
enum ARM_AM::ShiftOpc ShiftType; // used when OffsetRegShifted is true
unsigned OffsetRegShifted : 1; // only used when OffsetIsReg is true
unsigned Preindexed : 1;
unsigned Postindexed : 1;
@ -192,6 +186,11 @@ class ARMOperand : public MCParsedAsmOperand {
unsigned Negative : 1; // only used when OffsetIsReg is true
unsigned Writeback : 1;
} Mem;
struct {
ARM_AM::ShiftOpc ShiftTy;
unsigned RegNum;
} Shift;
};
ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
@ -234,6 +233,10 @@ public:
break;
case ProcIFlags:
IFlags = o.IFlags;
break;
case Shifter:
Shift = o.Shift;
break;
}
}
@ -310,7 +313,7 @@ public:
assert(Mem.OffsetIsReg && Mem.OffsetRegShifted && "Invalid access!");
return Mem.ShiftAmount;
}
enum ShiftType getMemShiftType() const {
enum ARM_AM::ShiftOpc getMemShiftType() const {
assert(Mem.OffsetIsReg && Mem.OffsetRegShifted && "Invalid access!");
return Mem.ShiftType;
}
@ -334,6 +337,7 @@ public:
bool isToken() const { return Kind == Token; }
bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; }
bool isMemory() const { return Kind == Memory; }
bool isShifter() const { return Kind == Shifter; }
bool isMemMode5() const {
if (!isMemory() || getMemOffsetIsReg() || getMemWriteback() ||
getMemNegative())
@ -402,6 +406,12 @@ public:
Inst.addOperand(MCOperand::CreateReg(getReg()));
}
void addShifterOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(
ARM_AM::getSORegOpc(Shift.ShiftTy, 0)));
}
void addRegListOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
const SmallVectorImpl<unsigned> &RegList = getRegList();
@ -525,6 +535,15 @@ public:
return Op;
}
static ARMOperand *CreateShifter(ARM_AM::ShiftOpc ShTy,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(Shifter);
Op->Shift.ShiftTy = ShTy;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *
CreateRegList(const SmallVectorImpl<std::pair<unsigned, SMLoc> > &Regs,
SMLoc StartLoc, SMLoc EndLoc) {
@ -555,7 +574,8 @@ public:
static ARMOperand *CreateMem(unsigned BaseRegNum, bool OffsetIsReg,
const MCExpr *Offset, int OffsetRegNum,
bool OffsetRegShifted, enum ShiftType ShiftType,
bool OffsetRegShifted,
enum ARM_AM::ShiftOpc ShiftType,
const MCExpr *ShiftAmount, bool Preindexed,
bool Postindexed, bool Negative, bool Writeback,
SMLoc S, SMLoc E) {
@ -676,6 +696,9 @@ void ARMOperand::dump(raw_ostream &OS) const {
case Register:
OS << "<register " << getReg() << ">";
break;
case Shifter:
OS << "<shifter " << getShiftOpcStr(Shift.ShiftTy) << ">";
break;
case RegisterList:
case DPRRegisterList:
case SPRRegisterList: {
@ -738,6 +761,42 @@ int ARMAsmParser::TryParseRegister() {
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.
///
bool ARMAsmParser::TryParseShiftRegister(
SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
std::string upperCase = Tok.getString().str();
std::string lowerCase = LowercaseString(upperCase);
ARM_AM::ShiftOpc ShiftTy = StringSwitch<ARM_AM::ShiftOpc>(lowerCase)
.Case("lsl", ARM_AM::lsl)
.Case("lsr", ARM_AM::lsr)
.Case("asr", ARM_AM::asr)
.Case("ror", ARM_AM::ror)
.Case("rrx", ARM_AM::rrx)
.Default(ARM_AM::no_shift);
if (ShiftTy == ARM_AM::no_shift)
return true;
Parser.Lex(); // Eat shift-type operand;
int RegNum = TryParseRegister();
if (RegNum == -1)
return Error(Parser.getTok().getLoc(), "register expected");
Operands.push_back(ARMOperand::CreateReg(RegNum,S, Parser.getTok().getLoc()));
Operands.push_back(ARMOperand::CreateShifter(ShiftTy,
S, Parser.getTok().getLoc()));
return false;
}
/// Try to parse a register name. The token must be an Identifier when called.
/// If it's a register, an AsmOperand is created. Another AsmOperand is created
/// if there is a "writeback". 'true' if it's not a register.
@ -1083,7 +1142,7 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
ARMOperand *WBOp = 0;
int OffsetRegNum = -1;
bool OffsetRegShifted = false;
enum ShiftType ShiftType = Lsl;
enum ARM_AM::ShiftOpc ShiftType = ARM_AM::lsl;
const MCExpr *ShiftAmount = 0;
const MCExpr *Offset = 0;
@ -1165,7 +1224,7 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
/// we return false on success or an error otherwise.
bool ARMAsmParser::ParseMemoryOffsetReg(bool &Negative,
bool &OffsetRegShifted,
enum ShiftType &ShiftType,
enum ARM_AM::ShiftOpc &ShiftType,
const MCExpr *&ShiftAmount,
const MCExpr *&Offset,
bool &OffsetIsReg,
@ -1226,28 +1285,28 @@ 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,
SMLoc &E) {
bool ARMAsmParser::ParseShift(ARM_AM::ShiftOpc &St,
const MCExpr *&ShiftAmount, SMLoc &E) {
const AsmToken &Tok = Parser.getTok();
if (Tok.isNot(AsmToken::Identifier))
return true;
StringRef ShiftName = Tok.getString();
if (ShiftName == "lsl" || ShiftName == "LSL")
St = Lsl;
St = ARM_AM::lsl;
else if (ShiftName == "lsr" || ShiftName == "LSR")
St = Lsr;
St = ARM_AM::lsr;
else if (ShiftName == "asr" || ShiftName == "ASR")
St = Asr;
St = ARM_AM::asr;
else if (ShiftName == "ror" || ShiftName == "ROR")
St = Ror;
St = ARM_AM::ror;
else if (ShiftName == "rrx" || ShiftName == "RRX")
St = Rrx;
St = ARM_AM::rrx;
else
return true;
Parser.Lex(); // Eat shift type token.
// Rrx stands alone.
if (St == Rrx)
if (St == ARM_AM::rrx)
return false;
// Otherwise, there must be a '#' and a shift amount.
@ -1286,6 +1345,9 @@ bool ARMAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
case AsmToken::Identifier:
if (!TryParseRegisterWithWriteBack(Operands))
return false;
if (!TryParseShiftRegister(Operands))
return false;
// Fall though for the Identifier case that is not a register or a
// special name.

View File

@ -282,3 +282,5 @@
@ CHECK: msr cpsr_fsxc, r0 @ encoding: [0x00,0xf0,0x2f,0xe1]
msr cpsr_fsxc, r0
@ CHECK: add r1, r2, r3, lsl r4 @ encoding: [0x13,0x14,0x82,0xe0]
add r1, r2, r3, lsl r4