- Implement asm parsing support for LDRSBT, LDRHT, LDRSHT and STRHT

also fix the encoding of the later.
- Add a new encoding bit to describe the index mode used in AM3.
- Teach printAddrMode3Operand to check by the addressing mode which
  index mode to print.
- Testcases.

llvm-svn: 128832
This commit is contained in:
Bruno Cardoso Lopes 2011-04-04 17:18:19 +00:00
parent 94fc1341f5
commit 74363376e4
8 changed files with 258 additions and 32 deletions

View File

@ -409,7 +409,7 @@ namespace ARM_AM {
// The first operand is always a Reg. The second operand is a reg if in
// reg/reg form, otherwise it's reg#0. The third field encodes the operation
// in bit 12, the immediate in bits 0-11, and the shift op in 13-15. The
// forth operand 16-17 encodes the index mode.
// fourth operand 16-17 encodes the index mode.
//
// If this addressing mode is a frame index (before prolog/epilog insertion
// and code rewriting), this operand will have the form: FI#, reg0, <offs>
@ -446,12 +446,14 @@ namespace ARM_AM {
//
// The first operand is always a Reg. The second operand is a reg if in
// reg/reg form, otherwise it's reg#0. The third field encodes the operation
// in bit 8, the immediate in bits 0-7.
// in bit 8, the immediate in bits 0-7. The fourth operand 9-10 encodes the
// index mode.
/// getAM3Opc - This function encodes the addrmode3 opc field.
static inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset) {
static inline unsigned getAM3Opc(AddrOpc Opc, unsigned char Offset,
unsigned IdxMode = 0) {
bool isSub = Opc == sub;
return ((int)isSub << 8) | Offset;
return ((int)isSub << 8) | Offset | (IdxMode << 9);
}
static inline unsigned char getAM3Offset(unsigned AM3Opc) {
return AM3Opc & 0xFF;
@ -459,6 +461,9 @@ namespace ARM_AM {
static inline AddrOpc getAM3Op(unsigned AM3Opc) {
return ((AM3Opc >> 8) & 1) ? sub : add;
}
static inline unsigned getAM3IdxMode(unsigned AM3Opc) {
return (AM3Opc >> 9);
}
//===--------------------------------------------------------------------===//
// Addressing Mode #4

View File

@ -577,6 +577,34 @@ class AI3ldstidx<bits<4> op, bit op20, bit isLd, bit isPre, dag oops, dag iops,
let Inst{15-12} = Rt; // Rt
let Inst{7-4} = op;
}
// FIXME: Merge with the above class when addrmode2 gets used for LDR, LDRB
// but for now use this class for LDRSBT, LDRHT, LDSHT.
class AI3ldstidxT<bits<4> op, bit op20, bit isLd, bit isPre, dag oops, dag iops,
IndexMode im, Format f, InstrItinClass itin, string opc,
string asm, string cstr, list<dag> pattern>
: I<oops, iops, AddrMode3, Size4Bytes, im, f, itin,
opc, asm, cstr, pattern> {
// {13} 1 == imm8, 0 == Rm
// {12-9} Rn
// {8} isAdd
// {7-4} imm7_4/zero
// {3-0} imm3_0/Rm
bits<14> addr;
bits<4> Rt;
let Inst{27-25} = 0b000;
let Inst{24} = isPre; // P bit
let Inst{23} = addr{8}; // U bit
let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm
let Inst{20} = op20; // L bit
let Inst{19-16} = addr{12-9}; // Rn
let Inst{15-12} = Rt; // Rt
let Inst{11-8} = addr{7-4}; // imm7_4/zero
let Inst{7-4} = op;
let Inst{3-0} = addr{3-0}; // imm3_0/Rm
let AsmMatchConverter = "CvtLdWriteBackRegAddrMode3";
}
class AI3stridx<bits<4> op, bit isByte, bit isPre, dag oops, dag iops,
IndexMode im, Format f, InstrItinClass itin, string opc,
string asm, string cstr, list<dag> pattern>
@ -649,12 +677,25 @@ class AI3sthpo<dag oops, dag iops, Format f, InstrItinClass itin,
string opc, string asm, string cstr, list<dag> pattern>
: I<oops, iops, AddrMode3, Size4Bytes, IndexModePost, f, itin,
opc, asm, cstr,pattern> {
// {13} 1 == imm8, 0 == Rm
// {12-9} Rn
// {8} isAdd
// {7-4} imm7_4/zero
// {3-0} imm3_0/Rm
bits<14> addr;
bits<4> Rt;
let Inst{3-0} = addr{3-0}; // imm3_0/Rm
let Inst{4} = 1;
let Inst{5} = 1; // H bit
let Inst{6} = 0; // S bit
let Inst{7} = 1;
let Inst{11-8} = addr{7-4}; // imm7_4/zero
let Inst{15-12} = Rt; // Rt
let Inst{19-16} = addr{12-9}; // Rn
let Inst{20} = 0; // L bit
let Inst{21} = 0; // W bit
let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm
let Inst{23} = addr{8}; // U bit
let Inst{24} = 0; // P bit
let Inst{27-25} = 0b000;
}

View File

@ -475,6 +475,17 @@ def width_imm : Operand<i32>, PatLeaf<(imm), [{
// Define ARM specific addressing modes.
def MemMode2AsmOperand : AsmOperandClass {
let Name = "MemMode2";
let SuperClasses = [];
let ParserMethod = "tryParseMemMode2Operand";
}
def MemMode3AsmOperand : AsmOperandClass {
let Name = "MemMode3";
let SuperClasses = [];
let ParserMethod = "tryParseMemMode3Operand";
}
// addrmode_imm12 := reg +/- imm12
//
@ -498,12 +509,6 @@ def ldst_so_reg : Operand<i32>,
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
}
def MemMode2AsmOperand : AsmOperandClass {
let Name = "MemMode2";
let SuperClasses = [];
let ParserMethod = "tryParseMemMode2Operand";
}
// addrmode2 := reg +/- imm12
// := reg +/- reg shop imm
//
@ -530,6 +535,7 @@ def addrmode3 : Operand<i32>,
ComplexPattern<i32, 3, "SelectAddrMode3", []> {
let EncoderMethod = "getAddrMode3OpValue";
let PrintMethod = "printAddrMode3Operand";
let ParserMatchClass = MemMode3AsmOperand;
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
}
@ -1763,22 +1769,19 @@ def LDRBT : AI2ldstidx<1, 1, 0, (outs GPR:$Rt, GPR:$base_wb),
let Inst{11-0} = addr{11-0};
let AsmMatchConverter = "CvtLdWriteBackRegAddrMode2";
}
def LDRSBT : AI3ldstidx<0b1101, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb),
(ins GPR:$base, am3offset:$offset), IndexModePost,
LdMiscFrm, IIC_iLoad_bh_ru,
"ldrsbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
def LDRSBT : AI3ldstidxT<0b1101, 1, 1, 0, (outs GPR:$Rt, GPR:$base_wb),
(ins addrmode3:$addr), IndexModePost, LdMiscFrm, IIC_iLoad_bh_ru,
"ldrsbt", "\t$Rt, $addr", "$addr.base = $base_wb", []> {
let Inst{21} = 1; // overwrite
}
def LDRHT : AI3ldstidx<0b1011, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb),
(ins GPR:$base, am3offset:$offset), IndexModePost,
LdMiscFrm, IIC_iLoad_bh_ru,
"ldrht", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
def LDRHT : AI3ldstidxT<0b1011, 1, 1, 0, (outs GPR:$Rt, GPR:$base_wb),
(ins addrmode3:$addr), IndexModePost, LdMiscFrm, IIC_iLoad_bh_ru,
"ldrht", "\t$Rt, $addr", "$addr.base = $base_wb", []> {
let Inst{21} = 1; // overwrite
}
def LDRSHT : AI3ldstidx<0b1111, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb),
(ins GPR:$base, am3offset:$offset), IndexModePost,
LdMiscFrm, IIC_iLoad_bh_ru,
"ldrsht", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
def LDRSHT : AI3ldstidxT<0b1111, 1, 1, 0, (outs GPR:$Rt, GPR:$base_wb),
(ins addrmode3:$addr), IndexModePost, LdMiscFrm, IIC_iLoad_bh_ru,
"ldrsht", "\t$Rt, $addr", "$addr.base = $base_wb", []> {
let Inst{21} = 1; // overwrite
}
}
@ -1870,12 +1873,12 @@ def STRBT : AI2stridxT<1, 0, (outs GPR:$Rn_wb), (ins GPR:$Rt, addrmode2:$addr),
let AsmMatchConverter = "CvtStWriteBackRegAddrMode2";
}
def STRHT: AI3sthpo<(outs GPR:$base_wb),
(ins GPR:$src, GPR:$base,am3offset:$offset),
def STRHT: AI3sthpo<(outs GPR:$base_wb), (ins GPR:$Rt, addrmode3:$addr),
StMiscFrm, IIC_iStore_bh_ru,
"strht", "\t$src, [$base], $offset", "$base = $base_wb",
"strht", "\t$Rt, $addr", "$addr.base = $base_wb",
[/* For disassembly only; pattern left blank */]> {
let Inst{21} = 1; // overwrite
let AsmMatchConverter = "CvtStWriteBackRegAddrMode3";
}
//===----------------------------------------------------------------------===//

