mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-01 17:32:36 +00:00
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:
parent
aa4cc1a6d7
commit
e8606dc7c8
@ -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]> {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user