mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-15 23:31:37 +00:00
ARM LDRD(immediate) assembly parsing and encoding support.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137244 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e2d8cf77c8
commit
2fd2b87ded
@ -710,20 +710,26 @@ def am2offset_imm : Operand<i32>,
|
|||||||
// addrmode3 := reg +/- reg
|
// addrmode3 := reg +/- reg
|
||||||
// addrmode3 := reg +/- imm8
|
// addrmode3 := reg +/- imm8
|
||||||
//
|
//
|
||||||
//def AddrMode3AsmOperand : AsmOperandClass { let Name = "AddrMode3"; }
|
// FIXME: split into imm vs. reg versions.
|
||||||
|
def AddrMode3AsmOperand : AsmOperandClass { let Name = "AddrMode3"; }
|
||||||
def addrmode3 : Operand<i32>,
|
def addrmode3 : Operand<i32>,
|
||||||
ComplexPattern<i32, 3, "SelectAddrMode3", []> {
|
ComplexPattern<i32, 3, "SelectAddrMode3", []> {
|
||||||
let EncoderMethod = "getAddrMode3OpValue";
|
let EncoderMethod = "getAddrMode3OpValue";
|
||||||
let PrintMethod = "printAddrMode3Operand";
|
let PrintMethod = "printAddrMode3Operand";
|
||||||
|
let ParserMatchClass = AddrMode3AsmOperand;
|
||||||
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
|
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: split into imm vs. reg versions.
|
||||||
|
// FIXME: parser method to handle +/- register.
|
||||||
|
def AM3OffsetAsmOperand : AsmOperandClass { let Name = "AM3Offset"; }
|
||||||
def am3offset : Operand<i32>,
|
def am3offset : Operand<i32>,
|
||||||
ComplexPattern<i32, 2, "SelectAddrMode3Offset",
|
ComplexPattern<i32, 2, "SelectAddrMode3Offset",
|
||||||
[], [SDNPWantRoot]> {
|
[], [SDNPWantRoot]> {
|
||||||
let EncoderMethod = "getAddrMode3OffsetOpValue";
|
let EncoderMethod = "getAddrMode3OffsetOpValue";
|
||||||
let DecoderMethod = "DecodeAddrMode3Offset";
|
let DecoderMethod = "DecodeAddrMode3Offset";
|
||||||
let PrintMethod = "printAddrMode3OffsetOperand";
|
let PrintMethod = "printAddrMode3OffsetOperand";
|
||||||
|
let ParserMatchClass = AM3OffsetAsmOperand;
|
||||||
let MIOperandInfo = (ops GPR, i32imm);
|
let MIOperandInfo = (ops GPR, i32imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2030,20 +2036,22 @@ def LDRD_PRE : AI3ldstidx<0b1101, 0, 1, 1, (outs GPR:$Rt, GPR:$Rt2, GPR:$Rn_wb),
|
|||||||
let Inst{11-8} = addr{7-4}; // imm7_4/zero
|
let Inst{11-8} = addr{7-4}; // imm7_4/zero
|
||||||
let Inst{3-0} = addr{3-0}; // imm3_0/Rm
|
let Inst{3-0} = addr{3-0}; // imm3_0/Rm
|
||||||
let DecoderMethod = "DecodeAddrMode3Instruction";
|
let DecoderMethod = "DecodeAddrMode3Instruction";
|
||||||
|
let AsmMatchConverter = "cvtLdrdPre";
|
||||||
}
|
}
|
||||||
def LDRD_POST: AI3ldstidx<0b1101, 0, 1, 0, (outs GPR:$Rt, GPR:$Rt2, GPR:$Rn_wb),
|
def LDRD_POST: AI3ldstidx<0b1101, 0, 1, 0, (outs GPR:$Rt, GPR:$Rt2, GPR:$Rn_wb),
|
||||||
(ins GPR:$Rn, am3offset:$offset), IndexModePost,
|
(ins addr_offset_none:$addr, am3offset:$offset),
|
||||||
LdMiscFrm, IIC_iLoad_d_ru,
|
IndexModePost, LdMiscFrm, IIC_iLoad_d_ru,
|
||||||
"ldrd", "\t$Rt, $Rt2, [$Rn], $offset",
|
"ldrd", "\t$Rt, $Rt2, $addr, $offset",
|
||||||
"$Rn = $Rn_wb", []> {
|
"$addr.base = $Rn_wb", []> {
|
||||||
bits<10> offset;
|
bits<10> offset;
|
||||||
bits<4> Rn;
|
bits<4> addr;
|
||||||
let Inst{23} = offset{8}; // U bit
|
let Inst{23} = offset{8}; // U bit
|
||||||
let Inst{22} = offset{9}; // 1 == imm8, 0 == Rm
|
let Inst{22} = offset{9}; // 1 == imm8, 0 == Rm
|
||||||
let Inst{19-16} = Rn;
|
let Inst{19-16} = addr;
|
||||||
let Inst{11-8} = offset{7-4}; // imm7_4/zero
|
let Inst{11-8} = offset{7-4}; // imm7_4/zero
|
||||||
let Inst{3-0} = offset{3-0}; // imm3_0/Rm
|
let Inst{3-0} = offset{3-0}; // imm3_0/Rm
|
||||||
let DecoderMethod = "DecodeAddrMode3Instruction";
|
let DecoderMethod = "DecodeAddrMode3Instruction";
|
||||||
|
// let AsmMatchConverter = "cvtLdrdPost";
|
||||||
}
|
}
|
||||||
} // hasExtraDefRegAllocReq = 1
|
} // hasExtraDefRegAllocReq = 1
|
||||||
} // mayLoad = 1, neverHasSideEffects = 1
|
} // mayLoad = 1, neverHasSideEffects = 1
|
||||||
|
@ -128,6 +128,8 @@ class ARMAsmParser : public MCTargetAsmParser {
|
|||||||
const SmallVectorImpl<MCParsedAsmOperand*> &);
|
const SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
bool cvtStExtTWriteBackReg(MCInst &Inst, unsigned Opcode,
|
bool cvtStExtTWriteBackReg(MCInst &Inst, unsigned Opcode,
|
||||||
const SmallVectorImpl<MCParsedAsmOperand*> &);
|
const SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
|
bool cvtLdrdPre(MCInst &Inst, unsigned Opcode,
|
||||||
|
const SmallVectorImpl<MCParsedAsmOperand*> &);
|
||||||
|
|
||||||
bool validateInstruction(MCInst &Inst,
|
bool validateInstruction(MCInst &Inst,
|
||||||
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
|
const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
|
||||||
@ -534,6 +536,29 @@ public:
|
|||||||
int64_t Val = CE->getValue();
|
int64_t Val = CE->getValue();
|
||||||
return Val > -4096 && Val < 4096;
|
return Val > -4096 && Val < 4096;
|
||||||
}
|
}
|
||||||
|
bool isAddrMode3() const {
|
||||||
|
if (Kind != Memory)
|
||||||
|
return false;
|
||||||
|
// No shifts are legal for AM3.
|
||||||
|
if (Mem.ShiftType != ARM_AM::no_shift) return false;
|
||||||
|
// Check for register offset.
|
||||||
|
if (Mem.OffsetRegNum) return true;
|
||||||
|
// Immediate offset in range [-255, 255].
|
||||||
|
if (!Mem.OffsetImm) return true;
|
||||||
|
int64_t Val = Mem.OffsetImm->getValue();
|
||||||
|
return Val > -256 && Val < 256;
|
||||||
|
}
|
||||||
|
bool isAM3Offset() const {
|
||||||
|
if (Kind != Immediate && Kind != PostIndexRegister)
|
||||||
|
return false;
|
||||||
|
if (Kind == PostIndexRegister)
|
||||||
|
return PostIdxReg.ShiftTy == ARM_AM::no_shift;
|
||||||
|
// Immediate offset in range [-255, 255].
|
||||||
|
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
|
||||||
|
if (!CE) return false;
|
||||||
|
int64_t Val = CE->getValue();
|
||||||
|
return Val > -256 && Val < 256;
|
||||||
|
}
|
||||||
bool isAddrMode5() const {
|
bool isAddrMode5() const {
|
||||||
if (Kind != Memory)
|
if (Kind != Memory)
|
||||||
return false;
|
return false;
|
||||||
@ -814,6 +839,46 @@ public:
|
|||||||
Inst.addOperand(MCOperand::CreateImm(Val));
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addAddrMode3Operands(MCInst &Inst, unsigned N) const {
|
||||||
|
assert(N == 3 && "Invalid number of operands!");
|
||||||
|
int32_t Val = Mem.OffsetImm ? Mem.OffsetImm->getValue() : 0;
|
||||||
|
if (!Mem.OffsetRegNum) {
|
||||||
|
ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add;
|
||||||
|
// Special case for #-0
|
||||||
|
if (Val == INT32_MIN) Val = 0;
|
||||||
|
if (Val < 0) Val = -Val;
|
||||||
|
Val = ARM_AM::getAM3Opc(AddSub, Val);
|
||||||
|
} else {
|
||||||
|
// For register offset, we encode the shift type and negation flag
|
||||||
|
// here.
|
||||||
|
Val = ARM_AM::getAM3Opc(Mem.isNegative ? ARM_AM::sub : ARM_AM::add, 0);
|
||||||
|
}
|
||||||
|
Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum));
|
||||||
|
Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum));
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addAM3OffsetOperands(MCInst &Inst, unsigned N) const {
|
||||||
|
assert(N == 2 && "Invalid number of operands!");
|
||||||
|
if (Kind == PostIndexRegister) {
|
||||||
|
int32_t Val =
|
||||||
|
ARM_AM::getAM3Opc(PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub, 0);
|
||||||
|
Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum));
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant offset.
|
||||||
|
const MCConstantExpr *CE = static_cast<const MCConstantExpr*>(getImm());
|
||||||
|
int32_t Val = CE->getValue();
|
||||||
|
ARM_AM::AddrOpc AddSub = Val < 0 ? ARM_AM::sub : ARM_AM::add;
|
||||||
|
// Special case for #-0
|
||||||
|
if (Val == INT32_MIN) Val = 0;
|
||||||
|
if (Val < 0) Val = -Val;
|
||||||
|
Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift);
|
||||||
|
Inst.addOperand(MCOperand::CreateReg(0));
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(Val));
|
||||||
|
}
|
||||||
|
|
||||||
void addAddrMode5Operands(MCInst &Inst, unsigned N) const {
|
void addAddrMode5Operands(MCInst &Inst, unsigned N) const {
|
||||||
assert(N == 2 && "Invalid number of operands!");
|
assert(N == 2 && "Invalid number of operands!");
|
||||||
// The lower two bits are always zero and as such are not encoded.
|
// The lower two bits are always zero and as such are not encoded.
|
||||||
@ -2046,6 +2111,24 @@ cvtStExtTWriteBackReg(MCInst &Inst, unsigned Opcode,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// cvtLdrdPre - Convert parsed operands to MCInst.
|
||||||
|
/// Needed here because the Asm Gen Matcher can't handle properly tied operands
|
||||||
|
/// when they refer multiple MIOperands inside a single one.
|
||||||
|
bool ARMAsmParser::
|
||||||
|
cvtLdrdPre(MCInst &Inst, unsigned Opcode,
|
||||||
|
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||||
|
// Rt, Rt2
|
||||||
|
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
|
||||||
|
((ARMOperand*)Operands[3])->addRegOperands(Inst, 1);
|
||||||
|
// Create a writeback register dummy placeholder.
|
||||||
|
Inst.addOperand(MCOperand::CreateImm(0));
|
||||||
|
// addr
|
||||||
|
((ARMOperand*)Operands[4])->addAddrMode3Operands(Inst, 3);
|
||||||
|
// pred
|
||||||
|
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
bool ARMAsmParser::
|
bool ARMAsmParser::
|
||||||
@ -2645,6 +2728,9 @@ bool ARMAsmParser::
|
|||||||
validateInstruction(MCInst &Inst,
|
validateInstruction(MCInst &Inst,
|
||||||
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
|
||||||
switch (Inst.getOpcode()) {
|
switch (Inst.getOpcode()) {
|
||||||
|
case ARM::LDRD:
|
||||||
|
case ARM::LDRD_PRE:
|
||||||
|
case ARM::LDRD_POST:
|
||||||
case ARM::LDREXD: {
|
case ARM::LDREXD: {
|
||||||
// Rt2 must be Rt + 1.
|
// Rt2 must be Rt + 1.
|
||||||
unsigned Rt = getARMRegisterNumbering(Inst.getOperand(0).getReg());
|
unsigned Rt = getARMRegisterNumbering(Inst.getOperand(0).getReg());
|
||||||
@ -2654,6 +2740,9 @@ validateInstruction(MCInst &Inst,
|
|||||||
"destination operands must be sequential");
|
"destination operands must be sequential");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
case ARM::STRgD:
|
||||||
|
case ARM::STRgD_PRE:
|
||||||
|
case ARM::STRgD_POST:
|
||||||
case ARM::STREXD: {
|
case ARM::STREXD: {
|
||||||
// Rt2 must be Rt + 1.
|
// Rt2 must be Rt + 1.
|
||||||
unsigned Rt = getARMRegisterNumbering(Inst.getOperand(1).getReg());
|
unsigned Rt = getARMRegisterNumbering(Inst.getOperand(1).getReg());
|
||||||
|
@ -105,3 +105,17 @@ _func:
|
|||||||
@ CHECK: ldrbt r2, [r8], #-8 @ encoding: [0x08,0x20,0x78,0xe4]
|
@ CHECK: ldrbt r2, [r8], #-8 @ encoding: [0x08,0x20,0x78,0xe4]
|
||||||
@ CHECK: ldrbt r8, [r7], r6 @ encoding: [0x06,0x80,0xf7,0xe6]
|
@ CHECK: ldrbt r8, [r7], r6 @ encoding: [0x06,0x80,0xf7,0xe6]
|
||||||
@ CHECK: ldrbt r1, [r2], -r6, lsl #12 @ encoding: [0x06,0x16,0x72,0xe6]
|
@ CHECK: ldrbt r1, [r2], -r6, lsl #12 @ encoding: [0x06,0x16,0x72,0xe6]
|
||||||
|
|
||||||
|
|
||||||
|
@------------------------------------------------------------------------------
|
||||||
|
@ LDRD (immediate)
|
||||||
|
@------------------------------------------------------------------------------
|
||||||
|
ldrd r3, r4, [r5]
|
||||||
|
ldrd r7, r8, [r2, #15]
|
||||||
|
ldrd r1, r2, [r9, #32]!
|
||||||
|
ldrd r6, r7, [r1], #8
|
||||||
|
|
||||||
|
@ CHECK: ldrd r3, r4, [r5] @ encoding: [0xd0,0x30,0xc5,0xe1]
|
||||||
|
@ CHECK: ldrd r7, r8, [r2, #15] @ encoding: [0xdf,0x70,0xc2,0xe1]
|
||||||
|
@ CHECK: ldrd r1, r2, [r9, #32]! @ encoding: [0xd0,0x12,0xe9,0xe1]
|
||||||
|
@ CHECK: ldrd r6, r7, [r1], #8 @ encoding: [0xd8,0x60,0xc1,0xe0]
|
||||||
|
@ -283,3 +283,17 @@
|
|||||||
@ CHECK-ERRORS: error: bitfield width must be in range [1,32-lsb]
|
@ CHECK-ERRORS: error: bitfield width must be in range [1,32-lsb]
|
||||||
@ CHECK-ERRORS: ubfxgt r4, r5, #16, #17
|
@ CHECK-ERRORS: ubfxgt r4, r5, #16, #17
|
||||||
@ CHECK-ERRORS: ^
|
@ CHECK-ERRORS: ^
|
||||||
|
|
||||||
|
@ Out of order Rt/Rt2 operands for ldrd
|
||||||
|
ldrd r4, r3, [r8]
|
||||||
|
ldrd r4, r3, [r8, #8]!
|
||||||
|
ldrd r4, r3, [r8], #8
|
||||||
|
@ CHECK-ERRORS: error: destination operands must be sequential
|
||||||
|
@ CHECK-ERRORS: ldrd r4, r3, [r8]
|
||||||
|
@ CHECK-ERRORS: ^
|
||||||
|
@ CHECK-ERRORS: error: destination operands must be sequential
|
||||||
|
@ CHECK-ERRORS: ldrd r4, r3, [r8, #8]!
|
||||||
|
@ CHECK-ERRORS: ^
|
||||||
|
@ CHECK-ERRORS: error: destination operands must be sequential
|
||||||
|
@ CHECK-ERRORS: ldrd r4, r3, [r8], #8
|
||||||
|
@ CHECK-ERRORS: ^
|
||||||
|
Loading…
x
Reference in New Issue
Block a user