View File

@ -98,12 +98,18 @@ class ARMAsmParser : public TargetAsmParser {
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy tryParseMemMode2Operand(
SmallVectorImpl<MCParsedAsmOperand*>&);
OperandMatchResultTy tryParseMemMode3Operand(
SmallVectorImpl<MCParsedAsmOperand*>&);
// Asm Match Converter Methods
bool CvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool CvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool CvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
bool CvtStWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &);
public:
ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM)
@ -371,6 +377,30 @@ public:
return true;
}
bool isMemMode3() const {
if (getMemAddrMode() != ARMII::AddrMode3)
return false;
if (getMemOffsetIsReg()) {
if (getMemOffsetRegShifted())
return false; // No shift with offset reg allowed
return true;
}
if (getMemNegative() &&
!(getMemPostindexed() || getMemPreindexed()))
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getMemOffset());
if (!CE) return false;
int64_t Value = CE->getValue();
// The offset must be in the range 0-255 (imm8).
if (Value > 255 || Value < -255)
return false;
return true;
}
bool isMemMode5() const {
if (!isMemory() || getMemOffsetIsReg() || getMemWriteback() ||
getMemNegative())
@ -539,6 +569,37 @@ public:
-Offset, ARM_AM::no_shift, IdxMode)));
}
void addMemMode3Operands(MCInst &Inst, unsigned N) const {
assert(isMemMode3() && "Invalid mode or number of operands!");
Inst.addOperand(MCOperand::CreateReg(getMemBaseRegNum()));
unsigned IdxMode = (getMemPreindexed() | getMemPostindexed() << 1);
if (getMemOffsetIsReg()) {
Inst.addOperand(MCOperand::CreateReg(getMemOffsetRegNum()));
ARM_AM::AddrOpc AMOpc = getMemNegative() ? ARM_AM::sub : ARM_AM::add;
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM3Opc(AMOpc, 0,
IdxMode)));
return;
}
// Create a operand placeholder to always yield the same number of operands.
Inst.addOperand(MCOperand::CreateReg(0));
// FIXME: #-0 is encoded differently than #0. Does the parser preserve
// the difference?
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getMemOffset());
assert(CE && "Non-constant mode 3 offset operand!");
int64_t Offset = CE->getValue();
if (Offset >= 0)
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM3Opc(ARM_AM::add,
Offset, IdxMode)));
else
Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM3Opc(ARM_AM::sub,
-Offset, IdxMode)));
}
void addMemMode5Operands(MCInst &Inst, unsigned N) const {
assert(N == 2 && isMemMode5() && "Invalid number of operands!");
@ -1219,6 +1280,17 @@ tryParseMemMode2Operand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
return MatchOperand_Success;
}
/// tryParseMemMode3Operand - Try to parse memory addressing mode 3 operand.
ARMAsmParser::OperandMatchResultTy ARMAsmParser::
tryParseMemMode3Operand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
assert(Parser.getTok().is(AsmToken::LBrac) && "Token is not a \"[\"");
if (ParseMemory(Operands, ARMII::AddrMode3))
return MatchOperand_NoMatch;
return MatchOperand_Success;
}
/// CvtLdWriteBackRegAddrMode2 - 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.
@ -1249,6 +1321,36 @@ CvtStWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
return true;
}
/// CvtLdWriteBackRegAddrMode3 - 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::
CvtLdWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
// Create a writeback register dummy placeholder.
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[3])->addMemMode3Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
return true;
}
/// CvtStWriteBackRegAddrMode3 - 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::
CvtStWriteBackRegAddrMode3(MCInst &Inst, unsigned Opcode,
const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
// Create a writeback register dummy placeholder.
Inst.addOperand(MCOperand::CreateImm(0));
((ARMOperand*)Operands[2])->addRegOperands(Inst, 1);
((ARMOperand*)Operands[3])->addMemMode3Operands(Inst, 3);
((ARMOperand*)Operands[1])->addCondCodeOperands(Inst, 2);
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.
///
@ -1310,6 +1412,10 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
const AsmToken &ExclaimTok = Parser.getTok();
if (ExclaimTok.is(AsmToken::Exclaim)) {
// None of addrmode3 instruction uses "!"
if (AddrMode == ARMII::AddrMode3)
return true;
WBOp = ARMOperand::CreateToken(ExclaimTok.getString(),
ExclaimTok.getLoc());
Writeback = true;
@ -1350,6 +1456,11 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
if (!OffsetIsReg) {
if (!Offset)
Offset = MCConstantExpr::Create(0, getContext());
} else {
if (AddrMode == ARMII::AddrMode3 && OffsetRegShifted) {
Error(E, "shift amount not supported");
return true;
}
}
Operands.push_back(ARMOperand::CreateMem(AddrMode, BaseRegNum, OffsetIsReg,

View File

@ -1237,19 +1237,22 @@ static bool DisassembleLdStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn,
"Expect 1 reg operand followed by 1 imm operand");
ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub;
unsigned IndexMode =
(TID.TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
if (getAM3IBit(insn) == 1) {
MI.addOperand(MCOperand::CreateReg(0));
// Disassemble the 8-bit immediate offset.
unsigned Imm4H = (insn >> ARMII::ImmHiShift) & 0xF;
unsigned Imm4L = insn & 0xF;
unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, (Imm4H << 4) | Imm4L);
unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, (Imm4H << 4) | Imm4L,
IndexMode);
MI.addOperand(MCOperand::CreateImm(Offset));
} else {
// Disassemble the offset reg (Rm).
MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID,
decodeRm(insn))));
unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, 0);
unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, 0, IndexMode);
MI.addOperand(MCOperand::CreateImm(Offset));
}
OpIdx += 2;

