mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-08 03:29:41 +00:00
Thumb2 pre/post indexed loads.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@74696 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
d0265aa00e
commit
e88d5cee9d
@ -102,6 +102,8 @@ public:
|
|||||||
SDValue &OffImm);
|
SDValue &OffImm);
|
||||||
bool SelectT2AddrModeImm8(SDValue Op, SDValue N, SDValue &Base,
|
bool SelectT2AddrModeImm8(SDValue Op, SDValue N, SDValue &Base,
|
||||||
SDValue &OffImm);
|
SDValue &OffImm);
|
||||||
|
bool SelectT2AddrModeImm8Offset(SDValue Op, SDValue N,
|
||||||
|
SDValue &OffImm);
|
||||||
bool SelectT2AddrModeImm8s4(SDValue Op, SDValue N, SDValue &Base,
|
bool SelectT2AddrModeImm8s4(SDValue Op, SDValue N, SDValue &Base,
|
||||||
SDValue &OffImm);
|
SDValue &OffImm);
|
||||||
bool SelectT2AddrModeSoReg(SDValue Op, SDValue N, SDValue &Base,
|
bool SelectT2AddrModeSoReg(SDValue Op, SDValue N, SDValue &Base,
|
||||||
@ -111,7 +113,11 @@ public:
|
|||||||
#include "ARMGenDAGISel.inc"
|
#include "ARMGenDAGISel.inc"
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// SelectARMIndexedLoad - Indexed (pre/post inc/dec) load matching code for
|
||||||
|
/// ARM.
|
||||||
SDNode *SelectARMIndexedLoad(SDValue Op);
|
SDNode *SelectARMIndexedLoad(SDValue Op);
|
||||||
|
SDNode *SelectT2IndexedLoad(SDValue Op);
|
||||||
|
|
||||||
|
|
||||||
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
||||||
/// inline asm expressions.
|
/// inline asm expressions.
|
||||||
@ -628,6 +634,25 @@ bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue Op, SDValue N,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDValue Op, SDValue N,
|
||||||
|
SDValue &OffImm){
|
||||||
|
unsigned Opcode = Op.getOpcode();
|
||||||
|
ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
|
||||||
|
? cast<LoadSDNode>(Op)->getAddressingMode()
|
||||||
|
: cast<StoreSDNode>(Op)->getAddressingMode();
|
||||||
|
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N)) {
|
||||||
|
int RHSC = (int)RHS->getZExtValue();
|
||||||
|
if (RHSC >= 0 && RHSC < 0x100) { // 8 bits.
|
||||||
|
OffImm = (AM == ISD::PRE_INC)
|
||||||
|
? CurDAG->getTargetConstant(RHSC, MVT::i32)
|
||||||
|
: CurDAG->getTargetConstant(-RHSC, MVT::i32);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool ARMDAGToDAGISel::SelectT2AddrModeImm8s4(SDValue Op, SDValue N,
|
bool ARMDAGToDAGISel::SelectT2AddrModeImm8s4(SDValue Op, SDValue N,
|
||||||
SDValue &Base, SDValue &OffImm) {
|
SDValue &Base, SDValue &OffImm) {
|
||||||
if (N.getOpcode() == ISD::ADD) {
|
if (N.getOpcode() == ISD::ADD) {
|
||||||
@ -762,6 +787,46 @@ SDNode *ARMDAGToDAGISel::SelectARMIndexedLoad(SDValue Op) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDNode *ARMDAGToDAGISel::SelectT2IndexedLoad(SDValue Op) {
|
||||||
|
LoadSDNode *LD = cast<LoadSDNode>(Op);
|
||||||
|
ISD::MemIndexedMode AM = LD->getAddressingMode();
|
||||||
|
if (AM == ISD::UNINDEXED)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
MVT LoadedVT = LD->getMemoryVT();
|
||||||
|
SDValue Offset;
|
||||||
|
bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
|
||||||
|
unsigned Opcode = 0;
|
||||||
|
bool Match = false;
|
||||||
|
if (SelectT2AddrModeImm8Offset(Op, LD->getOffset(), Offset)) {
|
||||||
|
switch (LoadedVT.getSimpleVT()) {
|
||||||
|
case MVT::i32:
|
||||||
|
Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST;
|
||||||
|
break;
|
||||||
|
case MVT::i16:
|
||||||
|
Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST;
|
||||||
|
break;
|
||||||
|
case MVT::i8:
|
||||||
|
Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Match = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Match) {
|
||||||
|
SDValue Chain = LD->getChain();
|
||||||
|
SDValue Base = LD->getBasePtr();
|
||||||
|
SDValue Ops[]= { Base, Offset, getAL(CurDAG),
|
||||||
|
CurDAG->getRegister(0, MVT::i32), Chain };
|
||||||
|
return CurDAG->getTargetNode(Opcode, Op.getDebugLoc(), MVT::i32, MVT::i32,
|
||||||
|
MVT::Other, Ops, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
||||||
SDNode *N = Op.getNode();
|
SDNode *N = Op.getNode();
|
||||||
@ -892,7 +957,11 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
|
|||||||
return CurDAG->getTargetNode(ARM::SMULL, dl, MVT::i32, MVT::i32, Ops, 5);
|
return CurDAG->getTargetNode(ARM::SMULL, dl, MVT::i32, MVT::i32, Ops, 5);
|
||||||
}
|
}
|
||||||
case ISD::LOAD: {
|
case ISD::LOAD: {
|
||||||
SDNode *ResNode = SelectARMIndexedLoad(Op);
|
SDNode *ResNode = 0;
|
||||||
|
if (Subtarget->isThumb2())
|
||||||
|
ResNode = SelectT2IndexedLoad(Op);
|
||||||
|
else
|
||||||
|
ResNode = SelectARMIndexedLoad(Op);
|
||||||
if (ResNode)
|
if (ResNode)
|
||||||
return ResNode;
|
return ResNode;
|
||||||
// Other cases are autogenerated.
|
// Other cases are autogenerated.
|
||||||
|
@ -231,16 +231,18 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
|
|||||||
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
|
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
|
||||||
|
|
||||||
// ARM supports all 4 flavors of integer indexed load / store.
|
// ARM supports all 4 flavors of integer indexed load / store.
|
||||||
for (unsigned im = (unsigned)ISD::PRE_INC;
|
if (!Subtarget->isThumb1Only()) {
|
||||||
im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) {
|
for (unsigned im = (unsigned)ISD::PRE_INC;
|
||||||
setIndexedLoadAction(im, MVT::i1, Legal);
|
im != (unsigned)ISD::LAST_INDEXED_MODE; ++im) {
|
||||||
setIndexedLoadAction(im, MVT::i8, Legal);
|
setIndexedLoadAction(im, MVT::i1, Legal);
|
||||||
setIndexedLoadAction(im, MVT::i16, Legal);
|
setIndexedLoadAction(im, MVT::i8, Legal);
|
||||||
setIndexedLoadAction(im, MVT::i32, Legal);
|
setIndexedLoadAction(im, MVT::i16, Legal);
|
||||||
setIndexedStoreAction(im, MVT::i1, Legal);
|
setIndexedLoadAction(im, MVT::i32, Legal);
|
||||||
setIndexedStoreAction(im, MVT::i8, Legal);
|
setIndexedStoreAction(im, MVT::i1, Legal);
|
||||||
setIndexedStoreAction(im, MVT::i16, Legal);
|
setIndexedStoreAction(im, MVT::i8, Legal);
|
||||||
setIndexedStoreAction(im, MVT::i32, Legal);
|
setIndexedStoreAction(im, MVT::i16, Legal);
|
||||||
|
setIndexedStoreAction(im, MVT::i32, Legal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// i64 operation support.
|
// i64 operation support.
|
||||||
@ -2923,10 +2925,10 @@ bool ARMTargetLowering::isLegalAddressingMode(const AddrMode &AM,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool getIndexedAddressParts(SDNode *Ptr, MVT VT,
|
static bool getARMIndexedAddressParts(SDNode *Ptr, MVT VT,
|
||||||
bool isSEXTLoad, SDValue &Base,
|
bool isSEXTLoad, SDValue &Base,
|
||||||
SDValue &Offset, bool &isInc,
|
SDValue &Offset, bool &isInc,
|
||||||
SelectionDAG &DAG) {
|
SelectionDAG &DAG) {
|
||||||
if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB)
|
if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -2936,6 +2938,7 @@ static bool getIndexedAddressParts(SDNode *Ptr, MVT VT,
|
|||||||
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) {
|
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) {
|
||||||
int RHSC = (int)RHS->getZExtValue();
|
int RHSC = (int)RHS->getZExtValue();
|
||||||
if (RHSC < 0 && RHSC > -256) {
|
if (RHSC < 0 && RHSC > -256) {
|
||||||
|
assert(Ptr->getOpcode() == ISD::ADD);
|
||||||
isInc = false;
|
isInc = false;
|
||||||
Offset = DAG.getConstant(-RHSC, RHS->getValueType(0));
|
Offset = DAG.getConstant(-RHSC, RHS->getValueType(0));
|
||||||
return true;
|
return true;
|
||||||
@ -2949,6 +2952,7 @@ static bool getIndexedAddressParts(SDNode *Ptr, MVT VT,
|
|||||||
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) {
|
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) {
|
||||||
int RHSC = (int)RHS->getZExtValue();
|
int RHSC = (int)RHS->getZExtValue();
|
||||||
if (RHSC < 0 && RHSC > -0x1000) {
|
if (RHSC < 0 && RHSC > -0x1000) {
|
||||||
|
assert(Ptr->getOpcode() == ISD::ADD);
|
||||||
isInc = false;
|
isInc = false;
|
||||||
Offset = DAG.getConstant(-RHSC, RHS->getValueType(0));
|
Offset = DAG.getConstant(-RHSC, RHS->getValueType(0));
|
||||||
Base = Ptr->getOperand(0);
|
Base = Ptr->getOperand(0);
|
||||||
@ -2979,6 +2983,31 @@ static bool getIndexedAddressParts(SDNode *Ptr, MVT VT,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool getT2IndexedAddressParts(SDNode *Ptr, MVT VT,
|
||||||
|
bool isSEXTLoad, SDValue &Base,
|
||||||
|
SDValue &Offset, bool &isInc,
|
||||||
|
SelectionDAG &DAG) {
|
||||||
|
if (Ptr->getOpcode() != ISD::ADD && Ptr->getOpcode() != ISD::SUB)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Base = Ptr->getOperand(0);
|
||||||
|
if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Ptr->getOperand(1))) {
|
||||||
|
int RHSC = (int)RHS->getZExtValue();
|
||||||
|
if (RHSC < 0 && RHSC > -0x100) { // 8 bits.
|
||||||
|
assert(Ptr->getOpcode() == ISD::ADD);
|
||||||
|
isInc = false;
|
||||||
|
Offset = DAG.getConstant(-RHSC, RHS->getValueType(0));
|
||||||
|
return true;
|
||||||
|
} else if (RHSC > 0 && RHSC < 0x100) { // 8 bit, no zero.
|
||||||
|
isInc = Ptr->getOpcode() == ISD::ADD;
|
||||||
|
Offset = DAG.getConstant(RHSC, RHS->getValueType(0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// getPreIndexedAddressParts - returns true by value, base pointer and
|
/// getPreIndexedAddressParts - returns true by value, base pointer and
|
||||||
/// offset pointer and addressing mode by reference if the node's address
|
/// offset pointer and addressing mode by reference if the node's address
|
||||||
/// can be legally represented as pre-indexed load / store address.
|
/// can be legally represented as pre-indexed load / store address.
|
||||||
@ -2987,7 +3016,7 @@ ARMTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base,
|
|||||||
SDValue &Offset,
|
SDValue &Offset,
|
||||||
ISD::MemIndexedMode &AM,
|
ISD::MemIndexedMode &AM,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
if (Subtarget->isThumb())
|
if (Subtarget->isThumb1Only())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MVT VT;
|
MVT VT;
|
||||||
@ -3004,13 +3033,18 @@ ARMTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool isInc;
|
bool isInc;
|
||||||
bool isLegal = getIndexedAddressParts(Ptr.getNode(), VT, isSEXTLoad, Base,
|
bool isLegal = false;
|
||||||
|
if (Subtarget->isThumb2())
|
||||||
|
isLegal = getT2IndexedAddressParts(Ptr.getNode(), VT, isSEXTLoad, Base,
|
||||||
|
Offset, isInc, DAG);
|
||||||
|
else
|
||||||
|
isLegal = getARMIndexedAddressParts(Ptr.getNode(), VT, isSEXTLoad, Base,
|
||||||
Offset, isInc, DAG);
|
Offset, isInc, DAG);
|
||||||
if (isLegal) {
|
if (!isLegal)
|
||||||
AM = isInc ? ISD::PRE_INC : ISD::PRE_DEC;
|
return false;
|
||||||
return true;
|
|
||||||
}
|
AM = isInc ? ISD::PRE_INC : ISD::PRE_DEC;
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getPostIndexedAddressParts - returns true by value, base pointer and
|
/// getPostIndexedAddressParts - returns true by value, base pointer and
|
||||||
@ -3021,7 +3055,7 @@ bool ARMTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
|
|||||||
SDValue &Offset,
|
SDValue &Offset,
|
||||||
ISD::MemIndexedMode &AM,
|
ISD::MemIndexedMode &AM,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
if (Subtarget->isThumb())
|
if (Subtarget->isThumb1Only())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MVT VT;
|
MVT VT;
|
||||||
@ -3036,13 +3070,18 @@ bool ARMTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool isInc;
|
bool isInc;
|
||||||
bool isLegal = getIndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset,
|
bool isLegal = false;
|
||||||
|
if (Subtarget->isThumb2())
|
||||||
|
isLegal = getT2IndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset,
|
||||||
isInc, DAG);
|
isInc, DAG);
|
||||||
if (isLegal) {
|
else
|
||||||
AM = isInc ? ISD::POST_INC : ISD::POST_DEC;
|
isLegal = getARMIndexedAddressParts(Op, VT, isSEXTLoad, Base, Offset,
|
||||||
return true;
|
isInc, DAG);
|
||||||
}
|
if (!isLegal)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
AM = isInc ? ISD::POST_INC : ISD::POST_DEC;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op,
|
void ARMTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op,
|
||||||
|
@ -873,6 +873,18 @@ class T2XI<dag oops, dag iops, string asm, list<dag> pattern>
|
|||||||
class T2JTI<dag oops, dag iops, string asm, list<dag> pattern>
|
class T2JTI<dag oops, dag iops, string asm, list<dag> pattern>
|
||||||
: Thumb2XI<oops, iops, AddrModeNone, SizeSpecial, asm, "", pattern>;
|
: Thumb2XI<oops, iops, AddrModeNone, SizeSpecial, asm, "", pattern>;
|
||||||
|
|
||||||
|
// T2Iidxldst - Thumb2 indexed load / store instructions.
|
||||||
|
class T2Iidxldst<dag oops, dag iops, AddrMode am, IndexMode im,
|
||||||
|
string opc, string asm, string cstr, list<dag> pattern>
|
||||||
|
: InstARM<am, Size4Bytes, im, ThumbFrm, cstr> {
|
||||||
|
let OutOperandList = oops;
|
||||||
|
let InOperandList = !con(iops, (ops pred:$p));
|
||||||
|
let AsmString = !strconcat(opc, !strconcat("${p}", asm));
|
||||||
|
let Pattern = pattern;
|
||||||
|
list<Predicate> Predicates = [IsThumb2];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// T2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode.
|
// T2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode.
|
||||||
class T2Pat<dag pattern, dag result> : Pat<pattern, result> {
|
class T2Pat<dag pattern, dag result> : Pat<pattern, result> {
|
||||||
list<Predicate> Predicates = [IsThumb2];
|
list<Predicate> Predicates = [IsThumb2];
|
||||||
|
@ -89,7 +89,6 @@ def imm0_65535 : PatLeaf<(i32 imm), [{
|
|||||||
return (uint32_t)N->getZExtValue() < 65536;
|
return (uint32_t)N->getZExtValue() < 65536;
|
||||||
}]>;
|
}]>;
|
||||||
|
|
||||||
|
|
||||||
/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
|
/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
|
||||||
/// e.g., 0xf000ffff
|
/// e.g., 0xf000ffff
|
||||||
def bf_inv_mask_imm : Operand<i32>,
|
def bf_inv_mask_imm : Operand<i32>,
|
||||||
@ -136,13 +135,17 @@ def t2addrmode_imm12 : Operand<i32>,
|
|||||||
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
|
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// t2addrmode_imm8 := reg - imm8 (also reg + imm8 for some instructions)
|
// t2addrmode_imm8 := reg - imm8
|
||||||
def t2addrmode_imm8 : Operand<i32>,
|
def t2addrmode_imm8 : Operand<i32>,
|
||||||
ComplexPattern<i32, 2, "SelectT2AddrModeImm8", []> {
|
ComplexPattern<i32, 2, "SelectT2AddrModeImm8", []> {
|
||||||
let PrintMethod = "printT2AddrModeImm8Operand";
|
let PrintMethod = "printT2AddrModeImm8Operand";
|
||||||
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
|
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def t2am_imm8_offset : Operand<i32> {
|
||||||
|
let PrintMethod = "printT2AddrModeImm8OffsetOperand";
|
||||||
|
}
|
||||||
|
|
||||||
// t2addrmode_imm8s4 := reg + (imm8 << 2)
|
// t2addrmode_imm8s4 := reg + (imm8 << 2)
|
||||||
def t2addrmode_imm8s4 : Operand<i32>,
|
def t2addrmode_imm8s4 : Operand<i32>,
|
||||||
ComplexPattern<i32, 2, "SelectT2AddrModeImm8s4", []> {
|
ComplexPattern<i32, 2, "SelectT2AddrModeImm8s4", []> {
|
||||||
@ -541,10 +544,45 @@ def : T2Pat<(extloadi16 t2addrmode_so_reg:$addr),
|
|||||||
def : T2Pat<(extloadi16 (ARMWrapper tconstpool:$addr)),
|
def : T2Pat<(extloadi16 (ARMWrapper tconstpool:$addr)),
|
||||||
(t2LDRHpci tconstpool:$addr)>;
|
(t2LDRHpci tconstpool:$addr)>;
|
||||||
|
|
||||||
|
// Indexed loads
|
||||||
|
def t2LDR_PRE : T2Iidxldst<(outs GPR:$dst, GPR:$base_wb),
|
||||||
|
(ins t2addrmode_imm8:$addr),
|
||||||
|
AddrModeT2_i8, IndexModePre,
|
||||||
|
"ldr", " $dst, $addr!", "$addr.base = $base_wb",
|
||||||
|
[]>;
|
||||||
|
|
||||||
|
def t2LDR_POST : T2Iidxldst<(outs GPR:$dst, GPR:$base_wb),
|
||||||
|
(ins GPR:$base, t2am_imm8_offset:$offset),
|
||||||
|
AddrModeT2_i8, IndexModePost,
|
||||||
|
"ldr", " $dst, [$base], $offset", "$base = $base_wb",
|
||||||
|
[]>;
|
||||||
|
|
||||||
|
def t2LDRB_PRE : T2Iidxldst<(outs GPR:$dst, GPR:$base_wb),
|
||||||
|
(ins t2addrmode_imm8:$addr),
|
||||||
|
AddrModeT2_i8, IndexModePre,
|
||||||
|
"ldrb", " $dst, $addr!", "$addr.base = $base_wb",
|
||||||
|
[]>;
|
||||||
|
def t2LDRB_POST : T2Iidxldst<(outs GPR:$dst, GPR:$base_wb),
|
||||||
|
(ins GPR:$base, t2am_imm8_offset:$offset),
|
||||||
|
AddrModeT2_i8, IndexModePost,
|
||||||
|
"ldrb", " $dst, [$base], $offset", "$base = $base_wb",
|
||||||
|
[]>;
|
||||||
|
|
||||||
|
def t2LDRH_PRE : T2Iidxldst<(outs GPR:$dst, GPR:$base_wb),
|
||||||
|
(ins t2addrmode_imm8:$addr),
|
||||||
|
AddrModeT2_i8, IndexModePre,
|
||||||
|
"ldrh", " $dst, $addr!", "$addr.base = $base_wb",
|
||||||
|
[]>;
|
||||||
|
def t2LDRH_POST : T2Iidxldst<(outs GPR:$dst, GPR:$base_wb),
|
||||||
|
(ins GPR:$base, t2am_imm8_offset:$offset),
|
||||||
|
AddrModeT2_i8, IndexModePost,
|
||||||
|
"ldrh", " $dst, [$base], $offset", "$base = $base_wb",
|
||||||
|
[]>;
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
defm t2STR : T2I_st<"str", BinOpFrag<(store node:$LHS, node:$RHS)>>;
|
defm t2STR : T2I_st<"str", BinOpFrag<(store node:$LHS, node:$RHS)>>;
|
||||||
defm t2STRB : T2I_st<"strb", BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>;
|
defm t2STRB : T2I_st<"strb", BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>;
|
||||||
defm t2STRH : T2I_st<"strh", BinOpFrag<(truncstorei16 node:$LHS, node:$RHS)>>;
|
defm t2STRH : T2I_st<"strh", BinOpFrag<(truncstorei16 node:$LHS, node:$RHS)>>;
|
||||||
|
|
||||||
// Store doubleword
|
// Store doubleword
|
||||||
let mayLoad = 1 in
|
let mayLoad = 1 in
|
||||||
|
@ -122,6 +122,7 @@ namespace {
|
|||||||
void printT2SOOperand(const MachineInstr *MI, int OpNum);
|
void printT2SOOperand(const MachineInstr *MI, int OpNum);
|
||||||
void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum);
|
void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum);
|
||||||
void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum);
|
void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum);
|
||||||
|
void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum);
|
||||||
void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum);
|
void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum);
|
||||||
|
|
||||||
void printPredicateOperand(const MachineInstr *MI, int OpNum);
|
void printPredicateOperand(const MachineInstr *MI, int OpNum);
|
||||||
@ -747,6 +748,17 @@ void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI,
|
|||||||
O << "]";
|
O << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI,
|
||||||
|
int OpNum) {
|
||||||
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
||||||
|
int32_t OffImm = (int32_t)MO1.getImm();
|
||||||
|
// Don't print +0.
|
||||||
|
if (OffImm < 0)
|
||||||
|
O << "#-" << -OffImm;
|
||||||
|
else if (OffImm > 0)
|
||||||
|
O << "#+" << OffImm;
|
||||||
|
}
|
||||||
|
|
||||||
void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI,
|
void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI,
|
||||||
int OpNum) {
|
int OpNum) {
|
||||||
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
const MachineOperand &MO1 = MI->getOperand(OpNum);
|
||||||
|
12
test/CodeGen/Thumb2/thumb2-ldr_post.ll
Normal file
12
test/CodeGen/Thumb2/thumb2-ldr_post.ll
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | \
|
||||||
|
; RUN: grep {ldr.*\\\[.*\],} | count 1
|
||||||
|
|
||||||
|
define i32 @test(i32 %a, i32 %b, i32 %c) {
|
||||||
|
%tmp1 = mul i32 %a, %b ; <i32> [#uses=2]
|
||||||
|
%tmp2 = inttoptr i32 %tmp1 to i32* ; <i32*> [#uses=1]
|
||||||
|
%tmp3 = load i32* %tmp2 ; <i32> [#uses=1]
|
||||||
|
%tmp4 = sub i32 %tmp1, 8 ; <i32> [#uses=1]
|
||||||
|
%tmp5 = mul i32 %tmp4, %tmp3 ; <i32> [#uses=1]
|
||||||
|
ret i32 %tmp5
|
||||||
|
}
|
||||||
|
|
19
test/CodeGen/Thumb2/thumb2-ldr_pre.ll
Normal file
19
test/CodeGen/Thumb2/thumb2-ldr_pre.ll
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | \
|
||||||
|
; RUN: grep {ldr.*\\!} | count 2
|
||||||
|
|
||||||
|
define i32* @test1(i32* %X, i32* %dest) {
|
||||||
|
%Y = getelementptr i32* %X, i32 4 ; <i32*> [#uses=2]
|
||||||
|
%A = load i32* %Y ; <i32> [#uses=1]
|
||||||
|
store i32 %A, i32* %dest
|
||||||
|
ret i32* %Y
|
||||||
|
}
|
||||||
|
|
||||||
|
define i32 @test2(i32 %a, i32 %b) {
|
||||||
|
%tmp1 = sub i32 %a, 64 ; <i32> [#uses=2]
|
||||||
|
%tmp2 = inttoptr i32 %tmp1 to i32* ; <i32*> [#uses=1]
|
||||||
|
%tmp3 = load i32* %tmp2 ; <i32> [#uses=1]
|
||||||
|
%tmp4 = sub i32 %tmp1, %b ; <i32> [#uses=1]
|
||||||
|
%tmp5 = add i32 %tmp4, %tmp3 ; <i32> [#uses=1]
|
||||||
|
ret i32 %tmp5
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user