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

@ -412,14 +412,20 @@ def shift_imm : Operand<i32> {
let ParserMatchClass = ShifterAsmOperand;
}
def ShiftedRegAsmOperand : AsmOperandClass {
let Name = "ShiftedReg";
}
// shifter_operand operands: so_reg and so_imm.
def so_reg : Operand<i32>, // reg reg imm
ComplexPattern<i32, 3, "SelectShifterOperandReg",
[shl,srl,sra,rotr]> {
let EncoderMethod = "getSORegOpValue";
let PrintMethod = "printSORegOperand";
let ParserMatchClass = ShiftedRegAsmOperand;
let MIOperandInfo = (ops GPR, GPR, shift_imm);
}
// FIXME: Does this need to be distinct from so_reg?
def shift_so_reg : Operand<i32>, // reg reg imm
ComplexPattern<i32, 3, "SelectShiftShifterOperandReg",
[shl,srl,sra,rotr]> {

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;

View File

@ -142,6 +142,8 @@ void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum,
// Print the shift opc.
ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO3.getImm());
O << ", " << ARM_AM::getShiftOpcStr(ShOpc);
if (ShOpc == ARM_AM::rrx)
return;
if (MO2.getReg()) {
O << ' ' << getRegisterName(MO2.getReg());
assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0);

View File

@ -1,6 +1,13 @@
@ RUN: llvm-mc -triple=armv7-apple-darwin -show-encoding < %s | FileCheck %s
.syntax unified
.globl _func
@ Check that the assembler can handle the documented syntax from the ARM ARM.
@ For complex constructs like shifter operands, check more thoroughly for them
@ once then spot check that following instructions accept the form generally.
@ This gives us good coverage while keeping the overall size of the test
@ more reasonable.
_func:
@ CHECK: _func
@ -31,3 +38,44 @@ _func:
@ CHECK: adcs r1, r2, #3840 @ encoding: [0x0f,0x1c,0xb2,0xe2]
@ CHECK: adcseq r1, r2, #3840 @ encoding: [0x0f,0x1c,0xb2,0x02]
@ CHECK: adceq r1, r2, #3840 @ encoding: [0x0f,0x1c,0xa2,0x02]
@ ADC (register)
adc r4, r5, r6
@ Constant shifts
adc r4, r5, r6, lsl #1
adc r4, r5, r6, lsl #31
adc r4, r5, r6, lsr #1
adc r4, r5, r6, lsr #31
adc r4, r5, r6, lsr #32
adc r4, r5, r6, asr #1
adc r4, r5, r6, asr #31
adc r4, r5, r6, asr #32
adc r4, r5, r6, ror #1
adc r4, r5, r6, ror #31
@ Register shifts
adc r6, r7, r8, lsl r9
adc r6, r7, r8, lsr r9
adc r6, r7, r8, asr r9
adc r6, r7, r8, ror r9
adc r4, r5, r6, rrx
@ CHECK: adc r4, r5, r6 @ encoding: [0x06,0x40,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, lsl #1 @ encoding: [0x86,0x40,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, lsl #31 @ encoding: [0x86,0x4f,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, lsr #1 @ encoding: [0xa6,0x40,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, lsr #31 @ encoding: [0xa6,0x4f,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, lsr #32 @ encoding: [0x26,0x40,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, asr #1 @ encoding: [0xc6,0x40,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, asr #31 @ encoding: [0xc6,0x4f,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, asr #32 @ encoding: [0x46,0x40,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, ror #1 @ encoding: [0xe6,0x40,0xa5,0xe0]
@ CHECK: adc r4, r5, r6, ror #31 @ encoding: [0xe6,0x4f,0xa5,0xe0]
@ CHECK: adc r6, r7, r8, lsl r9 @ encoding: [0x18,0x69,0xa7,0xe0]
@ CHECK: adc r6, r7, r8, lsr r9 @ encoding: [0x38,0x69,0xa7,0xe0]
@ CHECK: adc r6, r7, r8, asr r9 @ encoding: [0x58,0x69,0xa7,0xe0]
@ CHECK: adc r6, r7, r8, ror r9 @ encoding: [0x78,0x69,0xa7,0xe0]
@ CHECK: adc r4, r5, r6, rrx @ encoding: [0x66,0x40,0xa5,0xe0]