[llvm] r244882 - [ARM] Reorganise and simplify thumb-1 load/store selection
John Brawn via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 13 03:48:23 PDT 2015
Author: john.brawn
Date: Thu Aug 13 05:48:22 2015
New Revision: 244882
URL: http://llvm.org/viewvc/llvm-project?rev=244882&view=rev
Log:
[ARM] Reorganise and simplify thumb-1 load/store selection
Other than PC-relative loads/store the patterns that match the various
load/store addressing modes have the same complexity, so the order that they
are matched is the order that they appear in the .td file.
Rearrange the instruction definitions in ARMInstrThumb.td, and make use of
AddedComplexity for PC-relative loads, so that the instruction matching order
is the order that results in the simplest selection logic. This also makes
register-offset load/store be selected when it should, as previously it was
only selected for too-large immediate offsets.
Differential Revision: http://reviews.llvm.org/D11800
Modified:
llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
llvm/trunk/lib/Target/ARM/ARMInstrThumb.td
llvm/trunk/test/CodeGen/ARM/load.ll
Modified: llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp?rev=244882&r1=244881&r2=244882&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp Thu Aug 13 05:48:22 2015
@@ -160,11 +160,6 @@ public:
// Thumb Addressing Modes:
bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset);
- bool SelectThumbAddrModeRI(SDValue N, SDValue &Base, SDValue &Offset,
- unsigned Scale);
- bool SelectThumbAddrModeRI5S1(SDValue N, SDValue &Base, SDValue &Offset);
- bool SelectThumbAddrModeRI5S2(SDValue N, SDValue &Base, SDValue &Offset);
- bool SelectThumbAddrModeRI5S4(SDValue N, SDValue &Base, SDValue &Offset);
bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base,
SDValue &OffImm);
bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
@@ -1086,77 +1081,13 @@ bool ARMDAGToDAGISel::SelectThumbAddrMod
}
bool
-ARMDAGToDAGISel::SelectThumbAddrModeRI(SDValue N, SDValue &Base,
- SDValue &Offset, unsigned Scale) {
- if (Scale == 4) {
- SDValue TmpBase, TmpOffImm;
- if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm))
- return false; // We want to select tLDRspi / tSTRspi instead.
-
- if (N.getOpcode() == ARMISD::Wrapper &&
- N.getOperand(0).getOpcode() == ISD::TargetConstantPool)
- return false; // We want to select tLDRpci instead.
- }
-
- if (!CurDAG->isBaseWithConstantOffset(N))
- return false;
-
- // Thumb does not have [sp, r] address mode.
- RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0));
- RegisterSDNode *RHSR = dyn_cast<RegisterSDNode>(N.getOperand(1));
- if ((LHSR && LHSR->getReg() == ARM::SP) ||
- (RHSR && RHSR->getReg() == ARM::SP))
- return false;
-
- // FIXME: Why do we explicitly check for a match here and then return false?
- // Presumably to allow something else to match, but shouldn't this be
- // documented?
- int RHSC;
- if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC))
- return false;
-
- Base = N.getOperand(0);
- Offset = N.getOperand(1);
- return true;
-}
-
-bool
-ARMDAGToDAGISel::SelectThumbAddrModeRI5S1(SDValue N,
- SDValue &Base,
- SDValue &Offset) {
- return SelectThumbAddrModeRI(N, Base, Offset, 1);
-}
-
-bool
-ARMDAGToDAGISel::SelectThumbAddrModeRI5S2(SDValue N,
- SDValue &Base,
- SDValue &Offset) {
- return SelectThumbAddrModeRI(N, Base, Offset, 2);
-}
-
-bool
-ARMDAGToDAGISel::SelectThumbAddrModeRI5S4(SDValue N,
- SDValue &Base,
- SDValue &Offset) {
- return SelectThumbAddrModeRI(N, Base, Offset, 4);
-}
-
-bool
ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale,
SDValue &Base, SDValue &OffImm) {
- if (Scale == 4) {
- SDValue TmpBase, TmpOffImm;
- if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm))
- return false; // We want to select tLDRspi / tSTRspi instead.
-
- if (N.getOpcode() == ARMISD::Wrapper &&
- N.getOperand(0).getOpcode() == ISD::TargetConstantPool)
- return false; // We want to select tLDRpci instead.
- }
-
if (!CurDAG->isBaseWithConstantOffset(N)) {
- if (N.getOpcode() == ARMISD::Wrapper &&
- N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress) {
+ if (N.getOpcode() == ISD::ADD) {
+ return false; // We want to select register offset instead
+ } else if (N.getOpcode() == ARMISD::Wrapper &&
+ N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress) {
Base = N.getOperand(0);
} else {
Base = N;
@@ -1166,23 +1097,6 @@ ARMDAGToDAGISel::SelectThumbAddrModeImm5
return true;
}
- RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0));
- RegisterSDNode *RHSR = dyn_cast<RegisterSDNode>(N.getOperand(1));
- if ((LHSR && LHSR->getReg() == ARM::SP) ||
- (RHSR && RHSR->getReg() == ARM::SP)) {
- ConstantSDNode *LHS = dyn_cast<ConstantSDNode>(N.getOperand(0));
- ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
- unsigned LHSC = LHS ? LHS->getZExtValue() : 0;
- unsigned RHSC = RHS ? RHS->getZExtValue() : 0;
-
- // Thumb does not have [sp, #imm5] address mode for non-zero imm5.
- if (LHSC != 0 || RHSC != 0) return false;
-
- Base = N;
- OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
- return true;
- }
-
// If the RHS is + imm5 * scale, fold into addr mode.
int RHSC;
if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) {
@@ -1191,9 +1105,8 @@ ARMDAGToDAGISel::SelectThumbAddrModeImm5
return true;
}
- Base = N.getOperand(0);
- OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
- return true;
+ // Offset is too large, so use register offset instead.
+ return false;
}
bool
Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb.td?rev=244882&r1=244881&r2=244882&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrThumb.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrThumb.td Thu Aug 13 05:48:22 2015
@@ -591,6 +591,34 @@ def tTRAP : TI<(outs), (ins), IIC_Br,
// Load Store Instructions.
//
+// PC-relative loads need to be matched first as constant pool accesses need to
+// always be PC-relative. We do this using AddedComplexity, as the pattern is
+// simpler than the patterns of the other load instructions.
+let canFoldAsLoad = 1, isReMaterializable = 1, AddedComplexity = 10 in
+def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
+ "ldr", "\t$Rt, $addr",
+ [(set tGPR:$Rt, (load (ARMWrapper tconstpool:$addr)))]>,
+ T1Encoding<{0,1,0,0,1,?}> {
+ // A6.2 & A8.6.59
+ bits<3> Rt;
+ bits<8> addr;
+ let Inst{10-8} = Rt;
+ let Inst{7-0} = addr;
+}
+
+// SP-relative loads should be matched before standard immediate-offset loads as
+// it means we avoid having to move SP to another register.
+let canFoldAsLoad = 1 in
+def tLDRspi : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_sp:$addr), IIC_iLoad_i,
+ "ldr", "\t$Rt, $addr",
+ [(set tGPR:$Rt, (load t_addrmode_sp:$addr))]>,
+ T1LdStSP<{1,?,?}> {
+ bits<3> Rt;
+ bits<8> addr;
+ let Inst{10-8} = Rt;
+ let Inst{7-0} = addr;
+}
+
// Loads: reg/reg and reg/imm5
let canFoldAsLoad = 1, isReMaterializable = 1 in
multiclass thumb_ld_rr_ri_enc<bits<3> reg_opc, bits<4> imm_opc,
@@ -598,16 +626,20 @@ multiclass thumb_ld_rr_ri_enc<bits<3> re
AddrMode am, InstrItinClass itin_r,
InstrItinClass itin_i, string asm,
PatFrag opnode> {
- def r : // reg/reg
- T1pILdStEncode<reg_opc,
- (outs tGPR:$Rt), (ins AddrMode_r:$addr),
- am, itin_r, asm, "\t$Rt, $addr",
- [(set tGPR:$Rt, (opnode AddrMode_r:$addr))]>;
+ // Immediate-offset loads should be matched before register-offset loads as
+ // when the offset is a constant it's simpler to first check if it fits in the
+ // immediate offset field then fall back to register-offset if it doesn't.
def i : // reg/imm5
T1pILdStEncodeImm<imm_opc, 1 /* Load */,
(outs tGPR:$Rt), (ins AddrMode_i:$addr),
am, itin_i, asm, "\t$Rt, $addr",
[(set tGPR:$Rt, (opnode AddrMode_i:$addr))]>;
+ // Register-offset loads are matched last.
+ def r : // reg/reg
+ T1pILdStEncode<reg_opc,
+ (outs tGPR:$Rt), (ins AddrMode_r:$addr),
+ am, itin_r, asm, "\t$Rt, $addr",
+ [(set tGPR:$Rt, (opnode AddrMode_r:$addr))]>;
}
// Stores: reg/reg and reg/imm5
multiclass thumb_st_rr_ri_enc<bits<3> reg_opc, bits<4> imm_opc,
@@ -615,32 +647,32 @@ multiclass thumb_st_rr_ri_enc<bits<3> re
AddrMode am, InstrItinClass itin_r,
InstrItinClass itin_i, string asm,
PatFrag opnode> {
- def r : // reg/reg
- T1pILdStEncode<reg_opc,
- (outs), (ins tGPR:$Rt, AddrMode_r:$addr),
- am, itin_r, asm, "\t$Rt, $addr",
- [(opnode tGPR:$Rt, AddrMode_r:$addr)]>;
def i : // reg/imm5
T1pILdStEncodeImm<imm_opc, 0 /* Store */,
(outs), (ins tGPR:$Rt, AddrMode_i:$addr),
am, itin_i, asm, "\t$Rt, $addr",
[(opnode tGPR:$Rt, AddrMode_i:$addr)]>;
+ def r : // reg/reg
+ T1pILdStEncode<reg_opc,
+ (outs), (ins tGPR:$Rt, AddrMode_r:$addr),
+ am, itin_r, asm, "\t$Rt, $addr",
+ [(opnode tGPR:$Rt, AddrMode_r:$addr)]>;
}
// A8.6.57 & A8.6.60
-defm tLDR : thumb_ld_rr_ri_enc<0b100, 0b0110, t_addrmode_rrs4,
+defm tLDR : thumb_ld_rr_ri_enc<0b100, 0b0110, t_addrmode_rr,
t_addrmode_is4, AddrModeT1_4,
IIC_iLoad_r, IIC_iLoad_i, "ldr",
UnOpFrag<(load node:$Src)>>;
// A8.6.64 & A8.6.61
-defm tLDRB : thumb_ld_rr_ri_enc<0b110, 0b0111, t_addrmode_rrs1,
+defm tLDRB : thumb_ld_rr_ri_enc<0b110, 0b0111, t_addrmode_rr,
t_addrmode_is1, AddrModeT1_1,
IIC_iLoad_bh_r, IIC_iLoad_bh_i, "ldrb",
UnOpFrag<(zextloadi8 node:$Src)>>;
// A8.6.76 & A8.6.73
-defm tLDRH : thumb_ld_rr_ri_enc<0b101, 0b1000, t_addrmode_rrs2,
+defm tLDRH : thumb_ld_rr_ri_enc<0b101, 0b1000, t_addrmode_rr,
t_addrmode_is2, AddrModeT1_2,
IIC_iLoad_bh_r, IIC_iLoad_bh_i, "ldrh",
UnOpFrag<(zextloadi16 node:$Src)>>;
@@ -659,58 +691,36 @@ def tLDRSH : // A8.6.
"ldrsh", "\t$Rt, $addr",
[(set tGPR:$Rt, (sextloadi16 t_addrmode_rr:$addr))]>;
-let canFoldAsLoad = 1 in
-def tLDRspi : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_sp:$addr), IIC_iLoad_i,
- "ldr", "\t$Rt, $addr",
- [(set tGPR:$Rt, (load t_addrmode_sp:$addr))]>,
- T1LdStSP<{1,?,?}> {
- bits<3> Rt;
- bits<8> addr;
- let Inst{10-8} = Rt;
- let Inst{7-0} = addr;
-}
-let canFoldAsLoad = 1, isReMaterializable = 1 in
-def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
- "ldr", "\t$Rt, $addr",
- [(set tGPR:$Rt, (load (ARMWrapper tconstpool:$addr)))]>,
- T1Encoding<{0,1,0,0,1,?}> {
- // A6.2 & A8.6.59
+def tSTRspi : T1pIs<(outs), (ins tGPR:$Rt, t_addrmode_sp:$addr), IIC_iStore_i,
+ "str", "\t$Rt, $addr",
+ [(store tGPR:$Rt, t_addrmode_sp:$addr)]>,
+ T1LdStSP<{0,?,?}> {
bits<3> Rt;
bits<8> addr;
let Inst{10-8} = Rt;
- let Inst{7-0} = addr;
+ let Inst{7-0} = addr;
}
// A8.6.194 & A8.6.192
-defm tSTR : thumb_st_rr_ri_enc<0b000, 0b0110, t_addrmode_rrs4,
+defm tSTR : thumb_st_rr_ri_enc<0b000, 0b0110, t_addrmode_rr,
t_addrmode_is4, AddrModeT1_4,
IIC_iStore_r, IIC_iStore_i, "str",
BinOpFrag<(store node:$LHS, node:$RHS)>>;
// A8.6.197 & A8.6.195
-defm tSTRB : thumb_st_rr_ri_enc<0b010, 0b0111, t_addrmode_rrs1,
+defm tSTRB : thumb_st_rr_ri_enc<0b010, 0b0111, t_addrmode_rr,
t_addrmode_is1, AddrModeT1_1,
IIC_iStore_bh_r, IIC_iStore_bh_i, "strb",
BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>;
// A8.6.207 & A8.6.205
-defm tSTRH : thumb_st_rr_ri_enc<0b001, 0b1000, t_addrmode_rrs2,
+defm tSTRH : thumb_st_rr_ri_enc<0b001, 0b1000, t_addrmode_rr,
t_addrmode_is2, AddrModeT1_2,
IIC_iStore_bh_r, IIC_iStore_bh_i, "strh",
BinOpFrag<(truncstorei16 node:$LHS, node:$RHS)>>;
-def tSTRspi : T1pIs<(outs), (ins tGPR:$Rt, t_addrmode_sp:$addr), IIC_iStore_i,
- "str", "\t$Rt, $addr",
- [(store tGPR:$Rt, t_addrmode_sp:$addr)]>,
- T1LdStSP<{0,?,?}> {
- bits<3> Rt;
- bits<8> addr;
- let Inst{10-8} = Rt;
- let Inst{7-0} = addr;
-}
-
//===----------------------------------------------------------------------===//
// Load / store multiple Instructions.
//
@@ -1328,16 +1338,16 @@ def : T1Pat<(subc tGPR:$lhs, tGPR:$rhs
(tSUBrr tGPR:$lhs, tGPR:$rhs)>;
// Bswap 16 with load/store
-def : T1Pat<(srl (bswap (extloadi16 t_addrmode_rrs2:$addr)), (i32 16)),
- (tREV16 (tLDRHr t_addrmode_rrs2:$addr))>;
def : T1Pat<(srl (bswap (extloadi16 t_addrmode_is2:$addr)), (i32 16)),
(tREV16 (tLDRHi t_addrmode_is2:$addr))>;
-def : T1Pat<(truncstorei16 (srl (bswap tGPR:$Rn), (i32 16)),
- t_addrmode_rrs2:$addr),
- (tSTRHr (tREV16 tGPR:$Rn), t_addrmode_rrs2:$addr)>;
+def : T1Pat<(srl (bswap (extloadi16 t_addrmode_rr:$addr)), (i32 16)),
+ (tREV16 (tLDRHr t_addrmode_rr:$addr))>;
def : T1Pat<(truncstorei16 (srl (bswap tGPR:$Rn), (i32 16)),
t_addrmode_is2:$addr),
(tSTRHi(tREV16 tGPR:$Rn), t_addrmode_is2:$addr)>;
+def : T1Pat<(truncstorei16 (srl (bswap tGPR:$Rn), (i32 16)),
+ t_addrmode_rr:$addr),
+ (tSTRHr (tREV16 tGPR:$Rn), t_addrmode_rr:$addr)>;
// ConstantPool
def : T1Pat<(ARMWrapper tconstpool :$dst), (tLEApcrel tconstpool :$dst)>;
@@ -1372,10 +1382,10 @@ def : Tv5Pat<(ARMcall GPR:$dst), (tBLXr
Requires<[IsThumb, HasV5T]>;
// zextload i1 -> zextload i8
-def : T1Pat<(zextloadi1 t_addrmode_rrs1:$addr),
- (tLDRBr t_addrmode_rrs1:$addr)>;
def : T1Pat<(zextloadi1 t_addrmode_is1:$addr),
(tLDRBi t_addrmode_is1:$addr)>;
+def : T1Pat<(zextloadi1 t_addrmode_rr:$addr),
+ (tLDRBr t_addrmode_rr:$addr)>;
// extload from the stack -> word load from the stack, as it avoids having to
// materialize the base in a separate register. This only works when a word
@@ -1389,61 +1399,61 @@ def : T1Pat<(extloadi16 t_addrmode_sp:$a
Requires<[IsThumb, IsThumb1Only, IsLE]>;
// extload -> zextload
-def : T1Pat<(extloadi1 t_addrmode_rrs1:$addr), (tLDRBr t_addrmode_rrs1:$addr)>;
-def : T1Pat<(extloadi1 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
-def : T1Pat<(extloadi8 t_addrmode_rrs1:$addr), (tLDRBr t_addrmode_rrs1:$addr)>;
-def : T1Pat<(extloadi8 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
-def : T1Pat<(extloadi16 t_addrmode_rrs2:$addr), (tLDRHr t_addrmode_rrs2:$addr)>;
-def : T1Pat<(extloadi16 t_addrmode_is2:$addr), (tLDRHi t_addrmode_is2:$addr)>;
+def : T1Pat<(extloadi1 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
+def : T1Pat<(extloadi1 t_addrmode_rr:$addr), (tLDRBr t_addrmode_rr:$addr)>;
+def : T1Pat<(extloadi8 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
+def : T1Pat<(extloadi8 t_addrmode_rr:$addr), (tLDRBr t_addrmode_rr:$addr)>;
+def : T1Pat<(extloadi16 t_addrmode_is2:$addr), (tLDRHi t_addrmode_is2:$addr)>;
+def : T1Pat<(extloadi16 t_addrmode_rr:$addr), (tLDRHr t_addrmode_rr:$addr)>;
// If it's impossible to use [r,r] address mode for sextload, select to
// ldr{b|h} + sxt{b|h} instead.
def : T1Pat<(sextloadi8 t_addrmode_is1:$addr),
(tSXTB (tLDRBi t_addrmode_is1:$addr))>,
Requires<[IsThumb, IsThumb1Only, HasV6]>;
-def : T1Pat<(sextloadi8 t_addrmode_rrs1:$addr),
- (tSXTB (tLDRBr t_addrmode_rrs1:$addr))>,
+def : T1Pat<(sextloadi8 t_addrmode_rr:$addr),
+ (tSXTB (tLDRBr t_addrmode_rr:$addr))>,
Requires<[IsThumb, IsThumb1Only, HasV6]>;
def : T1Pat<(sextloadi16 t_addrmode_is2:$addr),
(tSXTH (tLDRHi t_addrmode_is2:$addr))>,
Requires<[IsThumb, IsThumb1Only, HasV6]>;
-def : T1Pat<(sextloadi16 t_addrmode_rrs2:$addr),
- (tSXTH (tLDRHr t_addrmode_rrs2:$addr))>,
+def : T1Pat<(sextloadi16 t_addrmode_rr:$addr),
+ (tSXTH (tLDRHr t_addrmode_rr:$addr))>,
Requires<[IsThumb, IsThumb1Only, HasV6]>;
-def : T1Pat<(sextloadi8 t_addrmode_rrs1:$addr),
- (tASRri (tLSLri (tLDRBr t_addrmode_rrs1:$addr), 24), 24)>;
def : T1Pat<(sextloadi8 t_addrmode_is1:$addr),
(tASRri (tLSLri (tLDRBi t_addrmode_is1:$addr), 24), 24)>;
-def : T1Pat<(sextloadi16 t_addrmode_rrs2:$addr),
- (tASRri (tLSLri (tLDRHr t_addrmode_rrs2:$addr), 16), 16)>;
+def : T1Pat<(sextloadi8 t_addrmode_rr:$addr),
+ (tASRri (tLSLri (tLDRBr t_addrmode_rr:$addr), 24), 24)>;
def : T1Pat<(sextloadi16 t_addrmode_is2:$addr),
(tASRri (tLSLri (tLDRHi t_addrmode_is2:$addr), 16), 16)>;
+def : T1Pat<(sextloadi16 t_addrmode_rr:$addr),
+ (tASRri (tLSLri (tLDRHr t_addrmode_rr:$addr), 16), 16)>;
def : T1Pat<(atomic_load_8 t_addrmode_is1:$src),
(tLDRBi t_addrmode_is1:$src)>;
-def : T1Pat<(atomic_load_8 t_addrmode_rrs1:$src),
- (tLDRBr t_addrmode_rrs1:$src)>;
+def : T1Pat<(atomic_load_8 t_addrmode_rr:$src),
+ (tLDRBr t_addrmode_rr:$src)>;
def : T1Pat<(atomic_load_16 t_addrmode_is2:$src),
(tLDRHi t_addrmode_is2:$src)>;
-def : T1Pat<(atomic_load_16 t_addrmode_rrs2:$src),
- (tLDRHr t_addrmode_rrs2:$src)>;
+def : T1Pat<(atomic_load_16 t_addrmode_rr:$src),
+ (tLDRHr t_addrmode_rr:$src)>;
def : T1Pat<(atomic_load_32 t_addrmode_is4:$src),
(tLDRi t_addrmode_is4:$src)>;
-def : T1Pat<(atomic_load_32 t_addrmode_rrs4:$src),
- (tLDRr t_addrmode_rrs4:$src)>;
+def : T1Pat<(atomic_load_32 t_addrmode_rr:$src),
+ (tLDRr t_addrmode_rr:$src)>;
def : T1Pat<(atomic_store_8 t_addrmode_is1:$ptr, tGPR:$val),
(tSTRBi tGPR:$val, t_addrmode_is1:$ptr)>;
-def : T1Pat<(atomic_store_8 t_addrmode_rrs1:$ptr, tGPR:$val),
- (tSTRBr tGPR:$val, t_addrmode_rrs1:$ptr)>;
+def : T1Pat<(atomic_store_8 t_addrmode_rr:$ptr, tGPR:$val),
+ (tSTRBr tGPR:$val, t_addrmode_rr:$ptr)>;
def : T1Pat<(atomic_store_16 t_addrmode_is2:$ptr, tGPR:$val),
(tSTRHi tGPR:$val, t_addrmode_is2:$ptr)>;
-def : T1Pat<(atomic_store_16 t_addrmode_rrs2:$ptr, tGPR:$val),
- (tSTRHr tGPR:$val, t_addrmode_rrs2:$ptr)>;
+def : T1Pat<(atomic_store_16 t_addrmode_rr:$ptr, tGPR:$val),
+ (tSTRHr tGPR:$val, t_addrmode_rr:$ptr)>;
def : T1Pat<(atomic_store_32 t_addrmode_is4:$ptr, tGPR:$val),
(tSTRi tGPR:$val, t_addrmode_is4:$ptr)>;
-def : T1Pat<(atomic_store_32 t_addrmode_rrs4:$ptr, tGPR:$val),
- (tSTRr tGPR:$val, t_addrmode_rrs4:$ptr)>;
+def : T1Pat<(atomic_store_32 t_addrmode_rr:$ptr, tGPR:$val),
+ (tSTRr tGPR:$val, t_addrmode_rr:$ptr)>;
// Large immediate handling.
Modified: llvm/trunk/test/CodeGen/ARM/load.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/load.ll?rev=244882&r1=244881&r2=244882&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/load.ll (original)
+++ llvm/trunk/test/CodeGen/ARM/load.ll Thu Aug 13 05:48:22 2015
@@ -1,35 +1,564 @@
-; RUN: llc -mtriple=arm-eabi %s -o - | FileCheck %s
+; RUN: llc -mtriple=thumbv6m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T1
+; RUN: llc -mtriple=thumbv7m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T2
-define i32 @f1(i8* %p) {
+
+; Register offset
+
+; CHECK-LABEL: ldrsb_rr
+; CHECK: ldrsb r0, [r0, r1]
+define i32 @ldrsb_rr(i8* %p, i32 %n) {
+entry:
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
+ %0 = load i8, i8* %arrayidx, align 1
+ %conv = sext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrsh_rr
+; CHECK-T1: lsls r1, r1, #1
+; CHECK-T1: ldrsh r0, [r0, r1]
+; CHECK-T2: ldrsh.w r0, [r0, r1, lsl #1]
+define i32 @ldrsh_rr(i16* %p, i32 %n) {
+entry:
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
+ %0 = load i16, i16* %arrayidx, align 2
+ %conv = sext i16 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrb_rr
+; CHECK: ldrb r0, [r0, r1]
+define i32 @ldrb_rr(i8* %p, i32 %n) {
+entry:
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
+ %0 = load i8, i8* %arrayidx, align 1
+ %conv = zext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrh_rr
+; CHECK-T1: lsls r1, r1, #1
+; CHECK-T1: ldrh r0, [r0, r1]
+; CHECK-T2: ldrh.w r0, [r0, r1, lsl #1]
+define i32 @ldrh_rr(i16* %p, i32 %n) {
+entry:
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
+ %0 = load i16, i16* %arrayidx, align 2
+ %conv = zext i16 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldr_rr
+; CHECK-T1: lsls r1, r1, #2
+; CHECK-T1: ldr r0, [r0, r1]
+; CHECK-T2: ldr.w r0, [r0, r1, lsl #2]
+define i32 @ldr_rr(i32* %p, i32 %n) {
+entry:
+ %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
+}
+
+; CHECK-LABEL: strb_rr
+; CHECK: strb r2, [r0, r1]
+define void @strb_rr(i8* %p, i32 %n, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i8
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
+ store i8 %conv, i8* %arrayidx, align 1
+ ret void
+}
+
+; CHECK-LABEL: strh_rr
+; CHECK-T1: lsls r1, r1, #1
+; CHECK-T1: strh r2, [r0, r1]
+; CHECK-T2: strh.w r2, [r0, r1, lsl #1]
+define void @strh_rr(i16* %p, i32 %n, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i16
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
+ store i16 %conv, i16* %arrayidx, align 2
+ ret void
+}
+
+; CHECK-LABEL: str_rr
+; CHECK-T1: lsls r1, r1, #2
+; CHECK-T1: str r2, [r0, r1]
+; CHECK-T2: str.w r2, [r0, r1, lsl #2]
+define void @str_rr(i32* %p, i32 %n, i32 %x) {
+entry:
+ %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
+ store i32 %x, i32* %arrayidx, align 4
+ ret void
+}
+
+
+; Immediate offset of zero
+
+; CHECK-LABEL: ldrsb_ri_zero
+; CHECK-T1: ldrb r0, [r0]
+; CHECK-T1: sxtb r0, r0
+; CHECK-T2: ldrsb.w r0, [r0]
+define i32 @ldrsb_ri_zero(i8* %p) {
+entry:
+ %0 = load i8, i8* %p, align 1
+ %conv = sext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrsh_ri_zero
+; CHECK-T1: ldrh r0, [r0]
+; CHECK-T1: sxth r0, r0
+; CHECK-T2: ldrsh.w r0, [r0]
+define i32 @ldrsh_ri_zero(i16* %p) {
+entry:
+ %0 = load i16, i16* %p, align 2
+ %conv = sext i16 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrb_ri_zero
+; CHECK: ldrb r0, [r0]
+define i32 @ldrb_ri_zero(i8* %p) {
+entry:
+ %0 = load i8, i8* %p, align 1
+ %conv = zext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrh_ri_zero
+; CHECK: ldrh r0, [r0]
+define i32 @ldrh_ri_zero(i16* %p) {
+entry:
+ %0 = load i16, i16* %p, align 2
+ %conv = zext i16 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldr_ri_zero
+; CHECK: ldr r0, [r0]
+define i32 @ldr_ri_zero(i32* %p) {
+entry:
+ %0 = load i32, i32* %p, align 4
+ ret i32 %0
+}
+
+; CHECK-LABEL: strb_ri_zero
+; CHECK: strb r1, [r0]
+define void @strb_ri_zero(i8* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i8
+ store i8 %conv, i8* %p, align 1
+ ret void
+}
+
+; CHECK-LABEL: strh_ri_zero
+; CHECK: strh r1, [r0]
+define void @strh_ri_zero(i16* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i16
+ store i16 %conv, i16* %p, align 2
+ ret void
+}
+
+; CHECK-LABEL: str_ri_zero
+; CHECK: str r1, [r0]
+define void @str_ri_zero(i32* %p, i32 %x) {
+entry:
+ store i32 %x, i32* %p, align 4
+ ret void
+}
+
+
+; Maximum Thumb-1 immediate offset
+
+; CHECK-LABEL: ldrsb_ri_t1_max
+; CHECK-T1: movs r1, #31
+; CHECK-T1: ldrsb r0, [r0, r1]
+; CHECK-T2: ldrsb.w r0, [r0, #31]
+define i32 @ldrsb_ri_t1_max(i8* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
+ %0 = load i8, i8* %arrayidx, align 1
+ %conv = sext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrsh_ri_t1_max
+; CHECK-T1: movs r1, #62
+; CHECK-T1: ldrsh r0, [r0, r1]
+; CHECK-T2: ldrsh.w r0, [r0, #62]
+define i32 @ldrsh_ri_t1_max(i16* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
+ %0 = load i16, i16* %arrayidx, align 2
+ %conv = sext i16 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrb_ri_t1_max
+; CHECK: ldrb r0, [r0, #31]
+define i32 @ldrb_ri_t1_max(i8* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
+ %0 = load i8, i8* %arrayidx, align 1
+ %conv = zext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrh_ri_t1_max
+; CHECK: ldrh r0, [r0, #62]
+define i32 @ldrh_ri_t1_max(i16* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
+ %0 = load i16, i16* %arrayidx, align 2
+ %conv = zext i16 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldr_ri_t1_max
+; CHECK: ldr r0, [r0, #124]
+define i32 @ldr_ri_t1_max(i32* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i32, i32* %p, i32 31
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
+}
+
+; CHECK-LABEL: strb_ri_t1_max
+; CHECK: strb r1, [r0, #31]
+define void @strb_ri_t1_max(i8* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i8
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
+ store i8 %conv, i8* %arrayidx, align 1
+ ret void
+}
+
+; CHECK-LABEL: strh_ri_t1_max
+; CHECK: strh r1, [r0, #62]
+define void @strh_ri_t1_max(i16* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i16
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
+ store i16 %conv, i16* %arrayidx, align 2
+ ret void
+}
+
+; CHECK-LABEL: str_ri_t1_max
+; CHECK: str r1, [r0, #124]
+define void @str_ri_t1_max(i32* %p, i32 %x) {
+entry:
+ %arrayidx = getelementptr inbounds i32, i32* %p, i32 31
+ store i32 %x, i32* %arrayidx, align 4
+ ret void
+}
+
+
+; One past maximum Thumb-1 immediate offset
+
+; CHECK-LABEL: ldrsb_ri_t1_too_big
+; CHECK-T1: movs r1, #32
+; CHECK-T1: ldrsb r0, [r0, r1]
+; CHECK-T2: ldrsb.w r0, [r0, #32]
+define i32 @ldrsb_ri_t1_too_big(i8* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
+ %0 = load i8, i8* %arrayidx, align 1
+ %conv = sext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrsh_ri_t1_too_big
+; CHECK-T1: movs r1, #64
+; CHECK-T1: ldrsh r0, [r0, r1]
+; CHECK-T2: ldrsh.w r0, [r0, #64]
+define i32 @ldrsh_ri_t1_too_big(i16* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
+ %0 = load i16, i16* %arrayidx, align 2
+ %conv = sext i16 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrb_ri_t1_too_big
+; CHECK-T1: movs r1, #32
+; CHECK-T1: ldrb r0, [r0, r1]
+; CHECK-T2: ldrb.w r0, [r0, #32]
+define i32 @ldrb_ri_t1_too_big(i8* %p) {
+entry:
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
+ %0 = load i8, i8* %arrayidx, align 1
+ %conv = zext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrh_ri_t1_too_big
+; CHECK-T1: movs r1, #64
+; CHECK-T1: ldrh r0, [r0, r1]
+; CHECK-T2: ldrh.w r0, [r0, #64]
+define i32 @ldrh_ri_t1_too_big(i16* %p) {
entry:
- %tmp = load i8, i8* %p ; <i8> [#uses=1]
- %tmp1 = sext i8 %tmp to i32 ; <i32> [#uses=1]
- ret i32 %tmp1
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
+ %0 = load i16, i16* %arrayidx, align 2
+ %conv = zext i16 %0 to i32
+ ret i32 %conv
}
-define i32 @f2(i8* %p) {
+; CHECK-LABEL: ldr_ri_t1_too_big
+; CHECK-T1: movs r1, #128
+; CHECK-T1: ldr r0, [r0, r1]
+; CHECK-T2: ldr.w r0, [r0, #128]
+define i32 @ldr_ri_t1_too_big(i32* %p) {
entry:
- %tmp = load i8, i8* %p ; <i8> [#uses=1]
- %tmp2 = zext i8 %tmp to i32 ; <i32> [#uses=1]
- ret i32 %tmp2
+ %arrayidx = getelementptr inbounds i32, i32* %p, i32 32
+ %0 = load i32, i32* %arrayidx, align 4
+ ret i32 %0
}
-define i32 @f3(i16* %p) {
+; CHECK-LABEL: strb_ri_t1_too_big
+; CHECK-T1: movs r2, #32
+; CHECK-T1: strb r1, [r0, r2]
+; CHECK-T2: strb.w r1, [r0, #32]
+define void @strb_ri_t1_too_big(i8* %p, i32 %x) {
entry:
- %tmp = load i16, i16* %p ; <i16> [#uses=1]
- %tmp3 = sext i16 %tmp to i32 ; <i32> [#uses=1]
- ret i32 %tmp3
+ %conv = trunc i32 %x to i8
+ %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
+ store i8 %conv, i8* %arrayidx, align 1
+ ret void
}
-define i32 @f4(i16* %p) {
+; CHECK-LABEL: strh_ri_t1_too_big
+; CHECK-T1: movs r2, #64
+; CHECK-T1: strh r1, [r0, r2]
+; CHECK-T2: strh.w r1, [r0, #64]
+define void @strh_ri_t1_too_big(i16* %p, i32 %x) {
entry:
- %tmp = load i16, i16* %p ; <i16> [#uses=1]
- %tmp4 = zext i16 %tmp to i32 ; <i32> [#uses=1]
- ret i32 %tmp4
+ %conv = trunc i32 %x to i16
+ %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
+ store i16 %conv, i16* %arrayidx, align 2
+ ret void
}
-; CHECK: ldrsb
-; CHECK: ldrb
-; CHECK: ldrsh
-; CHECK: ldrh
+; CHECK-LABEL: str_ri_t1_too_big
+; CHECK-T1: movs r2, #128
+; CHECK-T1: str r1, [r0, r2]
+; CHECK-T2: str.w r1, [r0, #128]
+define void @str_ri_t1_too_big(i32* %p, i32 %x) {
+entry:
+ %arrayidx = getelementptr inbounds i32, i32* %p, i32 32
+ store i32 %x, i32* %arrayidx, align 4
+ ret void
+}
+
+
+; Maximum Thumb-2 immediate offset
+
+; CHECK-LABEL: ldrsb_ri_t2_max
+; CHECK-T1: ldr r1, .LCP
+; CHECK-T1: ldrsb r0, [r0, r1]
+; CHECK-T2: ldrsb.w r0, [r0, #4095]
+define i32 @ldrsb_ri_t2_max(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ %0 = load i8, i8* %add.ptr, align 1
+ %conv = sext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrsh_ri_t2_max
+; CHECK-T1: ldr r1, .LCP
+; CHECK-T1: ldrsh r0, [r0, r1]
+; CHECK-T2: ldrsh.w r0, [r0, #4095]
+define i32 @ldrsh_ri_t2_max(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ %0 = bitcast i8* %add.ptr to i16*
+ %1 = load i16, i16* %0, align 2
+ %conv = sext i16 %1 to i32
+ ret i32 %conv
+}
+; CHECK-LABEL: ldrb_ri_t2_max
+; CHECK-T1: ldr r1, .LCP
+; CHECK-T1: ldrb r0, [r0, r1]
+; CHECK-T2: ldrb.w r0, [r0, #4095]
+define i32 @ldrb_ri_t2_max(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ %0 = load i8, i8* %add.ptr, align 1
+ %conv = zext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrh_ri_t2_max
+; CHECK-T1: ldr r1, .LCP
+; CHECK-T1: ldrh r0, [r0, r1]
+; CHECK-T2: ldrh.w r0, [r0, #4095]
+define i32 @ldrh_ri_t2_max(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ %0 = bitcast i8* %add.ptr to i16*
+ %1 = load i16, i16* %0, align 2
+ %conv = zext i16 %1 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldr_ri_t2_max
+; CHECK-T1: ldr r1, .LCP
+; CHECK-T1: ldr r0, [r0, r1]
+; CHECK-T2: ldr.w r0, [r0, #4095]
+define i32 @ldr_ri_t2_max(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ %0 = bitcast i8* %add.ptr to i32*
+ %1 = load i32, i32* %0, align 4
+ ret i32 %1
+}
+
+; CHECK-LABEL: strb_ri_t2_max
+; CHECK-T1: ldr r2, .LCP
+; CHECK-T1: strb r1, [r0, r2]
+; CHECK-T2: strb.w r1, [r0, #4095]
+define void @strb_ri_t2_max(i8* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i8
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ store i8 %conv, i8* %add.ptr, align 1
+ ret void
+}
+
+; CHECK-LABEL: strh_ri_t2_max
+; CHECK-T1: ldr r2, .LCP
+; CHECK-T1: strh r1, [r0, r2]
+; CHECK-T2: strh.w r1, [r0, #4095]
+define void @strh_ri_t2_max(i8* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i16
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ %0 = bitcast i8* %add.ptr to i16*
+ store i16 %conv, i16* %0, align 2
+ ret void
+}
+
+; CHECK-LABEL: str_ri_t2_max
+; CHECK-T1: ldr r2, .LCP
+; CHECK-T1: str r1, [r0, r2]
+; CHECK-T2: str.w r1, [r0, #4095]
+define void @str_ri_t2_max(i8* %p, i32 %x) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
+ %0 = bitcast i8* %add.ptr to i32*
+ store i32 %x, i32* %0, align 4
+ ret void
+}
+
+
+; One past maximum Thumb-2 immediate offset
+
+; CHECK-LABEL: ldrsb_ri_t2_too_big
+; CHECK-T1: movs r1, #1
+; CHECK-T1: lsls r1, r1, #12
+; CHECK-T2: mov.w r1, #4096
+; CHECK: ldrsb r0, [r0, r1]
+define i32 @ldrsb_ri_t2_too_big(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ %0 = load i8, i8* %add.ptr, align 1
+ %conv = sext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrsh_ri_t2_too_big
+; CHECK-T1: movs r1, #1
+; CHECK-T1: lsls r1, r1, #12
+; CHECK-T2: mov.w r1, #4096
+; CHECK: ldrsh r0, [r0, r1]
+define i32 @ldrsh_ri_t2_too_big(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ %0 = bitcast i8* %add.ptr to i16*
+ %1 = load i16, i16* %0, align 2
+ %conv = sext i16 %1 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrb_ri_t2_too_big
+; CHECK-T1: movs r1, #1
+; CHECK-T1: lsls r1, r1, #12
+; CHECK-T2: mov.w r1, #4096
+; CHECK: ldrb r0, [r0, r1]
+define i32 @ldrb_ri_t2_too_big(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ %0 = load i8, i8* %add.ptr, align 1
+ %conv = zext i8 %0 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldrh_ri_t2_too_big
+; CHECK-T1: movs r1, #1
+; CHECK-T1: lsls r1, r1, #12
+; CHECK-T2: mov.w r1, #4096
+; CHECK: ldrh r0, [r0, r1]
+define i32 @ldrh_ri_t2_too_big(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ %0 = bitcast i8* %add.ptr to i16*
+ %1 = load i16, i16* %0, align 2
+ %conv = zext i16 %1 to i32
+ ret i32 %conv
+}
+
+; CHECK-LABEL: ldr_ri_t2_too_big
+; CHECK-T1: movs r1, #1
+; CHECK-T1: lsls r1, r1, #12
+; CHECK-T2: mov.w r1, #4096
+; CHECK: ldr r0, [r0, r1]
+define i32 @ldr_ri_t2_too_big(i8* %p) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ %0 = bitcast i8* %add.ptr to i32*
+ %1 = load i32, i32* %0, align 4
+ ret i32 %1
+}
+
+; CHECK-LABEL: strb_ri_t2_too_big
+; CHECK-T1: movs r2, #1
+; CHECK-T1: lsls r2, r2, #12
+; CHECK-T2: mov.w r2, #4096
+; CHECK: strb r1, [r0, r2]
+define void @strb_ri_t2_too_big(i8* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i8
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ store i8 %conv, i8* %add.ptr, align 1
+ ret void
+}
+
+; CHECK-LABEL: strh_ri_t2_too_big
+; CHECK-T1: movs r2, #1
+; CHECK-T1: lsls r2, r2, #12
+; CHECK-T2: mov.w r2, #4096
+; CHECK: strh r1, [r0, r2]
+define void @strh_ri_t2_too_big(i8* %p, i32 %x) {
+entry:
+ %conv = trunc i32 %x to i16
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ %0 = bitcast i8* %add.ptr to i16*
+ store i16 %conv, i16* %0, align 2
+ ret void
+}
+
+; CHECK-LABEL: str_ri_t2_too_big
+; CHECK-T1: movs r2, #1
+; CHECK-T1: lsls r2, r2, #12
+; CHECK-T2: mov.w r2, #4096
+; CHECK: str r1, [r0, r2]
+define void @str_ri_t2_too_big(i8* %p, i32 %x) {
+entry:
+ %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
+ %0 = bitcast i8* %add.ptr to i32*
+ store i32 %x, i32* %0, align 4
+ ret void
+}
More information about the llvm-commits
mailing list