llvm.org GIT mirror llvm / 4d88dae
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244882 91177308-0d34-0410-b5e6-96231b3b80d8 John Brawn 4 years ago
3 changed file(s) with 707 addition(s) and 255 deletion(s). Raw diff Collapse all Expand all
159159
160160 // Thumb Addressing Modes:
161161 bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset);
162 bool SelectThumbAddrModeRI(SDValue N, SDValue &Base, SDValue &Offset,
163 unsigned Scale);
164 bool SelectThumbAddrModeRI5S1(SDValue N, SDValue &Base, SDValue &Offset);
165 bool SelectThumbAddrModeRI5S2(SDValue N, SDValue &Base, SDValue &Offset);
166 bool SelectThumbAddrModeRI5S4(SDValue N, SDValue &Base, SDValue &Offset);
167162 bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base,
168163 SDValue &OffImm);
169164 bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
10851080 }
10861081
10871082 bool
1088 ARMDAGToDAGISel::SelectThumbAddrModeRI(SDValue N, SDValue &Base,
1089 SDValue &Offset, unsigned Scale) {
1090 if (Scale == 4) {
1091 SDValue TmpBase, TmpOffImm;
1092 if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm))
1093 return false; // We want to select tLDRspi / tSTRspi instead.
1094
1095 if (N.getOpcode() == ARMISD::Wrapper &&
1096 N.getOperand(0).getOpcode() == ISD::TargetConstantPool)
1097 return false; // We want to select tLDRpci instead.
1098 }
1099
1100 if (!CurDAG->isBaseWithConstantOffset(N))
1101 return false;
1102
1103 // Thumb does not have [sp, r] address mode.
1104 RegisterSDNode *LHSR = dyn_cast(N.getOperand(0));
1105 RegisterSDNode *RHSR = dyn_cast(N.getOperand(1));
1106 if ((LHSR && LHSR->getReg() == ARM::SP) ||
1107 (RHSR && RHSR->getReg() == ARM::SP))
1108 return false;
1109
1110 // FIXME: Why do we explicitly check for a match here and then return false?
1111 // Presumably to allow something else to match, but shouldn't this be
1112 // documented?
1113 int RHSC;
1114 if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC))
1115 return false;
1116
1117 Base = N.getOperand(0);
1118 Offset = N.getOperand(1);
1119 return true;
1120 }
1121
1122 bool
1123 ARMDAGToDAGISel::SelectThumbAddrModeRI5S1(SDValue N,
1124 SDValue &Base,
1125 SDValue &Offset) {
1126 return SelectThumbAddrModeRI(N, Base, Offset, 1);
1127 }
1128
1129 bool
1130 ARMDAGToDAGISel::SelectThumbAddrModeRI5S2(SDValue N,
1131 SDValue &Base,
1132 SDValue &Offset) {
1133 return SelectThumbAddrModeRI(N, Base, Offset, 2);
1134 }
1135
1136 bool
1137 ARMDAGToDAGISel::SelectThumbAddrModeRI5S4(SDValue N,
1138 SDValue &Base,
1139 SDValue &Offset) {
1140 return SelectThumbAddrModeRI(N, Base, Offset, 4);
1141 }
1142
1143 bool
11441083 ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale,
11451084 SDValue &Base, SDValue &OffImm) {
1146 if (Scale == 4) {
1147 SDValue TmpBase, TmpOffImm;
1148 if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm))
1149 return false; // We want to select tLDRspi / tSTRspi instead.
1150
1151 if (N.getOpcode() == ARMISD::Wrapper &&
1152 N.getOperand(0).getOpcode() == ISD::TargetConstantPool)
1153 return false; // We want to select tLDRpci instead.
1154 }
1155
11561085 if (!CurDAG->isBaseWithConstantOffset(N)) {
1157 if (N.getOpcode() == ARMISD::Wrapper &&
1158 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress) {
1086 if (N.getOpcode() == ISD::ADD) {
1087 return false; // We want to select register offset instead
1088 } else if (N.getOpcode() == ARMISD::Wrapper &&
1089 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress) {
11591090 Base = N.getOperand(0);
11601091 } else {
11611092 Base = N;
11621093 }
11631094
1164 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
1165 return true;
1166 }
1167
1168 RegisterSDNode *LHSR = dyn_cast(N.getOperand(0));
1169 RegisterSDNode *RHSR = dyn_cast(N.getOperand(1));
1170 if ((LHSR && LHSR->getReg() == ARM::SP) ||
1171 (RHSR && RHSR->getReg() == ARM::SP)) {
1172 ConstantSDNode *LHS = dyn_cast(N.getOperand(0));
1173 ConstantSDNode *RHS = dyn_cast(N.getOperand(1));
1174 unsigned LHSC = LHS ? LHS->getZExtValue() : 0;
1175 unsigned RHSC = RHS ? RHS->getZExtValue() : 0;
1176
1177 // Thumb does not have [sp, #imm5] address mode for non-zero imm5.
1178 if (LHSC != 0 || RHSC != 0) return false;
1179
1180 Base = N;
11811095 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
11821096 return true;
11831097 }
11901104 return true;
11911105 }
11921106
1193 Base = N.getOperand(0);
1194 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
1195 return true;
1107 // Offset is too large, so use register offset instead.
1108 return false;
11961109 }
11971110
11981111 bool
590590 // Load Store Instructions.
591591 //
592592
593 // Loads: reg/reg and reg/imm5
594 let canFoldAsLoad = 1, isReMaterializable = 1 in
595 multiclass thumb_ld_rr_ri_enc reg_opc, bits<4> imm_opc,
596 Operand AddrMode_r, Operand AddrMode_i,
597 AddrMode am, InstrItinClass itin_r,
598 InstrItinClass itin_i, string asm,
599 PatFrag opnode> {
600 def r : // reg/reg
601 T1pILdStEncode
602 (outs tGPR:$Rt), (ins AddrMode_r:$addr),
603 am, itin_r, asm, "\t$Rt, $addr",
604 [(set tGPR:$Rt, (opnode AddrMode_r:$addr))]>;
605 def i : // reg/imm5
606 T1pILdStEncodeImm
607 (outs tGPR:$Rt), (ins AddrMode_i:$addr),
608 am, itin_i, asm, "\t$Rt, $addr",
609 [(set tGPR:$Rt, (opnode AddrMode_i:$addr))]>;
610 }
611 // Stores: reg/reg and reg/imm5
612 multiclass thumb_st_rr_ri_enc reg_opc, bits<4> imm_opc,
613 Operand AddrMode_r, Operand AddrMode_i,
614 AddrMode am, InstrItinClass itin_r,
615 InstrItinClass itin_i, string asm,
616 PatFrag opnode> {
617 def r : // reg/reg
618 T1pILdStEncode
619 (outs), (ins tGPR:$Rt, AddrMode_r:$addr),
620 am, itin_r, asm, "\t$Rt, $addr",
621 [(opnode tGPR:$Rt, AddrMode_r:$addr)]>;
622 def i : // reg/imm5
623 T1pILdStEncodeImm
624 (outs), (ins tGPR:$Rt, AddrMode_i:$addr),
625 am, itin_i, asm, "\t$Rt, $addr",
626 [(opnode tGPR:$Rt, AddrMode_i:$addr)]>;
627 }
628
629 // A8.6.57 & A8.6.60
630 defm tLDR : thumb_ld_rr_ri_enc<0b100, 0b0110, t_addrmode_rrs4,
631 t_addrmode_is4, AddrModeT1_4,
632 IIC_iLoad_r, IIC_iLoad_i, "ldr",
633 UnOpFrag<(load node:$Src)>>;
634
635 // A8.6.64 & A8.6.61
636 defm tLDRB : thumb_ld_rr_ri_enc<0b110, 0b0111, t_addrmode_rrs1,
637 t_addrmode_is1, AddrModeT1_1,
638 IIC_iLoad_bh_r, IIC_iLoad_bh_i, "ldrb",
639 UnOpFrag<(zextloadi8 node:$Src)>>;
640
641 // A8.6.76 & A8.6.73
642 defm tLDRH : thumb_ld_rr_ri_enc<0b101, 0b1000, t_addrmode_rrs2,
643 t_addrmode_is2, AddrModeT1_2,
644 IIC_iLoad_bh_r, IIC_iLoad_bh_i, "ldrh",
645 UnOpFrag<(zextloadi16 node:$Src)>>;
646
647 let AddedComplexity = 10 in
648 def tLDRSB : // A8.6.80
649 T1pILdStEncode<0b011, (outs tGPR:$Rt), (ins t_addrmode_rr:$addr),
650 AddrModeT1_1, IIC_iLoad_bh_r,
651 "ldrsb", "\t$Rt, $addr",
652 [(set tGPR:$Rt, (sextloadi8 t_addrmode_rr:$addr))]>;
653
654 let AddedComplexity = 10 in
655 def tLDRSH : // A8.6.84
656 T1pILdStEncode<0b111, (outs tGPR:$Rt), (ins t_addrmode_rr:$addr),
657 AddrModeT1_2, IIC_iLoad_bh_r,
658 "ldrsh", "\t$Rt, $addr",
659 [(set tGPR:$Rt, (sextloadi16 t_addrmode_rr:$addr))]>;
660
593 // PC-relative loads need to be matched first as constant pool accesses need to
594 // always be PC-relative. We do this using AddedComplexity, as the pattern is
595 // simpler than the patterns of the other load instructions.
596 let canFoldAsLoad = 1, isReMaterializable = 1, AddedComplexity = 10 in
597 def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
598 "ldr", "\t$Rt, $addr",
599 [(set tGPR:$Rt, (load (ARMWrapper tconstpool:$addr)))]>,
600 T1Encoding<{0,1,0,0,1,?}> {
601 // A6.2 & A8.6.59
602 bits<3> Rt;
603 bits<8> addr;
604 let Inst{10-8} = Rt;
605 let Inst{7-0} = addr;
606 }
607
608 // SP-relative loads should be matched before standard immediate-offset loads as
609 // it means we avoid having to move SP to another register.
661610 let canFoldAsLoad = 1 in
662611 def tLDRspi : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_sp:$addr), IIC_iLoad_i,
663612 "ldr", "\t$Rt, $addr",
669618 let Inst{7-0} = addr;
670619 }
671620
621 // Loads: reg/reg and reg/imm5
672622 let canFoldAsLoad = 1, isReMaterializable = 1 in
673 def tLDRpci : T1pIs<(outs tGPR:$Rt), (ins t_addrmode_pc:$addr), IIC_iLoad_i,
674 "ldr", "\t$Rt, $addr",
675 [(set tGPR:$Rt, (load (ARMWrapper tconstpool:$addr)))]>,
676 T1Encoding<{0,1,0,0,1,?}> {
677 // A6.2 & A8.6.59
678 bits<3> Rt;
679 bits<8> addr;
680 let Inst{10-8} = Rt;
681 let Inst{7-0} = addr;
682 }
683
684 // A8.6.194 & A8.6.192
685 defm tSTR : thumb_st_rr_ri_enc<0b000, 0b0110, t_addrmode_rrs4,
623 multiclass thumb_ld_rr_ri_enc reg_opc, bits<4> imm_opc,
624 Operand AddrMode_r, Operand AddrMode_i,
625 AddrMode am, InstrItinClass itin_r,
626 InstrItinClass itin_i, string asm,
627 PatFrag opnode> {
628 // Immediate-offset loads should be matched before register-offset loads as
629 // when the offset is a constant it's simpler to first check if it fits in the
630 // immediate offset field then fall back to register-offset if it doesn't.
631 def i : // reg/imm5
632 T1pILdStEncodeImm
633 (outs tGPR:$Rt), (ins AddrMode_i:$addr),
634 am, itin_i, asm, "\t$Rt, $addr",
635 [(set tGPR:$Rt, (opnode AddrMode_i:$addr))]>;
636 // Register-offset loads are matched last.
637 def r : // reg/reg
638 T1pILdStEncode
639 (outs tGPR:$Rt), (ins AddrMode_r:$addr),
640 am, itin_r, asm, "\t$Rt, $addr",
641 [(set tGPR:$Rt, (opnode AddrMode_r:$addr))]>;
642 }
643 // Stores: reg/reg and reg/imm5
644 multiclass thumb_st_rr_ri_enc reg_opc, bits<4> imm_opc,
645 Operand AddrMode_r, Operand AddrMode_i,
646 AddrMode am, InstrItinClass itin_r,
647 InstrItinClass itin_i, string asm,
648 PatFrag opnode> {
649 def i : // reg/imm5
650 T1pILdStEncodeImm
651 (outs), (ins tGPR:$Rt, AddrMode_i:$addr),
652 am, itin_i, asm, "\t$Rt, $addr",
653 [(opnode tGPR:$Rt, AddrMode_i:$addr)]>;
654 def r : // reg/reg
655 T1pILdStEncode
656 (outs), (ins tGPR:$Rt, AddrMode_r:$addr),
657 am, itin_r, asm, "\t$Rt, $addr",
658 [(opnode tGPR:$Rt, AddrMode_r:$addr)]>;
659 }
660
661 // A8.6.57 & A8.6.60
662 defm tLDR : thumb_ld_rr_ri_enc<0b100, 0b0110, t_addrmode_rr,
686663 t_addrmode_is4, AddrModeT1_4,
687 IIC_iStore_r, IIC_iStore_i, "str",
688 BinOpFrag<(store node:$LHS, node:$RHS)>>;
689
690 // A8.6.197 & A8.6.195
691 defm tSTRB : thumb_st_rr_ri_enc<0b010, 0b0111, t_addrmode_rrs1,
664 IIC_iLoad_r, IIC_iLoad_i, "ldr",
665 UnOpFrag<(load node:$Src)>>;
666
667 // A8.6.64 & A8.6.61
668 defm tLDRB : thumb_ld_rr_ri_enc<0b110, 0b0111, t_addrmode_rr,
692669 t_addrmode_is1, AddrModeT1_1,
693 IIC_iStore_bh_r, IIC_iStore_bh_i, "strb",
694 BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>;
695
696 // A8.6.207 & A8.6.205
697 defm tSTRH : thumb_st_rr_ri_enc<0b001, 0b1000, t_addrmode_rrs2,
698 t_addrmode_is2, AddrModeT1_2,
699 IIC_iStore_bh_r, IIC_iStore_bh_i, "strh",
700 BinOpFrag<(truncstorei16 node:$LHS, node:$RHS)>>;
670 IIC_iLoad_bh_r, IIC_iLoad_bh_i, "ldrb",
671 UnOpFrag<(zextloadi8 node:$Src)>>;
672
673 // A8.6.76 & A8.6.73
674 defm tLDRH : thumb_ld_rr_ri_enc<0b101, 0b1000, t_addrmode_rr,
675 t_addrmode_is2, AddrModeT1_2,
676 IIC_iLoad_bh_r, IIC_iLoad_bh_i, "ldrh",
677 UnOpFrag<(zextloadi16 node:$Src)>>;
678
679 let AddedComplexity = 10 in
680 def tLDRSB : // A8.6.80
681 T1pILdStEncode<0b011, (outs tGPR:$Rt), (ins t_addrmode_rr:$addr),
682 AddrModeT1_1, IIC_iLoad_bh_r,
683 "ldrsb", "\t$Rt, $addr",
684 [(set tGPR:$Rt, (sextloadi8 t_addrmode_rr:$addr))]>;
685
686 let AddedComplexity = 10 in
687 def tLDRSH : // A8.6.84
688 T1pILdStEncode<0b111, (outs tGPR:$Rt), (ins t_addrmode_rr:$addr),
689 AddrModeT1_2, IIC_iLoad_bh_r,
690 "ldrsh", "\t$Rt, $addr",
691 [(set tGPR:$Rt, (sextloadi16 t_addrmode_rr:$addr))]>;
701692
702693
703694 def tSTRspi : T1pIs<(outs), (ins tGPR:$Rt, t_addrmode_sp:$addr), IIC_iStore_i,
709700 let Inst{10-8} = Rt;
710701 let Inst{7-0} = addr;
711702 }
703
704 // A8.6.194 & A8.6.192
705 defm tSTR : thumb_st_rr_ri_enc<0b000, 0b0110, t_addrmode_rr,
706 t_addrmode_is4, AddrModeT1_4,
707 IIC_iStore_r, IIC_iStore_i, "str",
708 BinOpFrag<(store node:$LHS, node:$RHS)>>;
709
710 // A8.6.197 & A8.6.195
711 defm tSTRB : thumb_st_rr_ri_enc<0b010, 0b0111, t_addrmode_rr,
712 t_addrmode_is1, AddrModeT1_1,
713 IIC_iStore_bh_r, IIC_iStore_bh_i, "strb",
714 BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>;
715
716 // A8.6.207 & A8.6.205
717 defm tSTRH : thumb_st_rr_ri_enc<0b001, 0b1000, t_addrmode_rr,
718 t_addrmode_is2, AddrModeT1_2,
719 IIC_iStore_bh_r, IIC_iStore_bh_i, "strh",
720 BinOpFrag<(truncstorei16 node:$LHS, node:$RHS)>>;
721
712722
713723 //===----------------------------------------------------------------------===//
714724 // Load / store multiple Instructions.
13271337 (tSUBrr tGPR:$lhs, tGPR:$rhs)>;
13281338
13291339 // Bswap 16 with load/store
1330 def : T1Pat<(srl (bswap (extloadi16 t_addrmode_rrs2:$addr)), (i32 16)),
1331 (tREV16 (tLDRHr t_addrmode_rrs2:$addr))>;
13321340 def : T1Pat<(srl (bswap (extloadi16 t_addrmode_is2:$addr)), (i32 16)),
13331341 (tREV16 (tLDRHi t_addrmode_is2:$addr))>;
1334 def : T1Pat<(truncstorei16 (srl (bswap tGPR:$Rn), (i32 16)),
1335 t_addrmode_rrs2:$addr),
1336 (tSTRHr (tREV16 tGPR:$Rn), t_addrmode_rrs2:$addr)>;
1342 def : T1Pat<(srl (bswap (extloadi16 t_addrmode_rr:$addr)), (i32 16)),
1343 (tREV16 (tLDRHr t_addrmode_rr:$addr))>;
13371344 def : T1Pat<(truncstorei16 (srl (bswap tGPR:$Rn), (i32 16)),
13381345 t_addrmode_is2:$addr),
13391346 (tSTRHi(tREV16 tGPR:$Rn), t_addrmode_is2:$addr)>;
1347 def : T1Pat<(truncstorei16 (srl (bswap tGPR:$Rn), (i32 16)),
1348 t_addrmode_rr:$addr),
1349 (tSTRHr (tREV16 tGPR:$Rn), t_addrmode_rr:$addr)>;
13401350
13411351 // ConstantPool
13421352 def : T1Pat<(ARMWrapper tconstpool :$dst), (tLEApcrel tconstpool :$dst)>;
13711381 Requires<[IsThumb, HasV5T]>;
13721382
13731383 // zextload i1 -> zextload i8
1374 def : T1Pat<(zextloadi1 t_addrmode_rrs1:$addr),
1375 (tLDRBr t_addrmode_rrs1:$addr)>;
13761384 def : T1Pat<(zextloadi1 t_addrmode_is1:$addr),
13771385 (tLDRBi t_addrmode_is1:$addr)>;
1386 def : T1Pat<(zextloadi1 t_addrmode_rr:$addr),
1387 (tLDRBr t_addrmode_rr:$addr)>;
13781388
13791389 // extload from the stack -> word load from the stack, as it avoids having to
13801390 // materialize the base in a separate register. This only works when a word
13881398 Requires<[IsThumb, IsThumb1Only, IsLE]>;
13891399
13901400 // extload -> zextload
1391 def : T1Pat<(extloadi1 t_addrmode_rrs1:$addr), (tLDRBr t_addrmode_rrs1:$addr)>;
1392 def : T1Pat<(extloadi1 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
1393 def : T1Pat<(extloadi8 t_addrmode_rrs1:$addr), (tLDRBr t_addrmode_rrs1:$addr)>;
1394 def : T1Pat<(extloadi8 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
1395 def : T1Pat<(extloadi16 t_addrmode_rrs2:$addr), (tLDRHr t_addrmode_rrs2:$addr)>;
1396 def : T1Pat<(extloadi16 t_addrmode_is2:$addr), (tLDRHi t_addrmode_is2:$addr)>;
1401 def : T1Pat<(extloadi1 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
1402 def : T1Pat<(extloadi1 t_addrmode_rr:$addr), (tLDRBr t_addrmode_rr:$addr)>;
1403 def : T1Pat<(extloadi8 t_addrmode_is1:$addr), (tLDRBi t_addrmode_is1:$addr)>;
1404 def : T1Pat<(extloadi8 t_addrmode_rr:$addr), (tLDRBr t_addrmode_rr:$addr)>;
1405 def : T1Pat<(extloadi16 t_addrmode_is2:$addr), (tLDRHi t_addrmode_is2:$addr)>;
1406 def : T1Pat<(extloadi16 t_addrmode_rr:$addr), (tLDRHr t_addrmode_rr:$addr)>;
13971407
13981408 // If it's impossible to use [r,r] address mode for sextload, select to
13991409 // ldr{b|h} + sxt{b|h} instead.
14001410 def : T1Pat<(sextloadi8 t_addrmode_is1:$addr),
14011411 (tSXTB (tLDRBi t_addrmode_is1:$addr))>,
14021412 Requires<[IsThumb, IsThumb1Only, HasV6]>;
1403 def : T1Pat<(sextloadi8 t_addrmode_rrs1:$addr),
1404 (tSXTB (tLDRBr t_addrmode_rrs1:$addr))>,
1413 def : T1Pat<(sextloadi8 t_addrmode_rr:$addr),
1414 (tSXTB (tLDRBr t_addrmode_rr:$addr))>,
14051415 Requires<[IsThumb, IsThumb1Only, HasV6]>;
14061416 def : T1Pat<(sextloadi16 t_addrmode_is2:$addr),
14071417 (tSXTH (tLDRHi t_addrmode_is2:$addr))>,
14081418 Requires<[IsThumb, IsThumb1Only, HasV6]>;
1409 def : T1Pat<(sextloadi16 t_addrmode_rrs2:$addr),
1410 (tSXTH (tLDRHr t_addrmode_rrs2:$addr))>,
1419 def : T1Pat<(sextloadi16 t_addrmode_rr:$addr),
1420 (tSXTH (tLDRHr t_addrmode_rr:$addr))>,
14111421 Requires<[IsThumb, IsThumb1Only, HasV6]>;
14121422
1413 def : T1Pat<(sextloadi8 t_addrmode_rrs1:$addr),
1414 (tASRri (tLSLri (tLDRBr t_addrmode_rrs1:$addr), 24), 24)>;
14151423 def : T1Pat<(sextloadi8 t_addrmode_is1:$addr),
14161424 (tASRri (tLSLri (tLDRBi t_addrmode_is1:$addr), 24), 24)>;
1417 def : T1Pat<(sextloadi16 t_addrmode_rrs2:$addr),
1418 (tASRri (tLSLri (tLDRHr t_addrmode_rrs2:$addr), 16), 16)>;
1425 def : T1Pat<(sextloadi8 t_addrmode_rr:$addr),
1426 (tASRri (tLSLri (tLDRBr t_addrmode_rr:$addr), 24), 24)>;
14191427 def : T1Pat<(sextloadi16 t_addrmode_is2:$addr),
14201428 (tASRri (tLSLri (tLDRHi t_addrmode_is2:$addr), 16), 16)>;
1429 def : T1Pat<(sextloadi16 t_addrmode_rr:$addr),
1430 (tASRri (tLSLri (tLDRHr t_addrmode_rr:$addr), 16), 16)>;
14211431
14221432 def : T1Pat<(atomic_load_8 t_addrmode_is1:$src),
14231433 (tLDRBi t_addrmode_is1:$src)>;
1424 def : T1Pat<(atomic_load_8 t_addrmode_rrs1:$src),
1425 (tLDRBr t_addrmode_rrs1:$src)>;
1434 def : T1Pat<(atomic_load_8 t_addrmode_rr:$src),
1435 (tLDRBr t_addrmode_rr:$src)>;
14261436 def : T1Pat<(atomic_load_16 t_addrmode_is2:$src),
14271437 (tLDRHi t_addrmode_is2:$src)>;
1428 def : T1Pat<(atomic_load_16 t_addrmode_rrs2:$src),
1429 (tLDRHr t_addrmode_rrs2:$src)>;
1438 def : T1Pat<(atomic_load_16 t_addrmode_rr:$src),
1439 (tLDRHr t_addrmode_rr:$src)>;
14301440 def : T1Pat<(atomic_load_32 t_addrmode_is4:$src),
14311441 (tLDRi t_addrmode_is4:$src)>;
1432 def : T1Pat<(atomic_load_32 t_addrmode_rrs4:$src),
1433 (tLDRr t_addrmode_rrs4:$src)>;
1442 def : T1Pat<(atomic_load_32 t_addrmode_rr:$src),
1443 (tLDRr t_addrmode_rr:$src)>;
14341444 def : T1Pat<(atomic_store_8 t_addrmode_is1:$ptr, tGPR:$val),
14351445 (tSTRBi tGPR:$val, t_addrmode_is1:$ptr)>;
1436 def : T1Pat<(atomic_store_8 t_addrmode_rrs1:$ptr, tGPR:$val),
1437 (tSTRBr tGPR:$val, t_addrmode_rrs1:$ptr)>;
1446 def : T1Pat<(atomic_store_8 t_addrmode_rr:$ptr, tGPR:$val),
1447 (tSTRBr tGPR:$val, t_addrmode_rr:$ptr)>;
14381448 def : T1Pat<(atomic_store_16 t_addrmode_is2:$ptr, tGPR:$val),
14391449 (tSTRHi tGPR:$val, t_addrmode_is2:$ptr)>;
1440 def : T1Pat<(atomic_store_16 t_addrmode_rrs2:$ptr, tGPR:$val),
1441 (tSTRHr tGPR:$val, t_addrmode_rrs2:$ptr)>;
1450 def : T1Pat<(atomic_store_16 t_addrmode_rr:$ptr, tGPR:$val),
1451 (tSTRHr tGPR:$val, t_addrmode_rr:$ptr)>;
14421452 def : T1Pat<(atomic_store_32 t_addrmode_is4:$ptr, tGPR:$val),
14431453 (tSTRi tGPR:$val, t_addrmode_is4:$ptr)>;
1444 def : T1Pat<(atomic_store_32 t_addrmode_rrs4:$ptr, tGPR:$val),
1445 (tSTRr tGPR:$val, t_addrmode_rrs4:$ptr)>;
1454 def : T1Pat<(atomic_store_32 t_addrmode_rr:$ptr, tGPR:$val),
1455 (tSTRr tGPR:$val, t_addrmode_rr:$ptr)>;
14461456
14471457 // Large immediate handling.
14481458
None ; RUN: llc -mtriple=arm-eabi %s -o - | FileCheck %s
1
2 define i32 @f1(i8* %p) {
3 entry:
4 %tmp = load i8, i8* %p ; [#uses=1]
5 %tmp1 = sext i8 %tmp to i32 ; [#uses=1]
6 ret i32 %tmp1
7 }
8
9 define i32 @f2(i8* %p) {
10 entry:
11 %tmp = load i8, i8* %p ; [#uses=1]
12 %tmp2 = zext i8 %tmp to i32 ; [#uses=1]
13 ret i32 %tmp2
14 }
15
16 define i32 @f3(i16* %p) {
17 entry:
18 %tmp = load i16, i16* %p ; [#uses=1]
19 %tmp3 = sext i16 %tmp to i32 ; [#uses=1]
20 ret i32 %tmp3
21 }
22
23 define i32 @f4(i16* %p) {
24 entry:
25 %tmp = load i16, i16* %p ; [#uses=1]
26 %tmp4 = zext i16 %tmp to i32 ; [#uses=1]
27 ret i32 %tmp4
28 }
29
30 ; CHECK: ldrsb
31 ; CHECK: ldrb
32 ; CHECK: ldrsh
33 ; CHECK: ldrh
34
0 ; RUN: llc -mtriple=thumbv6m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T1
1 ; RUN: llc -mtriple=thumbv7m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T2
2
3
4 ; Register offset
5
6 ; CHECK-LABEL: ldrsb_rr
7 ; CHECK: ldrsb r0, [r0, r1]
8 define i32 @ldrsb_rr(i8* %p, i32 %n) {
9 entry:
10 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
11 %0 = load i8, i8* %arrayidx, align 1
12 %conv = sext i8 %0 to i32
13 ret i32 %conv
14 }
15
16 ; CHECK-LABEL: ldrsh_rr
17 ; CHECK-T1: lsls r1, r1, #1
18 ; CHECK-T1: ldrsh r0, [r0, r1]
19 ; CHECK-T2: ldrsh.w r0, [r0, r1, lsl #1]
20 define i32 @ldrsh_rr(i16* %p, i32 %n) {
21 entry:
22 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
23 %0 = load i16, i16* %arrayidx, align 2
24 %conv = sext i16 %0 to i32
25 ret i32 %conv
26 }
27
28 ; CHECK-LABEL: ldrb_rr
29 ; CHECK: ldrb r0, [r0, r1]
30 define i32 @ldrb_rr(i8* %p, i32 %n) {
31 entry:
32 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
33 %0 = load i8, i8* %arrayidx, align 1
34 %conv = zext i8 %0 to i32
35 ret i32 %conv
36 }
37
38 ; CHECK-LABEL: ldrh_rr
39 ; CHECK-T1: lsls r1, r1, #1
40 ; CHECK-T1: ldrh r0, [r0, r1]
41 ; CHECK-T2: ldrh.w r0, [r0, r1, lsl #1]
42 define i32 @ldrh_rr(i16* %p, i32 %n) {
43 entry:
44 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
45 %0 = load i16, i16* %arrayidx, align 2
46 %conv = zext i16 %0 to i32
47 ret i32 %conv
48 }
49
50 ; CHECK-LABEL: ldr_rr
51 ; CHECK-T1: lsls r1, r1, #2
52 ; CHECK-T1: ldr r0, [r0, r1]
53 ; CHECK-T2: ldr.w r0, [r0, r1, lsl #2]
54 define i32 @ldr_rr(i32* %p, i32 %n) {
55 entry:
56 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
57 %0 = load i32, i32* %arrayidx, align 4
58 ret i32 %0
59 }
60
61 ; CHECK-LABEL: strb_rr
62 ; CHECK: strb r2, [r0, r1]
63 define void @strb_rr(i8* %p, i32 %n, i32 %x) {
64 entry:
65 %conv = trunc i32 %x to i8
66 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n
67 store i8 %conv, i8* %arrayidx, align 1
68 ret void
69 }
70
71 ; CHECK-LABEL: strh_rr
72 ; CHECK-T1: lsls r1, r1, #1
73 ; CHECK-T1: strh r2, [r0, r1]
74 ; CHECK-T2: strh.w r2, [r0, r1, lsl #1]
75 define void @strh_rr(i16* %p, i32 %n, i32 %x) {
76 entry:
77 %conv = trunc i32 %x to i16
78 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n
79 store i16 %conv, i16* %arrayidx, align 2
80 ret void
81 }
82
83 ; CHECK-LABEL: str_rr
84 ; CHECK-T1: lsls r1, r1, #2
85 ; CHECK-T1: str r2, [r0, r1]
86 ; CHECK-T2: str.w r2, [r0, r1, lsl #2]
87 define void @str_rr(i32* %p, i32 %n, i32 %x) {
88 entry:
89 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n
90 store i32 %x, i32* %arrayidx, align 4
91 ret void
92 }
93
94
95 ; Immediate offset of zero
96
97 ; CHECK-LABEL: ldrsb_ri_zero
98 ; CHECK-T1: ldrb r0, [r0]
99 ; CHECK-T1: sxtb r0, r0
100 ; CHECK-T2: ldrsb.w r0, [r0]
101 define i32 @ldrsb_ri_zero(i8* %p) {
102 entry:
103 %0 = load i8, i8* %p, align 1
104 %conv = sext i8 %0 to i32
105 ret i32 %conv
106 }
107
108 ; CHECK-LABEL: ldrsh_ri_zero
109 ; CHECK-T1: ldrh r0, [r0]
110 ; CHECK-T1: sxth r0, r0
111 ; CHECK-T2: ldrsh.w r0, [r0]
112 define i32 @ldrsh_ri_zero(i16* %p) {
113 entry:
114 %0 = load i16, i16* %p, align 2
115 %conv = sext i16 %0 to i32
116 ret i32 %conv
117 }
118
119 ; CHECK-LABEL: ldrb_ri_zero
120 ; CHECK: ldrb r0, [r0]
121 define i32 @ldrb_ri_zero(i8* %p) {
122 entry:
123 %0 = load i8, i8* %p, align 1
124 %conv = zext i8 %0 to i32
125 ret i32 %conv
126 }
127
128 ; CHECK-LABEL: ldrh_ri_zero
129 ; CHECK: ldrh r0, [r0]
130 define i32 @ldrh_ri_zero(i16* %p) {
131 entry:
132 %0 = load i16, i16* %p, align 2
133 %conv = zext i16 %0 to i32
134 ret i32 %conv
135 }
136
137 ; CHECK-LABEL: ldr_ri_zero
138 ; CHECK: ldr r0, [r0]
139 define i32 @ldr_ri_zero(i32* %p) {
140 entry:
141 %0 = load i32, i32* %p, align 4
142 ret i32 %0
143 }
144
145 ; CHECK-LABEL: strb_ri_zero
146 ; CHECK: strb r1, [r0]
147 define void @strb_ri_zero(i8* %p, i32 %x) {
148 entry:
149 %conv = trunc i32 %x to i8
150 store i8 %conv, i8* %p, align 1
151 ret void
152 }
153
154 ; CHECK-LABEL: strh_ri_zero
155 ; CHECK: strh r1, [r0]
156 define void @strh_ri_zero(i16* %p, i32 %x) {
157 entry:
158 %conv = trunc i32 %x to i16
159 store i16 %conv, i16* %p, align 2
160 ret void
161 }
162
163 ; CHECK-LABEL: str_ri_zero
164 ; CHECK: str r1, [r0]
165 define void @str_ri_zero(i32* %p, i32 %x) {
166 entry:
167 store i32 %x, i32* %p, align 4
168 ret void
169 }
170
171
172 ; Maximum Thumb-1 immediate offset
173
174 ; CHECK-LABEL: ldrsb_ri_t1_max
175 ; CHECK-T1: movs r1, #31
176 ; CHECK-T1: ldrsb r0, [r0, r1]
177 ; CHECK-T2: ldrsb.w r0, [r0, #31]
178 define i32 @ldrsb_ri_t1_max(i8* %p) {
179 entry:
180 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
181 %0 = load i8, i8* %arrayidx, align 1
182 %conv = sext i8 %0 to i32
183 ret i32 %conv
184 }
185
186 ; CHECK-LABEL: ldrsh_ri_t1_max
187 ; CHECK-T1: movs r1, #62
188 ; CHECK-T1: ldrsh r0, [r0, r1]
189 ; CHECK-T2: ldrsh.w r0, [r0, #62]
190 define i32 @ldrsh_ri_t1_max(i16* %p) {
191 entry:
192 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
193 %0 = load i16, i16* %arrayidx, align 2
194 %conv = sext i16 %0 to i32
195 ret i32 %conv
196 }
197
198 ; CHECK-LABEL: ldrb_ri_t1_max
199 ; CHECK: ldrb r0, [r0, #31]
200 define i32 @ldrb_ri_t1_max(i8* %p) {
201 entry:
202 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
203 %0 = load i8, i8* %arrayidx, align 1
204 %conv = zext i8 %0 to i32
205 ret i32 %conv
206 }
207
208 ; CHECK-LABEL: ldrh_ri_t1_max
209 ; CHECK: ldrh r0, [r0, #62]
210 define i32 @ldrh_ri_t1_max(i16* %p) {
211 entry:
212 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
213 %0 = load i16, i16* %arrayidx, align 2
214 %conv = zext i16 %0 to i32
215 ret i32 %conv
216 }
217
218 ; CHECK-LABEL: ldr_ri_t1_max
219 ; CHECK: ldr r0, [r0, #124]
220 define i32 @ldr_ri_t1_max(i32* %p) {
221 entry:
222 %arrayidx = getelementptr inbounds i32, i32* %p, i32 31
223 %0 = load i32, i32* %arrayidx, align 4
224 ret i32 %0
225 }
226
227 ; CHECK-LABEL: strb_ri_t1_max
228 ; CHECK: strb r1, [r0, #31]
229 define void @strb_ri_t1_max(i8* %p, i32 %x) {
230 entry:
231 %conv = trunc i32 %x to i8
232 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31
233 store i8 %conv, i8* %arrayidx, align 1
234 ret void
235 }
236
237 ; CHECK-LABEL: strh_ri_t1_max
238 ; CHECK: strh r1, [r0, #62]
239 define void @strh_ri_t1_max(i16* %p, i32 %x) {
240 entry:
241 %conv = trunc i32 %x to i16
242 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31
243 store i16 %conv, i16* %arrayidx, align 2
244 ret void
245 }
246
247 ; CHECK-LABEL: str_ri_t1_max
248 ; CHECK: str r1, [r0, #124]
249 define void @str_ri_t1_max(i32* %p, i32 %x) {
250 entry:
251 %arrayidx = getelementptr inbounds i32, i32* %p, i32 31
252 store i32 %x, i32* %arrayidx, align 4
253 ret void
254 }
255
256
257 ; One past maximum Thumb-1 immediate offset
258
259 ; CHECK-LABEL: ldrsb_ri_t1_too_big
260 ; CHECK-T1: movs r1, #32
261 ; CHECK-T1: ldrsb r0, [r0, r1]
262 ; CHECK-T2: ldrsb.w r0, [r0, #32]
263 define i32 @ldrsb_ri_t1_too_big(i8* %p) {
264 entry:
265 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
266 %0 = load i8, i8* %arrayidx, align 1
267 %conv = sext i8 %0 to i32
268 ret i32 %conv
269 }
270
271 ; CHECK-LABEL: ldrsh_ri_t1_too_big
272 ; CHECK-T1: movs r1, #64
273 ; CHECK-T1: ldrsh r0, [r0, r1]
274 ; CHECK-T2: ldrsh.w r0, [r0, #64]
275 define i32 @ldrsh_ri_t1_too_big(i16* %p) {
276 entry:
277 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
278 %0 = load i16, i16* %arrayidx, align 2
279 %conv = sext i16 %0 to i32
280 ret i32 %conv
281 }
282
283 ; CHECK-LABEL: ldrb_ri_t1_too_big
284 ; CHECK-T1: movs r1, #32
285 ; CHECK-T1: ldrb r0, [r0, r1]
286 ; CHECK-T2: ldrb.w r0, [r0, #32]
287 define i32 @ldrb_ri_t1_too_big(i8* %p) {
288 entry:
289 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
290 %0 = load i8, i8* %arrayidx, align 1
291 %conv = zext i8 %0 to i32
292 ret i32 %conv
293 }
294
295 ; CHECK-LABEL: ldrh_ri_t1_too_big
296 ; CHECK-T1: movs r1, #64
297 ; CHECK-T1: ldrh r0, [r0, r1]
298 ; CHECK-T2: ldrh.w r0, [r0, #64]
299 define i32 @ldrh_ri_t1_too_big(i16* %p) {
300 entry:
301 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
302 %0 = load i16, i16* %arrayidx, align 2
303 %conv = zext i16 %0 to i32
304 ret i32 %conv
305 }
306
307 ; CHECK-LABEL: ldr_ri_t1_too_big
308 ; CHECK-T1: movs r1, #128
309 ; CHECK-T1: ldr r0, [r0, r1]
310 ; CHECK-T2: ldr.w r0, [r0, #128]
311 define i32 @ldr_ri_t1_too_big(i32* %p) {
312 entry:
313 %arrayidx = getelementptr inbounds i32, i32* %p, i32 32
314 %0 = load i32, i32* %arrayidx, align 4
315 ret i32 %0
316 }
317
318 ; CHECK-LABEL: strb_ri_t1_too_big
319 ; CHECK-T1: movs r2, #32
320 ; CHECK-T1: strb r1, [r0, r2]
321 ; CHECK-T2: strb.w r1, [r0, #32]
322 define void @strb_ri_t1_too_big(i8* %p, i32 %x) {
323 entry:
324 %conv = trunc i32 %x to i8
325 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32
326 store i8 %conv, i8* %arrayidx, align 1
327 ret void
328 }
329
330 ; CHECK-LABEL: strh_ri_t1_too_big
331 ; CHECK-T1: movs r2, #64
332 ; CHECK-T1: strh r1, [r0, r2]
333 ; CHECK-T2: strh.w r1, [r0, #64]
334 define void @strh_ri_t1_too_big(i16* %p, i32 %x) {
335 entry:
336 %conv = trunc i32 %x to i16
337 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32
338 store i16 %conv, i16* %arrayidx, align 2
339 ret void
340 }
341
342 ; CHECK-LABEL: str_ri_t1_too_big
343 ; CHECK-T1: movs r2, #128
344 ; CHECK-T1: str r1, [r0, r2]
345 ; CHECK-T2: str.w r1, [r0, #128]
346 define void @str_ri_t1_too_big(i32* %p, i32 %x) {
347 entry:
348 %arrayidx = getelementptr inbounds i32, i32* %p, i32 32
349 store i32 %x, i32* %arrayidx, align 4
350 ret void
351 }
352
353
354 ; Maximum Thumb-2 immediate offset
355
356 ; CHECK-LABEL: ldrsb_ri_t2_max
357 ; CHECK-T1: ldr r1, .LCP
358 ; CHECK-T1: ldrsb r0, [r0, r1]
359 ; CHECK-T2: ldrsb.w r0, [r0, #4095]
360 define i32 @ldrsb_ri_t2_max(i8* %p) {
361 entry:
362 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
363 %0 = load i8, i8* %add.ptr, align 1
364 %conv = sext i8 %0 to i32
365 ret i32 %conv
366 }
367
368 ; CHECK-LABEL: ldrsh_ri_t2_max
369 ; CHECK-T1: ldr r1, .LCP
370 ; CHECK-T1: ldrsh r0, [r0, r1]
371 ; CHECK-T2: ldrsh.w r0, [r0, #4095]
372 define i32 @ldrsh_ri_t2_max(i8* %p) {
373 entry:
374 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
375 %0 = bitcast i8* %add.ptr to i16*
376 %1 = load i16, i16* %0, align 2
377 %conv = sext i16 %1 to i32
378 ret i32 %conv
379 }
380
381 ; CHECK-LABEL: ldrb_ri_t2_max
382 ; CHECK-T1: ldr r1, .LCP
383 ; CHECK-T1: ldrb r0, [r0, r1]
384 ; CHECK-T2: ldrb.w r0, [r0, #4095]
385 define i32 @ldrb_ri_t2_max(i8* %p) {
386 entry:
387 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
388 %0 = load i8, i8* %add.ptr, align 1
389 %conv = zext i8 %0 to i32
390 ret i32 %conv
391 }
392
393 ; CHECK-LABEL: ldrh_ri_t2_max
394 ; CHECK-T1: ldr r1, .LCP
395 ; CHECK-T1: ldrh r0, [r0, r1]
396 ; CHECK-T2: ldrh.w r0, [r0, #4095]
397 define i32 @ldrh_ri_t2_max(i8* %p) {
398 entry:
399 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
400 %0 = bitcast i8* %add.ptr to i16*
401 %1 = load i16, i16* %0, align 2
402 %conv = zext i16 %1 to i32
403 ret i32 %conv
404 }
405
406 ; CHECK-LABEL: ldr_ri_t2_max
407 ; CHECK-T1: ldr r1, .LCP
408 ; CHECK-T1: ldr r0, [r0, r1]
409 ; CHECK-T2: ldr.w r0, [r0, #4095]
410 define i32 @ldr_ri_t2_max(i8* %p) {
411 entry:
412 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
413 %0 = bitcast i8* %add.ptr to i32*
414 %1 = load i32, i32* %0, align 4
415 ret i32 %1
416 }
417
418 ; CHECK-LABEL: strb_ri_t2_max
419 ; CHECK-T1: ldr r2, .LCP
420 ; CHECK-T1: strb r1, [r0, r2]
421 ; CHECK-T2: strb.w r1, [r0, #4095]
422 define void @strb_ri_t2_max(i8* %p, i32 %x) {
423 entry:
424 %conv = trunc i32 %x to i8
425 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
426 store i8 %conv, i8* %add.ptr, align 1
427 ret void
428 }
429
430 ; CHECK-LABEL: strh_ri_t2_max
431 ; CHECK-T1: ldr r2, .LCP
432 ; CHECK-T1: strh r1, [r0, r2]
433 ; CHECK-T2: strh.w r1, [r0, #4095]
434 define void @strh_ri_t2_max(i8* %p, i32 %x) {
435 entry:
436 %conv = trunc i32 %x to i16
437 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
438 %0 = bitcast i8* %add.ptr to i16*
439 store i16 %conv, i16* %0, align 2
440 ret void
441 }
442
443 ; CHECK-LABEL: str_ri_t2_max
444 ; CHECK-T1: ldr r2, .LCP
445 ; CHECK-T1: str r1, [r0, r2]
446 ; CHECK-T2: str.w r1, [r0, #4095]
447 define void @str_ri_t2_max(i8* %p, i32 %x) {
448 entry:
449 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095
450 %0 = bitcast i8* %add.ptr to i32*
451 store i32 %x, i32* %0, align 4
452 ret void
453 }
454
455
456 ; One past maximum Thumb-2 immediate offset
457
458 ; CHECK-LABEL: ldrsb_ri_t2_too_big
459 ; CHECK-T1: movs r1, #1
460 ; CHECK-T1: lsls r1, r1, #12
461 ; CHECK-T2: mov.w r1, #4096
462 ; CHECK: ldrsb r0, [r0, r1]
463 define i32 @ldrsb_ri_t2_too_big(i8* %p) {
464 entry:
465 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
466 %0 = load i8, i8* %add.ptr, align 1
467 %conv = sext i8 %0 to i32
468 ret i32 %conv
469 }
470
471 ; CHECK-LABEL: ldrsh_ri_t2_too_big
472 ; CHECK-T1: movs r1, #1
473 ; CHECK-T1: lsls r1, r1, #12
474 ; CHECK-T2: mov.w r1, #4096
475 ; CHECK: ldrsh r0, [r0, r1]
476 define i32 @ldrsh_ri_t2_too_big(i8* %p) {
477 entry:
478 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
479 %0 = bitcast i8* %add.ptr to i16*
480 %1 = load i16, i16* %0, align 2
481 %conv = sext i16 %1 to i32
482 ret i32 %conv
483 }
484
485 ; CHECK-LABEL: ldrb_ri_t2_too_big
486 ; CHECK-T1: movs r1, #1
487 ; CHECK-T1: lsls r1, r1, #12
488 ; CHECK-T2: mov.w r1, #4096
489 ; CHECK: ldrb r0, [r0, r1]
490 define i32 @ldrb_ri_t2_too_big(i8* %p) {
491 entry:
492 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
493 %0 = load i8, i8* %add.ptr, align 1
494 %conv = zext i8 %0 to i32
495 ret i32 %conv
496 }
497
498 ; CHECK-LABEL: ldrh_ri_t2_too_big
499 ; CHECK-T1: movs r1, #1
500 ; CHECK-T1: lsls r1, r1, #12
501 ; CHECK-T2: mov.w r1, #4096
502 ; CHECK: ldrh r0, [r0, r1]
503 define i32 @ldrh_ri_t2_too_big(i8* %p) {
504 entry:
505 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
506 %0 = bitcast i8* %add.ptr to i16*
507 %1 = load i16, i16* %0, align 2
508 %conv = zext i16 %1 to i32
509 ret i32 %conv
510 }
511
512 ; CHECK-LABEL: ldr_ri_t2_too_big
513 ; CHECK-T1: movs r1, #1
514 ; CHECK-T1: lsls r1, r1, #12
515 ; CHECK-T2: mov.w r1, #4096
516 ; CHECK: ldr r0, [r0, r1]
517 define i32 @ldr_ri_t2_too_big(i8* %p) {
518 entry:
519 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
520 %0 = bitcast i8* %add.ptr to i32*
521 %1 = load i32, i32* %0, align 4
522 ret i32 %1
523 }
524
525 ; CHECK-LABEL: strb_ri_t2_too_big
526 ; CHECK-T1: movs r2, #1
527 ; CHECK-T1: lsls r2, r2, #12
528 ; CHECK-T2: mov.w r2, #4096
529 ; CHECK: strb r1, [r0, r2]
530 define void @strb_ri_t2_too_big(i8* %p, i32 %x) {
531 entry:
532 %conv = trunc i32 %x to i8
533 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
534 store i8 %conv, i8* %add.ptr, align 1
535 ret void
536 }
537
538 ; CHECK-LABEL: strh_ri_t2_too_big
539 ; CHECK-T1: movs r2, #1
540 ; CHECK-T1: lsls r2, r2, #12
541 ; CHECK-T2: mov.w r2, #4096
542 ; CHECK: strh r1, [r0, r2]
543 define void @strh_ri_t2_too_big(i8* %p, i32 %x) {
544 entry:
545 %conv = trunc i32 %x to i16
546 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
547 %0 = bitcast i8* %add.ptr to i16*
548 store i16 %conv, i16* %0, align 2
549 ret void
550 }
551
552 ; CHECK-LABEL: str_ri_t2_too_big
553 ; CHECK-T1: movs r2, #1
554 ; CHECK-T1: lsls r2, r2, #12
555 ; CHECK-T2: mov.w r2, #4096
556 ; CHECK: str r1, [r0, r2]
557 define void @str_ri_t2_too_big(i8* %p, i32 %x) {
558 entry:
559 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096
560 %0 = bitcast i8* %add.ptr to i32*
561 store i32 %x, i32* %0, align 4
562 ret void
563 }