View File

@ -181,6 +181,10 @@ void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum,
}
}
//===--------------------------------------------------------------------===//
// Addressing Mode #2
//===--------------------------------------------------------------------===//
void ARMInstPrinter::printAM2PreOrOffsetIndexOp(const MCInst *MI, unsigned Op,
raw_ostream &O) {
const MCOperand &MO1 = MI->getOperand(Op);
@ -276,11 +280,35 @@ void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI,
<< " #" << ShImm;
}
void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned OpNum,
raw_ostream &O) {
const MCOperand &MO1 = MI->getOperand(OpNum);
const MCOperand &MO2 = MI->getOperand(OpNum+1);
const MCOperand &MO3 = MI->getOperand(OpNum+2);
//===--------------------------------------------------------------------===//
// Addressing Mode #3
//===--------------------------------------------------------------------===//
void ARMInstPrinter::printAM3PostIndexOp(const MCInst *MI, unsigned Op,
raw_ostream &O) {
const MCOperand &MO1 = MI->getOperand(Op);
const MCOperand &MO2 = MI->getOperand(Op+1);
const MCOperand &MO3 = MI->getOperand(Op+2);
O << "[" << getRegisterName(MO1.getReg()) << "], ";
if (MO2.getReg()) {
O << (char)ARM_AM::getAM3Op(MO3.getImm())
<< getRegisterName(MO2.getReg());
return;
}
unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm());
O << '#'
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm()))
<< ImmOffs;
}
void ARMInstPrinter::printAM3PreOrOffsetIndexOp(const MCInst *MI, unsigned Op,
raw_ostream &O) {
const MCOperand &MO1 = MI->getOperand(Op);
const MCOperand &MO2 = MI->getOperand(Op+1);
const MCOperand &MO3 = MI->getOperand(Op+2);
O << '[' << getRegisterName(MO1.getReg());
@ -297,6 +325,18 @@ void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned OpNum,
O << ']';
}
void ARMInstPrinter::printAddrMode3Operand(const MCInst *MI, unsigned Op,
raw_ostream &O) {
const MCOperand &MO3 = MI->getOperand(Op+2);
unsigned IdxMode = ARM_AM::getAM3IdxMode(MO3.getImm());
if (IdxMode == ARMII::IndexModePost) {
printAM3PostIndexOp(MI, Op, O);
return;
}
printAM3PreOrOffsetIndexOp(MI, Op, O);
}
void ARMInstPrinter::printAddrMode3OffsetOperand(const MCInst *MI,
unsigned OpNum,
raw_ostream &O) {

View File

@ -49,9 +49,14 @@ public:
raw_ostream &O);
void printAddrMode2OffsetOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O);
void printAddrMode3Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printAM3PostIndexOp(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printAM3PreOrOffsetIndexOp(const MCInst *MI, unsigned OpNum,
raw_ostream &O);
void printAddrMode3OffsetOperand(const MCInst *MI, unsigned OpNum,
raw_ostream &O);
void printLdStmModeOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printAddrMode5Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
void printAddrMode6Operand(const MCInst *MI, unsigned OpNum, raw_ostream &O);

View File

@ -0,0 +1,18 @@
@ RUN: llvm-mc -mcpu=cortex-a8 -triple arm-unknown-unknown -show-encoding %s | FileCheck %s
@ CHECK: ldrsbt r1, [r0], +r2 @ encoding: [0xd2,0x10,0xb0,0xe0]
@ CHECK: ldrsbt r1, [r0], #4 @ encoding: [0xd4,0x10,0xf0,0xe0]
@ CHECK: ldrsht r1, [r0], +r2 @ encoding: [0xf2,0x10,0xb0,0xe0]
@ CHECK: ldrsht r1, [r0], #4 @ encoding: [0xf4,0x10,0xf0,0xe0]
@ CHECK: ldrht r1, [r0], +r2 @ encoding: [0xb2,0x10,0xb0,0xe0]
@ CHECK: ldrht r1, [r0], #4 @ encoding: [0xb4,0x10,0xf0,0xe0]
@ CHECK: strht r1, [r0], +r2 @ encoding: [0xb2,0x10,0xa0,0xe0]
@ CHECK: strht r1, [r0], #4 @ encoding: [0xb4,0x10,0xe0,0xe0]
ldrsbt r1, [r0], r2
ldrsbt r1, [r0], #4
ldrsht r1, [r0], r2
ldrsht r1, [r0], #4
ldrht r1, [r0], r2
ldrht r1, [r0], #4
strht r1, [r0], r2
strht r1, [r0], #4