Flesh out ARM Parser support for shifted-register operands.

Now works for parsing register shifted register and register shifted
immediate arithmetic instructions, including the 'rrx' rotate with extend.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@135049 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jim Grosbach
2011-07-13 17:50:29 +00:00
parent aa4cc1a6d7
commit e8606dc7c8
4 changed files with 153 additions and 8 deletions

View File

@@ -164,6 +164,7 @@ class ARMOperand : public MCParsedAsmOperand {
RegisterList,
DPRRegisterList,
SPRRegisterList,
ShiftedRegister,
Shifter,
Token
} Kind;
@@ -225,8 +226,14 @@ class ARMOperand : public MCParsedAsmOperand {
struct {
ARM_AM::ShiftOpc ShiftTy;
unsigned RegNum;
unsigned Imm;
} Shift;
struct {
ARM_AM::ShiftOpc ShiftTy;
unsigned SrcReg;
unsigned ShiftReg;
unsigned ShiftImm;
} ShiftedReg;
};
ARMOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
@@ -273,6 +280,9 @@ public:
case Shifter:
Shift = o.Shift;
break;
case ShiftedRegister:
ShiftedReg = o.ShiftedReg;
break;
}
}
@@ -392,6 +402,7 @@ public:
bool isMemBarrierOpt() const { return Kind == MemBarrierOpt; }
bool isMemory() const { return Kind == Memory; }
bool isShifter() const { return Kind == Shifter; }
bool isShiftedReg() const { return Kind == ShiftedRegister; }
bool isMemMode2() const {
if (getMemAddrMode() != ARMII::AddrMode2)
return false;
@@ -522,6 +533,18 @@ public:
Inst.addOperand(MCOperand::CreateReg(getReg()));
}
void addShiftedRegOperands(MCInst &Inst, unsigned N) const {
assert(N == 3 && "Invalid number of operands!");
assert(isShiftedReg() && "addShiftedRegOperands() on non ShiftedReg!");
assert((ShiftedReg.ShiftReg == 0 ||
ARM_AM::getSORegOffset(ShiftedReg.ShiftImm) == 0) &&
"Invalid shifted register operand!");
Inst.addOperand(MCOperand::CreateReg(ShiftedReg.SrcReg));
Inst.addOperand(MCOperand::CreateReg(ShiftedReg.ShiftReg));
Inst.addOperand(MCOperand::CreateImm(
ARM_AM::getSORegOpc(ShiftedReg.ShiftTy, ShiftedReg.ShiftImm)));
}
void addShifterOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::CreateImm(
@@ -743,6 +766,21 @@ public:
return Op;
}
static ARMOperand *CreateShiftedRegister(ARM_AM::ShiftOpc ShTy,
unsigned SrcReg,
unsigned ShiftReg,
unsigned ShiftImm,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(ShiftedRegister);
Op->ShiftedReg.ShiftTy = ShTy;
Op->ShiftedReg.SrcReg = SrcReg;
Op->ShiftedReg.ShiftReg = ShiftReg;
Op->ShiftedReg.ShiftImm = ShiftImm;
Op->StartLoc = S;
Op->EndLoc = E;
return Op;
}
static ARMOperand *CreateShifter(ARM_AM::ShiftOpc ShTy,
SMLoc S, SMLoc E) {
ARMOperand *Op = new ARMOperand(Shifter);
@@ -907,7 +945,15 @@ void ARMOperand::print(raw_ostream &OS) const {
OS << "<register " << getReg() << ">";
break;
case Shifter:
OS << "<shifter " << getShiftOpcStr(Shift.ShiftTy) << ">";
OS << "<shifter " << ARM_AM::getShiftOpcStr(Shift.ShiftTy) << ">";
break;
case ShiftedRegister:
OS << "<so_reg"
<< ShiftedReg.SrcReg
<< ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(ShiftedReg.ShiftImm))
<< ", " << ShiftedReg.ShiftReg << ", "
<< ARM_AM::getSORegOffset(ShiftedReg.ShiftImm)
<< ">";
break;
case RegisterList:
case DPRRegisterList:
@@ -994,13 +1040,56 @@ bool ARMAsmParser::TryParseShiftRegister(
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");
Parser.Lex(); // Eat the operator.
Operands.push_back(ARMOperand::CreateReg(RegNum,S, Parser.getTok().getLoc()));
Operands.push_back(ARMOperand::CreateShifter(ShiftTy,
// The source register for the shift has already been added to the
// operand list, so we need to pop it off and combine it into the shifted
// register operand instead.
ARMOperand *PrevOp = (ARMOperand*)Operands.pop_back_val();
if (!PrevOp->isReg())
return Error(PrevOp->getStartLoc(), "shift must be of a register");
int SrcReg = PrevOp->getReg();
int64_t Imm = 0;
int ShiftReg = 0;
if (ShiftTy == ARM_AM::rrx) {
// RRX Doesn't have an explicit shift amount. The encoder expects
// the shift register to be the same as the source register. Seems odd,
// but OK.
ShiftReg = SrcReg;
} else {
// Figure out if this is shifted by a constant or a register (for non-RRX).
if (Parser.getTok().is(AsmToken::Hash)) {
Parser.Lex(); // Eat hash.
SMLoc ImmLoc = Parser.getTok().getLoc();
const MCExpr *ShiftExpr = 0;
if (getParser().ParseExpression(ShiftExpr))
return Error(ImmLoc, "invalid immediate shift value");
// The expression must be evaluatable as an immediate.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftExpr);
if (!CE)
return Error(ImmLoc, "invalid immediate shift value");
// Range check the immediate.
// lsl, ror: 0 <= imm <= 31
// lsr, asr: 0 <= imm <= 32
Imm = CE->getValue();
if (Imm < 0 ||
((ShiftTy == ARM_AM::lsl || ShiftTy == ARM_AM::ror) && Imm > 31) ||
((ShiftTy == ARM_AM::lsr || ShiftTy == ARM_AM::asr) && Imm > 32)) {
return Error(ImmLoc, "immediate shift value out of range");
}
} else if (Parser.getTok().is(AsmToken::Identifier)) {
ShiftReg = TryParseRegister();
SMLoc L = Parser.getTok().getLoc();
if (ShiftReg == -1)
return Error (L, "expected immediate or register in shift operand");
} else
return Error (Parser.getTok().getLoc(),
"expected immediate or register in shift operand");
}
Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg,
ShiftReg, Imm,
S, Parser.getTok().getLoc()));
return false;