Index: llvm/lib/Target/AArch64/AArch64InstrInfo.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -1974,17 +1974,27 @@ default: return false; case AArch64::STURSi: + case AArch64::STRSpre: case AArch64::STURDi: + case AArch64::STRDpre: case AArch64::STURQi: + case AArch64::STRQpre: case AArch64::STURBBi: case AArch64::STURHHi: case AArch64::STURWi: + case AArch64::STRWpre: case AArch64::STURXi: + case AArch64::STRXpre: case AArch64::LDURSi: + case AArch64::LDRSpre: case AArch64::LDURDi: + case AArch64::LDRDpre: case AArch64::LDURQi: + case AArch64::LDRQpre: case AArch64::LDURWi: + case AArch64::LDRWpre: case AArch64::LDURXi: + case AArch64::LDRXpre: case AArch64::LDURSWi: case AArch64::LDURHHi: case AArch64::LDURBBi: @@ -2103,15 +2113,25 @@ case AArch64::LDRSWui: // Unscaled instructions. case AArch64::STURSi: + case AArch64::STRSpre: case AArch64::STURDi: + case AArch64::STRDpre: case AArch64::STURQi: + case AArch64::STRQpre: case AArch64::STURWi: + case AArch64::STRWpre: case AArch64::STURXi: + case AArch64::STRXpre: case AArch64::LDURSi: + case AArch64::LDRSpre: case AArch64::LDURDi: + case AArch64::LDRDpre: case AArch64::LDURQi: + case AArch64::LDRQpre: case AArch64::LDURWi: + case AArch64::LDRWpre: case AArch64::LDURXi: + case AArch64::LDRXpre: case AArch64::LDURSWi: return true; } @@ -2208,23 +2228,56 @@ // Is this a candidate for ld/st merging or pairing? For example, we don't // touch volatiles or load/stores that have a hint to avoid pair formation. bool AArch64InstrInfo::isCandidateToMergeOrPair(const MachineInstr &MI) const { - // If this is a volatile load/store, don't mess with it. - if (MI.hasOrderedMemoryRef()) + + bool IsPreLd = false; + bool IsPreSt = false; + + switch (MI.getOpcode()) { + case AArch64::LDRWpre: + case AArch64::LDRXpre: + case AArch64::LDRSpre: + case AArch64::LDRDpre: + case AArch64::LDRQpre: + IsPreLd = true; + break; + case AArch64::STRWpre: + case AArch64::STRXpre: + case AArch64::STRSpre: + case AArch64::STRDpre: + case AArch64::STRQpre: + IsPreSt = true; + break; + } + + // If this is a volatile load/store + // FIXME: Ignore if the instruction is LDRpre. This is currently + // required because the "::(load x)" memory operand is missing from + // LDRpre instructions. + if (MI.hasOrderedMemoryRef() && !IsPreLd) return false; // Make sure this is a reg/fi+imm (as opposed to an address reloc). assert((MI.getOperand(1).isReg() || MI.getOperand(1).isFI()) && "Expected a reg or frame index operand."); - if (!MI.getOperand(2).isImm()) + + // For Pre-indexed addressing quadword instructions, the third operand is the + // immediate value. + bool IsImmPreLdSt = (IsPreLd || IsPreSt) && MI.getOperand(3).isImm(); + + if (!MI.getOperand(2).isImm() && !IsImmPreLdSt) return false; // Can't merge/pair if the instruction modifies the base register. // e.g., ldr x0, [x0] // This case will never occur with an FI base. + // However, if the instruction is an LDRQpre, it can be merged, e.g., + // ldr q0, [x11, #32]! + // ldr q1, [x11, #16] + // to ldp q0, q1, [x11, #32]! if (MI.getOperand(1).isReg()) { Register BaseReg = MI.getOperand(1).getReg(); const TargetRegisterInfo *TRI = &getRegisterInfo(); - if (MI.modifiesRegister(BaseReg, TRI)) + if (MI.modifiesRegister(BaseReg, TRI) && !IsPreLd) return false; } @@ -2650,14 +2703,18 @@ return 2; case AArch64::LDRSui: case AArch64::LDURSi: + case AArch64::LDRSpre: case AArch64::LDRSWui: case AArch64::LDURSWi: + case AArch64::LDRWpre: case AArch64::LDRWui: case AArch64::LDURWi: case AArch64::STRSui: case AArch64::STURSi: + case AArch64::STRSpre: case AArch64::STRWui: case AArch64::STURWi: + case AArch64::STRWpre: case AArch64::LDPSi: case AArch64::LDPSWi: case AArch64::LDPWi: @@ -2666,12 +2723,16 @@ return 4; case AArch64::LDRDui: case AArch64::LDURDi: + case AArch64::LDRDpre: case AArch64::LDRXui: case AArch64::LDURXi: + case AArch64::LDRXpre: case AArch64::STRDui: case AArch64::STURDi: + case AArch64::STRDpre: case AArch64::STRXui: case AArch64::STURXi: + case AArch64::STRXpre: case AArch64::LDPDi: case AArch64::LDPXi: case AArch64::STPDi: @@ -2681,7 +2742,9 @@ case AArch64::LDURQi: case AArch64::STRQui: case AArch64::STURQi: + case AArch64::STRQpre: case AArch64::LDPQi: + case AArch64::LDRQpre: case AArch64::STPQi: case AArch64::STGOffset: case AArch64::STZGOffset: Index: llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp +++ llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp @@ -248,28 +248,38 @@ return std::numeric_limits::max(); case AArch64::STRDui: case AArch64::STURDi: + case AArch64::STRDpre: case AArch64::STRQui: case AArch64::STURQi: + case AArch64::STRQpre: case AArch64::STRBBui: case AArch64::STURBBi: case AArch64::STRHHui: case AArch64::STURHHi: case AArch64::STRWui: + case AArch64::STRWpre: case AArch64::STURWi: case AArch64::STRXui: + case AArch64::STRXpre: case AArch64::STURXi: case AArch64::LDRDui: case AArch64::LDURDi: + case AArch64::LDRDpre: case AArch64::LDRQui: case AArch64::LDURQi: + case AArch64::LDRQpre: case AArch64::LDRWui: case AArch64::LDURWi: + case AArch64::LDRWpre: case AArch64::LDRXui: case AArch64::LDURXi: + case AArch64::LDRXpre: case AArch64::STRSui: case AArch64::STURSi: + case AArch64::STRSpre: case AArch64::LDRSui: case AArch64::LDURSi: + case AArch64::LDRSpre: return Opc; case AArch64::LDRSWui: return AArch64::LDRWui; @@ -304,33 +314,53 @@ case AArch64::STRSui: case AArch64::STURSi: return AArch64::STPSi; + case AArch64::STRSpre: + return AArch64::STPSpre; case AArch64::STRDui: case AArch64::STURDi: return AArch64::STPDi; + case AArch64::STRDpre: + return AArch64::STPDpre; case AArch64::STRQui: case AArch64::STURQi: return AArch64::STPQi; + case AArch64::STRQpre: + return AArch64::STPQpre; case AArch64::STRWui: case AArch64::STURWi: return AArch64::STPWi; + case AArch64::STRWpre: + return AArch64::STPWpre; case AArch64::STRXui: case AArch64::STURXi: return AArch64::STPXi; + case AArch64::STRXpre: + return AArch64::STPXpre; case AArch64::LDRSui: case AArch64::LDURSi: return AArch64::LDPSi; + case AArch64::LDRSpre: + return AArch64::LDPSpre; case AArch64::LDRDui: case AArch64::LDURDi: return AArch64::LDPDi; + case AArch64::LDRDpre: + return AArch64::LDPDpre; case AArch64::LDRQui: case AArch64::LDURQi: return AArch64::LDPQi; + case AArch64::LDRQpre: + return AArch64::LDPQpre; case AArch64::LDRWui: case AArch64::LDURWi: return AArch64::LDPWi; + case AArch64::LDRWpre: + return AArch64::LDPWpre; case AArch64::LDRXui: case AArch64::LDURXi: return AArch64::LDPXi; + case AArch64::LDRXpre: + return AArch64::LDPXpre; case AArch64::LDRSWui: case AArch64::LDURSWi: return AArch64::LDPSWi; @@ -539,6 +569,85 @@ } } +static bool isPairedPreLdSt(unsigned int Opc) { + switch (Opc) { + default: + return false; + case AArch64::STPSpre: + case AArch64::STPDpre: + case AArch64::STPQpre: + case AArch64::STPWpre: + case AArch64::STPXpre: + case AArch64::LDPSpre: + case AArch64::LDPDpre: + case AArch64::LDPQpre: + case AArch64::LDPWpre: + case AArch64::LDPXpre: + return true; + } +} + +static bool isPreLd(const MachineInstr &MI) { + switch (MI.getOpcode()) { + default: + return false; + case AArch64::LDRWpre: + case AArch64::LDRXpre: + case AArch64::LDRSpre: + case AArch64::LDRDpre: + case AArch64::LDRQpre: + return true; + } +} + +static bool isPreSt(const MachineInstr &MI) { + switch (MI.getOpcode()) { + default: + return false; + case AArch64::STRWpre: + case AArch64::STRXpre: + case AArch64::STRSpre: + case AArch64::STRDpre: + case AArch64::STRQpre: + return true; + } +} + +static bool isPreLdSt(const MachineInstr &MI) { + return isPreLd(MI) || isPreSt(MI); +} + +static bool isPreLdStPairCandidate(MachineInstr &FirstMI, MachineInstr &MI) { + + unsigned OpcA = FirstMI.getOpcode(); + unsigned OpcB = MI.getOpcode(); + + switch (OpcA) { + default: + return false; + case AArch64::STRSpre: + return OpcB == AArch64::STRSui; + case AArch64::STRDpre: + return OpcB == AArch64::STRDui; + case AArch64::STRQpre: + return OpcB == AArch64::STRQui; + case AArch64::STRWpre: + return OpcB == AArch64::STRWui; + case AArch64::STRXpre: + return OpcB == AArch64::STRXui; + case AArch64::LDRSpre: + return OpcB == AArch64::LDRSui; + case AArch64::LDRDpre: + return OpcB == AArch64::LDRDui; + case AArch64::LDRQpre: + return OpcB == AArch64::LDRQui; + case AArch64::LDRWpre: + return OpcB == AArch64::LDRWui; + case AArch64::LDRXpre: + return OpcB == AArch64::LDRXui; + } +} + // Returns the scale and offset range of pre/post indexed variants of MI. static void getPrePostIndexedMemOpInfo(const MachineInstr &MI, int &Scale, int &MinOffset, int &MaxOffset) { @@ -561,17 +670,20 @@ static MachineOperand &getLdStRegOp(MachineInstr &MI, unsigned PairedRegOp = 0) { assert(PairedRegOp < 2 && "Unexpected register operand idx."); - unsigned Idx = isPairedLdSt(MI) ? PairedRegOp : 0; + bool IsPreLdSt = isPreLdSt(MI); + if (IsPreLdSt) + PairedRegOp = 1; + unsigned Idx = isPairedLdSt(MI) || IsPreLdSt ? PairedRegOp : 0; return MI.getOperand(Idx); } static const MachineOperand &getLdStBaseOp(const MachineInstr &MI) { - unsigned Idx = isPairedLdSt(MI) ? 2 : 1; + unsigned Idx = isPairedLdSt(MI) || isPreLdSt(MI) ? 2 : 1; return MI.getOperand(Idx); } static const MachineOperand &getLdStOffsetOp(const MachineInstr &MI) { - unsigned Idx = isPairedLdSt(MI) ? 3 : 2; + unsigned Idx = isPairedLdSt(MI) || isPreLdSt(MI) ? 3 : 2; return MI.getOperand(Idx); } @@ -894,8 +1006,10 @@ } // Which register is Rt and which is Rt2 depends on the offset order. + // However, for pre load/stores the Rt should be the one of the pre + // load/store. MachineInstr *RtMI, *Rt2MI; - if (Offset == PairedOffset + OffsetStride) { + if (Offset == PairedOffset + OffsetStride && !isPreLdSt(*I)) { RtMI = &*Paired; Rt2MI = &*I; // Here we swapped the assumption made for SExtIdx. @@ -940,13 +1054,20 @@ MI.clearRegisterKills(Reg, TRI); } } - MIB = BuildMI(*MBB, InsertionPoint, DL, TII->get(getMatchingPairOpcode(Opc))) - .add(RegOp0) - .add(RegOp1) - .add(BaseRegOp) - .addImm(OffsetImm) - .cloneMergedMemRefs({&*I, &*Paired}) - .setMIFlags(I->mergeFlagsWith(*Paired)); + + unsigned int MatchPairOpcode = getMatchingPairOpcode(Opc); + MIB = BuildMI(*MBB, InsertionPoint, DL, TII->get(MatchPairOpcode)); + + // Adds the pre-index operand for pre-indexed ld/st pairs. + if (isPairedPreLdSt(MatchPairOpcode)) + MIB.addReg(BaseRegOp.getReg(), RegState::Define); + + MIB.add(RegOp0) + .add(RegOp1) + .add(BaseRegOp) + .addImm(OffsetImm) + .cloneMergedMemRefs({&*I, &*Paired}) + .setMIFlags(I->mergeFlagsWith(*Paired)); (void)MIB; @@ -1225,8 +1346,12 @@ return false; // We should have already checked FirstMI for pair suppression and volatility. - assert(!FirstMI.hasOrderedMemoryRef() && - !TII->isLdStPairSuppressed(FirstMI) && + // FIXME: Ignore if the instruction is LDRpre. This is currently + // required because the "::(load x)" memory operand is missing from + // LDRpre instructions. + assert(((!FirstMI.hasOrderedMemoryRef() && + !TII->isLdStPairSuppressed(FirstMI)) || + isPreLd(FirstMI)) && "FirstMI shouldn't get here if either of these checks are true."); unsigned OpcA = FirstMI.getOpcode(); @@ -1257,6 +1382,12 @@ if (isNarrowStore(OpcA) || isNarrowStore(OpcB)) return false; + // The STRpre - STRui and + // LDRpre-LDRui + // are candidate pairs that can be merged. + if (isPreLdStPairCandidate(FirstMI, MI)) + return true; + // Try to match an unscaled load/store with a scaled load/store. return TII->isUnscaledLdSt(OpcA) != TII->isUnscaledLdSt(OpcB) && getMatchingPairOpcode(OpcA) == getMatchingPairOpcode(OpcB); @@ -1517,8 +1648,31 @@ } } + // If the offset of the second ld/st is not equal to the size of the + // destination register it can’t be paired with a pre-index ld/st + // pair. Additionaly if the base reg is used or modified the operatons + // can't be paired: bail and keep looking. + if (isPreLdStPairCandidate(FirstMI, MI)) { + bool IsOutOfBounds = MIOffset != TII->getMemScale(MI); + bool IsBaseRegUsed = + !UsedRegUnits.available(getLdStBaseOp(MI).getReg()); + bool IsBaseRegModified = + !ModifiedRegUnits.available(getLdStBaseOp(MI).getReg()); + if (IsOutOfBounds || IsBaseRegUsed || IsBaseRegModified) { + LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, + TRI); + MemInsns.push_back(&MI); + continue; + } + } + + // The Offset check for isPreLdStPairCandidates is ignored because the + // only requirement is that the offset of the second ld/st instruction is + // equal to the size of the destination register, and that is checked + // above. if (BaseReg == MIBaseReg && ((Offset == MIOffset + OffsetStride) || - (Offset + OffsetStride == MIOffset))) { + (Offset + OffsetStride == MIOffset) || + isPreLdStPairCandidate(FirstMI, MI))) { int MinOffset = Offset < MIOffset ? Offset : MIOffset; if (FindNarrowMerge) { // If the alignment requirements of the scaled wide load/store Index: llvm/test/CodeGen/AArch64/arm64-memset-inline.ll =================================================================== --- llvm/test/CodeGen/AArch64/arm64-memset-inline.ll +++ llvm/test/CodeGen/AArch64/arm64-memset-inline.ll @@ -65,8 +65,8 @@ define void @bzero_8_stack() { ; CHECK-LABEL: bzero_8_stack: -; CHECK: str xzr, [sp, #8] -; CHECK-NEXT: bl something +; CHECK: stp x30, xzr, [sp, #-16]! +; CHECK: bl something %buf = alloca [8 x i8], align 1 %cast = bitcast [8 x i8]* %buf to i8* call void @llvm.memset.p0i8.i32(i8* %cast, i8 0, i32 8, i1 false) @@ -232,8 +232,8 @@ define void @memset_8_stack() { ; CHECK-LABEL: memset_8_stack: ; CHECK: mov x8, #-6148914691236517206 -; CHECK-NEXT: add x0, sp, #8 -; CHECK-NEXT: str x8, [sp, #8] +; CHECK-NEXT: stp x30, x8, [sp, #-16]! +; CHECK-NEXT: add x0, sp, #8 // =8 ; CHECK-NEXT: bl something %buf = alloca [8 x i8], align 1 %cast = bitcast [8 x i8]* %buf to i8* Index: llvm/test/CodeGen/AArch64/ldrpre-ldr-merge.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/ldrpre-ldr-merge.mir @@ -0,0 +1,133 @@ +# RUN: llc -o - %s -mtriple=aarch64-none-eabi -mcpu=cortex-a55 -lsr-preferred-addressing-mode=preindexed -stop-after=aarch64-ldst-opt | FileCheck %s + +--- +name: 1-ldrwpre-ldrwui-merge +tracksRegLiveness: true +liveins: + - { reg: '$x1' } + - { reg: '$w0' } + - { reg: '$w1' } +machineFunctionInfo: + hasRedZone: false +body: | + bb.0: + liveins: $w0, $w1, $x1 + ; CHECK-LABEL: name: 1-ldrwpre-ldrwui-merge + ; CHECK: liveins: $w0, $w1, $x1 + ; CHECK: early-clobber $x1, renamable $w0, renamable $w1 = LDPWpre renamable $x1, 5 + ; CHECK: STPWi renamable $w0, renamable $w1, renamable $x1, 0 :: (store 4) + ; CHECK: RET undef $lr + early-clobber renamable $x1, renamable $w0 = LDRWpre killed renamable $x1, 20 + renamable $w1 = LDRWui renamable $x1, 1 :: (load 4) + STRWui killed renamable $w0, renamable $x1, 0 :: (store 4) + STRWui killed renamable $w1, renamable $x1, 1 :: (store 4) + RET undef $lr +... + + +--- +name: 2-ldrxpre-ldrxui-merge +tracksRegLiveness: true +liveins: + - { reg: '$x1' } + - { reg: '$x2' } + - { reg: '$x3' } +machineFunctionInfo: + hasRedZone: false +body: | + bb.0: + liveins: $x2, $x3, $x1 + ; CHECK-LABEL: name: 2-ldrxpre-ldrxui-merge + ; CHECK: liveins: $x1, $x2, $x3 + ; CHECK: early-clobber $x1, renamable $x2, renamable $x3 = LDPXpre renamable $x1, 3 + ; CHECK: STPXi renamable $x2, renamable $x3, renamable $x1, 0 :: (store 8) + ; CHECK: RET undef $lr + early-clobber renamable $x1, renamable $x2 = LDRXpre killed renamable $x1, 24 + renamable $x3 = LDRXui renamable $x1, 1 :: (load 8) + STRXui killed renamable $x2, renamable $x1, 0 :: (store 8) + STRXui killed renamable $x3, renamable $x1, 1 :: (store 8) + RET undef $lr +... + + +--- +name: 3-ldrspre-ldrwui-merge +tracksRegLiveness: true +liveins: + - { reg: '$x1' } + - { reg: '$s0' } + - { reg: '$s1' } +machineFunctionInfo: + hasRedZone: false +body: | + bb.0: + liveins: $s0, $s1, $x1 + ; CHECK-LABEL: name: 3-ldrspre-ldrwui-merge + ; CHECK: liveins: $s0, $s1, $x1 + ; CHECK: early-clobber $x1, renamable $s0, renamable $s1 = LDPSpre renamable $x1, 3 + ; CHECK: STRSui renamable $s0, renamable $x1, 0 :: (store 4) + ; CHECK: STRSui renamable $s1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 4) + ; CHECK: RET undef $lr + early-clobber renamable $x1, renamable $s0 = LDRSpre killed renamable $x1, 12 + renamable $s1 = LDRSui renamable $x1, 1 :: (load 4) + STRSui killed renamable $s0, renamable $x1, 0 :: (store 4) + STRSui killed renamable $s1, renamable $x1, 1 :: (store 4) + RET undef $lr +... + + + + +--- +name: 4-ldrqdre-ldrdui-merge +tracksRegLiveness: true +liveins: + - { reg: '$x1' } + - { reg: '$d0' } + - { reg: '$d1' } +machineFunctionInfo: + hasRedZone: false +body: | + bb.0: + liveins: $d0, $d1, $x1 + ; CHECK-LABEL: name: 4-ldrqdre-ldrdui-merge + ; CHECK: liveins: $d0, $d1, $x1 + ; CHECK: early-clobber $x1, renamable $d0, renamable $d1 = LDPDpre renamable $x1, 16 + ; CHECK: STRDui renamable $d0, renamable $x1, 0 :: (store 8) + ; CHECK: STRDui renamable $d1, renamable $x1, 1 :: ("aarch64-suppress-pair" store 8) + ; CHECK: RET undef $lr + early-clobber renamable $x1, renamable $d0 = LDRDpre killed renamable $x1, 128 + renamable $d1 = LDRDui renamable $x1, 1 :: (load 8) + STRDui killed renamable $d0, renamable $x1, 0 :: (store 8) + STRDui killed renamable $d1, renamable $x1, 1 :: (store 8) + RET undef $lr +... + + +--- +name: 5-ldrqpre-ldrqui-merge +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$x1' } + - { reg: '$q0' } + - { reg: '$q1' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: + hasRedZone: false +body: | + bb.0: + liveins: $q0, $q1, $x1 + ; CHECK-LABEL: name: 5-ldrqpre-ldrqui-merge + ; CHECK: liveins: $q0, $q1, $x1 + ; CHECK: early-clobber $x1, renamable $q0, renamable $q1 = LDPQpre renamable $x1, 3 + ; CHECK: STPQi renamable $q0, renamable $q1, renamable $x1, 0 :: (store 16) + ; CHECK: RET undef $lr + early-clobber renamable $x1, renamable $q0 = LDRQpre killed renamable $x1, 48 + renamable $q1 = LDRQui renamable $x1, 1 :: (load 16) + STRQui killed renamable $q0, renamable $x1, 0 :: (store 16) + STRQui killed renamable $q1, renamable $x1, 1 :: (store 16) + RET undef $lr +... Index: llvm/test/CodeGen/AArch64/strpre-str-merge.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/strpre-str-merge.mir @@ -0,0 +1,136 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -o - %s -mtriple=aarch64-none-eabi -mcpu=cortex-a55 -lsr-preferred-addressing-mode=preindexed -stop-after=aarch64-ldst-opt | FileCheck %s + +--- +name: 1-strwpre-strwui-merge +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$x0' } + - { reg: '$w1' } + - { reg: '$w2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: + hasRedZone: false +body: | + bb.0.entry: + liveins: $w1, $w2, $x0 + ; CHECK-LABEL: name: 1-strwpre-strwui-merge + ; CHECK: liveins: $w1, $w2, $x0 + ; CHECK: early-clobber $x0 = STPWpre renamable $w1, renamable $w2, renamable $x0, 5 :: (store 4) + ; CHECK: RET undef $lr, implicit $x0 + early-clobber renamable $x0 = STRWpre killed renamable $w1, killed renamable $x0, 20 :: (store 4) + STRWui killed renamable $w2, renamable $x0, 1 :: (store 4) + RET undef $lr, implicit $x0 + +... + + +--- +name: 2-strxpre-strxui-merge +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$x0' } + - { reg: '$x1' } + - { reg: '$x2' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: + hasRedZone: false +body: | + bb.0.entry: + liveins: $x0, $x1, $x2 + + ; CHECK-LABEL: name: 2-strxpre-strxui-merge + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK: early-clobber $x0 = STPXpre renamable $x1, renamable $x2, renamable $x0, 3 :: (store 8) + ; CHECK: RET undef $lr, implicit $x0 + early-clobber renamable $x0 = STRXpre killed renamable $x1, killed renamable $x0, 24 :: (store 8) + STRXui killed renamable $x2, renamable $x0, 1 :: (store 8) + RET undef $lr, implicit $x0 + +... + + +--- +name: 3-strspre-strsui-merge +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$x0' } + - { reg: '$s0' } + - { reg: '$s1' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: + hasRedZone: false +body: | + bb.0.entry: + liveins: $s0, $s1, $x0 + ; CHECK-LABEL: name: 3-strspre-strsui-merge + ; CHECK: liveins: $s0, $s1, $x0 + ; CHECK: early-clobber $x0 = STPSpre renamable $s0, renamable $s1, renamable $x0, 3 :: (store 4) + ; CHECK: RET undef $lr, implicit $x0 + early-clobber renamable $x0 = STRSpre killed renamable $s0, killed renamable $x0, 12 :: (store 4) + STRSui killed renamable $s1, renamable $x0, 1 :: (store 4) + RET undef $lr, implicit $x0 +... + +--- +name: 4-strdpre-strdui-merge +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$x0' } + - { reg: '$d0' } + - { reg: '$d1' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: + hasRedZone: false +body: | + bb.0.entry: + liveins: $d0, $d1, $x0 + + ; CHECK-LABEL: name: 4-strdpre-strdui-merge + ; CHECK: liveins: $d0, $d1, $x0 + ; CHECK: early-clobber $x0 = STPDpre renamable $d0, renamable $d1, renamable $x0, 16 :: (store 8) + ; CHECK: RET undef $lr, implicit $x0 + early-clobber renamable $x0 = STRDpre killed renamable $d0, killed renamable $x0, 128 :: (store 8) + STRDui killed renamable $d1, renamable $x0, 1 :: (store 8) + RET undef $lr, implicit $x0 + +... + +--- +name: 5-strqpre-strqui-merge +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$x0' } + - { reg: '$q0' } + - { reg: '$q1' } +frameInfo: + maxAlignment: 1 + maxCallFrameSize: 0 +machineFunctionInfo: + hasRedZone: false +body: | + bb.0.entry: + liveins: $q0, $q1, $x0 + + ; CHECK-LABEL: name: 5-strqpre-strqui-merge + ; CHECK: liveins: $q0, $q1, $x0 + ; CHECK: early-clobber $x0 = STPQpre renamable $q0, renamable $q1, renamable $x0, 3 :: (store 16) + ; CHECK: RET undef $lr, implicit $x0 + early-clobber renamable $x0 = STRQpre killed renamable $q0, killed renamable $x0, 48 :: (store 16) + STRQui killed renamable $q1, renamable $x0, 1 :: (store 16) + RET undef $lr, implicit $x0 + +...