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:
Evan Cheng 2009-07-02 07:28:31 +00:00
parent d0265aa00e
commit e88d5cee9d
7 changed files with 235 additions and 34 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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];

View File

@ -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

View File

@ -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);

View 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
}

View 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
}