blob: 89d9878fa48ee500a35b2d58ca5d78c35ccb7be5 [file] [log] [blame]
commit b53cac3143c4b284634bbe1b5370e56ecc99950d
Author: Victor Campos <victor.campos@arm.com>
Date: Fri May 22 10:03:18 2020 +0100
Revert "[ARM] Improve codegen of volatile load/store of i64"
This reverts commit 8a12553223180246eeafaa0fa7bfa11e834d34b6.
A bug has been found when generating code for Thumb2. In some very
specific cases, the prologue/epilogue emitter generates erroneous stack
offsets for the new LDRD instructions that access the stack.
This bug does not seem to be caused by the reverted patch though. Likely
the latter has made an undiscovered issue emerge in the
prologue/epilogue emission pass. Nevertheless, this reversion is
necessary since it is blocking users of the ARM backend.
diff --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
index 4dcb1f62577..25eabf53dee 100644
--- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -1955,24 +1955,6 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
MI.eraseFromParent();
return true;
}
- case ARM::LOADDUAL:
- case ARM::STOREDUAL: {
- Register PairReg = MI.getOperand(0).getReg();
-
- MachineInstrBuilder MIB =
- BuildMI(MBB, MBBI, MI.getDebugLoc(),
- TII->get(Opcode == ARM::LOADDUAL ? ARM::LDRD : ARM::STRD))
- .addReg(TRI->getSubReg(PairReg, ARM::gsub_0),
- Opcode == ARM::LOADDUAL ? RegState::Define : 0)
- .addReg(TRI->getSubReg(PairReg, ARM::gsub_1),
- Opcode == ARM::LOADDUAL ? RegState::Define : 0);
- for (unsigned i = 1; i < MI.getNumOperands(); i++)
- MIB.add(MI.getOperand(i));
- MIB.add(predOps(ARMCC::AL));
- MIB.cloneMemRefs(MI);
- MI.eraseFromParent();
- return true;
- }
}
}
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 6be6f5da637..a5f7d635a28 100644
--- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -145,8 +145,6 @@ public:
// Thumb 2 Addressing Modes:
bool SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
- template <unsigned Shift>
- bool SelectT2AddrModeImm8(SDValue N, SDValue &Base, SDValue &OffImm);
bool SelectT2AddrModeImm8(SDValue N, SDValue &Base,
SDValue &OffImm);
bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
@@ -1305,33 +1303,6 @@ bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N,
return true;
}
-template <unsigned Shift>
-bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N, SDValue &Base,
- SDValue &OffImm) {
- if (N.getOpcode() == ISD::SUB || CurDAG->isBaseWithConstantOffset(N)) {
- int RHSC;
- if (isScaledConstantInRange(N.getOperand(1), 1 << Shift, -255, 256, RHSC)) {
- Base = N.getOperand(0);
- if (Base.getOpcode() == ISD::FrameIndex) {
- int FI = cast<FrameIndexSDNode>(Base)->getIndex();
- Base = CurDAG->getTargetFrameIndex(
- FI, TLI->getPointerTy(CurDAG->getDataLayout()));
- }
-
- if (N.getOpcode() == ISD::SUB)
- RHSC = -RHSC;
- OffImm =
- CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32);
- return true;
- }
- }
-
- // Base only.
- Base = N;
- OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
- return true;
-}
-
bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N,
SDValue &Base, SDValue &OffImm) {
// Match simple R - imm8 operands.
@@ -3612,59 +3583,6 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
CurDAG->RemoveDeadNode(N);
return;
}
- case ARMISD::LDRD: {
- if (Subtarget->isThumb2())
- break; // TableGen handles isel in this case.
- SDValue Base, RegOffset, ImmOffset;
- const SDValue &Chain = N->getOperand(0);
- const SDValue &Addr = N->getOperand(1);
- SelectAddrMode3(Addr, Base, RegOffset, ImmOffset);
- if (RegOffset != CurDAG->getRegister(0, MVT::i32)) {
- // The register-offset variant of LDRD mandates that the register
- // allocated to RegOffset is not reused in any of the remaining operands.
- // This restriction is currently not enforced. Therefore emitting this
- // variant is explicitly avoided.
- Base = Addr;
- RegOffset = CurDAG->getRegister(0, MVT::i32);
- }
- SDValue Ops[] = {Base, RegOffset, ImmOffset, Chain};
- SDNode *New = CurDAG->getMachineNode(ARM::LOADDUAL, dl,
- {MVT::Untyped, MVT::Other}, Ops);
- SDValue Lo = CurDAG->getTargetExtractSubreg(ARM::gsub_0, dl, MVT::i32,
- SDValue(New, 0));
- SDValue Hi = CurDAG->getTargetExtractSubreg(ARM::gsub_1, dl, MVT::i32,
- SDValue(New, 0));
- transferMemOperands(N, New);
- ReplaceUses(SDValue(N, 0), Lo);
- ReplaceUses(SDValue(N, 1), Hi);
- ReplaceUses(SDValue(N, 2), SDValue(New, 1));
- CurDAG->RemoveDeadNode(N);
- return;
- }
- case ARMISD::STRD: {
- if (Subtarget->isThumb2())
- break; // TableGen handles isel in this case.
- SDValue Base, RegOffset, ImmOffset;
- const SDValue &Chain = N->getOperand(0);
- const SDValue &Addr = N->getOperand(3);
- SelectAddrMode3(Addr, Base, RegOffset, ImmOffset);
- if (RegOffset != CurDAG->getRegister(0, MVT::i32)) {
- // The register-offset variant of STRD mandates that the register
- // allocated to RegOffset is not reused in any of the remaining operands.
- // This restriction is currently not enforced. Therefore emitting this
- // variant is explicitly avoided.
- Base = Addr;
- RegOffset = CurDAG->getRegister(0, MVT::i32);
- }
- SDNode *RegPair =
- createGPRPairNode(MVT::Untyped, N->getOperand(1), N->getOperand(2));
- SDValue Ops[] = {SDValue(RegPair, 0), Base, RegOffset, ImmOffset, Chain};
- SDNode *New = CurDAG->getMachineNode(ARM::STOREDUAL, dl, MVT::Other, Ops);
- transferMemOperands(N, New);
- ReplaceUses(SDValue(N, 0), SDValue(New, 0));
- CurDAG->RemoveDeadNode(N);
- return;
- }
case ARMISD::LOOP_DEC: {
SDValue Ops[] = { N->getOperand(1),
N->getOperand(2),
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 858ea884316..0a0caefd9b8 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1074,8 +1074,6 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SRA, MVT::i64, Custom);
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom);
- setOperationAction(ISD::LOAD, MVT::i64, Custom);
- setOperationAction(ISD::STORE, MVT::i64, Custom);
// MVE lowers 64 bit shifts to lsll and lsrl
// assuming that ISD::SRL and SRA of i64 are already marked custom
@@ -1613,9 +1611,6 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::PRELOAD: return "ARMISD::PRELOAD";
- case ARMISD::LDRD: return "ARMISD::LDRD";
- case ARMISD::STRD: return "ARMISD::STRD";
-
case ARMISD::WIN__CHKSTK: return "ARMISD::WIN__CHKSTK";
case ARMISD::WIN__DBZCHK: return "ARMISD::WIN__DBZCHK";
@@ -9115,25 +9110,6 @@ static SDValue LowerPredicateLoad(SDValue Op, SelectionDAG &DAG) {
return DAG.getMergeValues({Pred, Load.getValue(1)}, dl);
}
-void ARMTargetLowering::LowerLOAD(SDNode *N, SmallVectorImpl<SDValue> &Results,
- SelectionDAG &DAG) const {
- LoadSDNode *LD = cast<LoadSDNode>(N);
- EVT MemVT = LD->getMemoryVT();
- assert(LD->isUnindexed() && "Loads should be unindexed at this point.");
-
- if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() &&
- !Subtarget->isThumb1Only() && LD->isVolatile()) {
- SDLoc dl(N);
- SDValue Result = DAG.getMemIntrinsicNode(
- ARMISD::LDRD, dl, DAG.getVTList({MVT::i32, MVT::i32, MVT::Other}),
- {LD->getChain(), LD->getBasePtr()}, MemVT, LD->getMemOperand());
- SDValue Lo = Result.getValue(DAG.getDataLayout().isLittleEndian() ? 0 : 1);
- SDValue Hi = Result.getValue(DAG.getDataLayout().isLittleEndian() ? 1 : 0);
- SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi);
- Results.append({Pair, Result.getValue(2)});
- }
-}
-
static SDValue LowerPredicateStore(SDValue Op, SelectionDAG &DAG) {
StoreSDNode *ST = cast<StoreSDNode>(Op.getNode());
EVT MemVT = ST->getMemoryVT();
@@ -9163,38 +9139,6 @@ static SDValue LowerPredicateStore(SDValue Op, SelectionDAG &DAG) {
ST->getMemOperand());
}
-static SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG,
- const ARMSubtarget *Subtarget) {
- StoreSDNode *ST = cast<StoreSDNode>(Op.getNode());
- EVT MemVT = ST->getMemoryVT();
- assert(ST->isUnindexed() && "Stores should be unindexed at this point.");
-
- if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() &&
- !Subtarget->isThumb1Only() && ST->isVolatile()) {
- SDNode *N = Op.getNode();
- SDLoc dl(N);
-
- SDValue Lo = DAG.getNode(
- ISD::EXTRACT_ELEMENT, dl, MVT::i32, ST->getValue(),
- DAG.getTargetConstant(DAG.getDataLayout().isLittleEndian() ? 0 : 1, dl,
- MVT::i32));
- SDValue Hi = DAG.getNode(
- ISD::EXTRACT_ELEMENT, dl, MVT::i32, ST->getValue(),
- DAG.getTargetConstant(DAG.getDataLayout().isLittleEndian() ? 1 : 0, dl,
- MVT::i32));
-
- return DAG.getMemIntrinsicNode(ARMISD::STRD, dl, DAG.getVTList(MVT::Other),
- {ST->getChain(), Lo, Hi, ST->getBasePtr()},
- MemVT, ST->getMemOperand());
- } else if (Subtarget->hasMVEIntegerOps() &&
- ((MemVT == MVT::v4i1 || MemVT == MVT::v8i1 ||
- MemVT == MVT::v16i1))) {
- return LowerPredicateStore(Op, DAG);
- }
-
- return SDValue();
-}
-
static bool isZeroVector(SDValue N) {
return (ISD::isBuildVectorAllZeros(N.getNode()) ||
(N->getOpcode() == ARMISD::VMOVIMM &&
@@ -9428,7 +9372,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::LOAD:
return LowerPredicateLoad(Op, DAG);
case ISD::STORE:
- return LowerSTORE(Op, DAG, Subtarget);
+ return LowerPredicateStore(Op, DAG);
case ISD::MLOAD:
return LowerMLOAD(Op, DAG);
case ISD::ATOMIC_LOAD:
@@ -9532,9 +9476,7 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N,
case ISD::ABS:
lowerABS(N, Results, DAG);
return ;
- case ISD::LOAD:
- LowerLOAD(N, Results, DAG);
- break;
+
}
if (Res.getNode())
Results.push_back(Res);
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index 99694cd9e03..7042962d259 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -295,11 +295,7 @@ class VectorType;
VST4_UPD,
VST2LN_UPD,
VST3LN_UPD,
- VST4LN_UPD,
-
- // Load/Store of dual registers
- LDRD,
- STRD
+ VST4LN_UPD
};
} // end namespace ARMISD
@@ -763,8 +759,6 @@ class VectorType;
SDValue LowerFSETCC(SDValue Op, SelectionDAG &DAG) const;
void lowerABS(SDNode *N, SmallVectorImpl<SDValue> &Results,
SelectionDAG &DAG) const;
- void LowerLOAD(SDNode *N, SmallVectorImpl<SDValue> &Results,
- SelectionDAG &DAG) const;
Register getRegisterByName(const char* RegName, LLT VT,
const MachineFunction &MF) const override;
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index b006b5e7e08..9e491e726b4 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -243,12 +243,6 @@ def ARMqsub8b : SDNode<"ARMISD::QSUB8b", SDT_ARMAnd, []>;
def ARMqadd16b : SDNode<"ARMISD::QADD16b", SDT_ARMAnd, []>;
def ARMqsub16b : SDNode<"ARMISD::QSUB16b", SDT_ARMAnd, []>;
-def SDT_ARMldrd : SDTypeProfile<2, 1, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>;
-def ARMldrd : SDNode<"ARMISD::LDRD", SDT_ARMldrd, [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
-
-def SDT_ARMstrd : SDTypeProfile<0, 3, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>;
-def ARMstrd : SDNode<"ARMISD::STRD", SDT_ARMstrd, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
-
// Vector operations shared between NEON and MVE
def ARMvdup : SDNode<"ARMISD::VDUP", SDTypeProfile<1, 1, [SDTCisVec<0>]>>;
@@ -2735,14 +2729,6 @@ let mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1 in {
Requires<[IsARM, HasV5TE]>;
}
-let mayLoad = 1, hasSideEffects = 0, hasNoSchedulingInfo = 1 in {
-def LOADDUAL : ARMPseudoInst<(outs GPRPairOp:$Rt), (ins addrmode3:$addr),
- 64, IIC_iLoad_d_r, []>,
- Requires<[IsARM, HasV5TE]> {
- let AM = AddrMode3;
-}
-}
-
def LDA : AIldracq<0b00, (outs GPR:$Rt), (ins addr_offset_none:$addr),
NoItinerary, "lda", "\t$Rt, $addr", []>;
def LDAB : AIldracq<0b10, (outs GPR:$Rt), (ins addr_offset_none:$addr),
@@ -3018,14 +3004,6 @@ let mayStore = 1, hasSideEffects = 0, hasExtraSrcRegAllocReq = 1 in {
}
}
-let mayStore = 1, hasSideEffects = 0, hasNoSchedulingInfo = 1 in {
-def STOREDUAL : ARMPseudoInst<(outs), (ins GPRPairOp:$Rt, addrmode3:$addr),
- 64, IIC_iStore_d_r, []>,
- Requires<[IsARM, HasV5TE]> {
- let AM = AddrMode3;
-}
-}
-
// Indexed stores
multiclass AI2_stridx<bit isByte, string opc,
InstrItinClass iii, InstrItinClass iir> {
diff --git a/llvm/lib/Target/ARM/ARMInstrThumb2.td b/llvm/lib/Target/ARM/ARMInstrThumb2.td
index d69526b32c7..c6e2e04965d 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb2.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb2.td
@@ -270,8 +270,7 @@ def t2am_imm8_offset : MemOperand,
// t2addrmode_imm8s4 := reg +/- (imm8 << 2)
def MemImm8s4OffsetAsmOperand : AsmOperandClass {let Name = "MemImm8s4Offset";}
-class T2AddrMode_Imm8s4 : MemOperand,
- ComplexPattern<i32, 2, "SelectT2AddrModeImm8<2>", []> {
+class T2AddrMode_Imm8s4 : MemOperand {
let EncoderMethod = "getT2AddrModeImm8s4OpValue";
let DecoderMethod = "DecodeT2AddrModeImm8s4";
let ParserMatchClass = MemImm8s4OffsetAsmOperand;
@@ -1449,8 +1448,7 @@ let mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1 in {
// Load doubleword
def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs rGPR:$Rt, rGPR:$Rt2),
(ins t2addrmode_imm8s4:$addr),
- IIC_iLoad_d_i, "ldrd", "\t$Rt, $Rt2, $addr", "",
- [(set rGPR:$Rt, rGPR:$Rt2, (ARMldrd t2addrmode_imm8s4:$addr))]>,
+ IIC_iLoad_d_i, "ldrd", "\t$Rt, $Rt2, $addr", "", []>,
Sched<[WriteLd]>;
} // mayLoad = 1, hasSideEffects = 0, hasExtraDefRegAllocReq = 1
@@ -1631,8 +1629,7 @@ defm t2STRH:T2I_st<0b01,"strh", IIC_iStore_bh_i, IIC_iStore_bh_si,
let mayStore = 1, hasSideEffects = 0, hasExtraSrcRegAllocReq = 1 in
def t2STRDi8 : T2Ii8s4<1, 0, 0, (outs),
(ins rGPR:$Rt, rGPR:$Rt2, t2addrmode_imm8s4:$addr),
- IIC_iStore_d_r, "strd", "\t$Rt, $Rt2, $addr", "",
- [(ARMstrd rGPR:$Rt, rGPR:$Rt2, t2addrmode_imm8s4:$addr)]>,
+ IIC_iStore_d_r, "strd", "\t$Rt, $Rt2, $addr", "", []>,
Sched<[WriteST]>;
// Indexed stores
diff --git a/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll b/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll
deleted file mode 100644
index e025c854409..00000000000
--- a/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll
+++ /dev/null
@@ -1,183 +0,0 @@
-; RUN: llc -mtriple=armv5e-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-ARMV5TE,CHECK
-; RUN: llc -mtriple=thumbv6t2-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-T2,CHECK
-; RUN: llc -mtriple=armv4t-arm-none-eabi %s -o - | FileCheck %s --check-prefixes=CHECK-ARMV4T,CHECK
-
-@x = common dso_local global i64 0, align 8
-@y = common dso_local global i64 0, align 8
-
-define void @test() {
-entry:
-; CHECK-LABEL: test:
-; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x
-; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y
-; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x
-; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y
-; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-T2-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], {{\[}}[[ADDR0]], #4]
-; CHECK-ARMV4T-NEXT: str [[R0]], {{\[}}[[ADDR1]], #4]
-; CHECK-ARMV4T-NEXT: str [[R1]], {{\[}}[[ADDR1]]]
- %0 = load volatile i64, i64* @x, align 8
- store volatile i64 %0, i64* @y, align 8
- ret void
-}
-
-define void @test_offset() {
-entry:
-; CHECK-LABEL: test_offset:
-; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #-4]
-; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]], #-4]
-; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x
-; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y
-; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x
-; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y
-; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #-4]
-; CHECK-T2-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]], #-4]
-; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], {{\[}}[[ADDR0]], #-4]
-; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-ARMV4T-NEXT: str [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-ARMV4T-NEXT: str [[R0]], {{\[}}[[ADDR1]], #-4]
- %0 = load volatile i64, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @x to i8*), i32 -4) to i64*), align 8
- store volatile i64 %0, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @y to i8*), i32 -4) to i64*), align 8
- ret void
-}
-
-define void @test_offset_1() {
-; CHECK-LABEL: test_offset_1:
-; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #255]
-; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]], #255]
-; CHECK-T2: adds [[ADDR0:r[0-9]+]], #255
-; CHECK-T2-NEXT: adds [[ADDR1:r[0-9]+]], #255
-; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-T2-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], {{\[}}[[ADDR0]], #255]
-; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #259]
-; CHECK-ARMV4T-NEXT: str [[R1]], {{\[}}[[ADDR1]], #259]
-; CHECK-ARMV4T-NEXT: str [[R0]], {{\[}}[[ADDR1]], #255]
-entry:
- %0 = load volatile i64, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @x to i8*), i32 255) to i64*), align 8
- store volatile i64 %0, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @y to i8*), i32 255) to i64*), align 8
- ret void
-}
-
-define void @test_offset_2() {
-; CHECK-LABEL: test_offset_2:
-; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: add [[ADDR0]], [[ADDR0]], #256
-; CHECK-ARMV5TE-NEXT: add [[ADDR1]], [[ADDR1]], #256
-; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x
-; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y
-; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x
-; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y
-; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #256]
-; CHECK-T2-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]], #256]
-; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], {{\[}}[[ADDR0]], #256]
-; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #260]
-; CHECK-ARMV4T-NEXT: str [[R1]], {{\[}}[[ADDR1]], #260]
-; CHECK-ARMV4T-NEXT: str [[R0]], {{\[}}[[ADDR1]], #256]
-entry:
- %0 = load volatile i64, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @x to i8*), i32 256) to i64*), align 8
- store volatile i64 %0, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @y to i8*), i32 256) to i64*), align 8
- ret void
-}
-
-define void @test_offset_3() {
-; CHECK-LABEL: test_offset_3:
-; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: add [[ADDR0]], [[ADDR0]], #1020
-; CHECK-ARMV5TE-NEXT: add [[ADDR1]], [[ADDR1]], #1020
-; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-T2: movw [[ADDR0:r[0-9]+]], :lower16:x
-; CHECK-T2-NEXT: movw [[ADDR1:r[0-9]+]], :lower16:y
-; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x
-; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y
-; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #1020]
-; CHECK-T2-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]], #1020]
-; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], {{\[}}[[ADDR0]], #1020]
-; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #1024]
-; CHECK-ARMV4T-NEXT: str [[R1]], {{\[}}[[ADDR1]], #1024]
-; CHECK-ARMV4T-NEXT: str [[R0]], {{\[}}[[ADDR1]], #1020]
-entry:
- %0 = load volatile i64, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @x to i8*), i32 1020) to i64*), align 8
- store volatile i64 %0, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @y to i8*), i32 1020) to i64*), align 8
- ret void
-}
-
-define void @test_offset_4() {
-; CHECK-LABEL: test_offset_4:
-; CHECK-ARMV5TE: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV5TE: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV5TE-NEXT: add [[ADDR0]], [[ADDR0]], #1024
-; CHECK-ARMV5TE-NEXT: add [[ADDR1]], [[ADDR1]], #1024
-; CHECK-ARMV5TE-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-ARMV5TE-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-T2: movw [[ADDR1:r[0-9]+]], :lower16:y
-; CHECK-T2-NEXT: movw [[ADDR0:r[0-9]+]], :lower16:x
-; CHECK-T2-NEXT: movt [[ADDR1]], :upper16:y
-; CHECK-T2-NEXT: movt [[ADDR0]], :upper16:x
-; CHECK-T2-NEXT: add.w [[ADDR0]], [[ADDR0]], #1024
-; CHECK-T2-NEXT: add.w [[ADDR1]], [[ADDR1]], #1024
-; CHECK-T2-NEXT: ldrd [[R0:r[0-9]+]], [[R1:r[0-9]+]], {{\[}}[[ADDR0]]]
-; CHECK-T2-NEXT: strd [[R0]], [[R1]], {{\[}}[[ADDR1]]]
-; CHECK-ARMV4T: ldr [[ADDR0:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[ADDR1:r[0-9]+]]
-; CHECK-ARMV4T-NEXT: ldr [[R0:r[0-9]+]], {{\[}}[[ADDR0]], #1024]
-; CHECK-ARMV4T-NEXT: ldr [[R1:r[0-9]+]], {{\[}}[[ADDR0]], #1028]
-; CHECK-ARMV4T-NEXT: str [[R1]], {{\[}}[[ADDR1]], #1028]
-; CHECK-ARMV4T-NEXT: str [[R0]], {{\[}}[[ADDR1]], #1024]
-entry:
- %0 = load volatile i64, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @x to i8*), i32 1024) to i64*), align 8
- store volatile i64 %0, i64* bitcast (i8* getelementptr (i8, i8* bitcast (i64* @y to i8*), i32 1024) to i64*), align 8
- ret void
-}
-
-define void @test_stack() {
-; CHECK-LABEL: test_stack:
-; CHECK-ARMV5TE: sub sp, sp, #8
-; CHECK-ARMV5TE-NEXT: mov r1, #0
-; CHECK-ARMV5TE-NEXT: mov r0, #5
-; CHECK-ARMV5TE-NEXT: strd r0, r1, [sp]
-; CHECK-ARMV5TE-NEXT: ldrd r0, r1, [sp]
-; CHECK-T2: sub sp, #8
-; CHECK-T2-NEXT: mov r0, sp
-; CHECK-T2-NEXT: movs r1, #0
-; CHECK-T2-NEXT: movs r2, #5
-; CHECK-T2-NEXT: strd r2, r1, [r0]
-; CHECK-T2-NEXT: ldrd r0, r1, [r0]
-; CHECK-ARMV4T: sub sp, sp, #8
-; CHECK-ARMV4T-NEXT: mov r0, #0
-; CHECK-ARMV4T-NEXT: str r0, [sp, #4]
-; CHECK-ARMV4T-NEXT: mov r0, #5
-; CHECK-ARMV4T-NEXT: str r0, [sp]
-; CHECK-ARMV4T-NEXT: ldr r0, [sp]
-; CHECK-ARMV4T-NEXT: ldr r0, [sp, #4]
-entry:
- %0 = alloca i64
- store volatile i64 5, i64* %0
- %1 = load volatile i64, i64* %0
- ret void
-}