[llvm] [AArch64MIPeepholeOpt] Coalesce sibling base-address materializations (PR #223682)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 04:15:13 PDT 2026


https://github.com/whokeke updated https://github.com/llvm/llvm-project/pull/223682

>From f859df9106126c9ecab3f6a41db392b8a28f3cec Mon Sep 17 00:00:00 2001
From: whoiskk <hukeke2 at huawei.com>
Date: Fri, 31 Jul 2026 05:02:44 +0800
Subject: [PATCH] [AArch64MIPeepholeOpt] Coalesce sibling base-address
 materializations

ISel materializes an independent SUBXri/ADDXri base for each negative
far-offset load/store whose offset falls outside LDUR's 9-bit signed
range, giving the accesses different base registers and preventing the
LoadStoreOptimizer from pairing them into LDP/STP.

Add AArch64MIPeepholeOpt::shareBaseAddresses, which coalesces sibling
single-use ADDXri/SUBXri (shift 0) materializations feeding scaled
LDRui/STRui within a basic block. The minimum-offset materialization
becomes the primary; each secondary load/store is rewritten to use it
with an adjusted scaled offset and its def is erased, restoring a
shared base so the LoadStoreOptimizer can pair the accesses. Gated by
-aarch64-base-address-cse (default on); runs pre-RA on SSA form, so
no register scavenger is needed.

Test: base-address-cse.mir (pass-level SHARED/NOBASECSE),
      base-address-cse.ll (end-to-end i32/i64/Q load + store,
      large offset, ENABLED vs NOBASECSE)
---
 .../Target/AArch64/AArch64MIPeepholeOpt.cpp   | 118 ++++++++++
 llvm/test/CodeGen/AArch64/base-address-cse.ll | 207 ++++++++++++++++++
 .../test/CodeGen/AArch64/base-address-cse.mir | 132 +++++++++++
 3 files changed, 457 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/base-address-cse.ll
 create mode 100644 llvm/test/CodeGen/AArch64/base-address-cse.mir

diff --git a/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp b/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
index 9b42f535ae232..740296735312d 100644
--- a/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
@@ -72,13 +72,20 @@
 #include "AArch64ExpandImm.h"
 #include "AArch64InstrInfo.h"
 #include "MCTargetDesc/AArch64AddressingModes.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/CodeGen/MachineDominators.h"
 #include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/Support/CommandLine.h"
 
 using namespace llvm;
 
 #define DEBUG_TYPE "aarch64-mi-peephole-opt"
 
+static cl::opt<bool> EnableBaseAddressCSE(
+    "aarch64-base-address-cse", cl::init(true), cl::Hidden,
+    cl::desc("Coalesce sibling base-address materializations to enable "
+             "LDP/STP pairing"));
+
 namespace {
 
 class AArch64MIPeepholeOptImpl {
@@ -143,6 +150,8 @@ class AArch64MIPeepholeOptImpl {
   bool visitFMOVDr(MachineInstr &MI);
   bool visitUBFMXri(MachineInstr &MI);
   bool visitCopy(MachineInstr &MI);
+
+  bool shareBaseAddresses(MachineBasicBlock &MBB);
 };
 
 struct AArch64MIPeepholeOptLegacy : public MachineFunctionPass {
@@ -957,6 +966,114 @@ bool AArch64MIPeepholeOptImpl::visitCopy(MachineInstr &MI) {
   return true;
 }
 
+bool AArch64MIPeepholeOptImpl::shareBaseAddresses(MachineBasicBlock &MBB) {
+  if (!EnableBaseAddressCSE)
+    return false;
+
+  bool Changed = false;
+
+  struct Cand {
+    MachineInstr *DefMI;
+    Register SrcReg;
+    unsigned Opc;
+    int64_t C;
+    Register BaseReg;
+    MachineInstr *UserMI;
+    int Scale;
+    int64_t OldOff;
+  };
+  SmallVector<Cand, 8> Cands;
+  using Key = std::pair<Register, unsigned>;
+  MapVector<Key, SmallVector<unsigned, 4>> Groups;
+
+  DenseMap<MachineInstr *, unsigned> Pos;
+  unsigned Idx = 0;
+  for (MachineInstr &MI : MBB.instrs()) {
+    Pos[&MI] = Idx++;
+    unsigned Opc = MI.getOpcode();
+    if (Opc != AArch64::ADDXri && Opc != AArch64::SUBXri)
+      continue;
+    if (!MI.getOperand(2).isImm() || !MI.getOperand(3).isImm() ||
+        MI.getOperand(3).getImm() != 0) // shift must be 0 (no LSL #12)
+      continue;
+    if (!MI.getOperand(0).isReg() || !MI.getOperand(1).isReg())
+      continue;
+    Register SrcReg = MI.getOperand(1).getReg();
+    Register BaseReg = MI.getOperand(0).getReg();
+    if (!SrcReg.isVirtual() || !BaseReg.isVirtual() ||
+        !MRI->hasOneUse(BaseReg)) // secondary def is erased below
+      continue;
+    MachineInstr &User = *MRI->use_instr_begin(BaseReg);
+    // After these exclusions, User is a scaled, non-paired, non-pre-indexed
+    // load/store (e.g. LDRWui/STRXui) whose offset is an immediate — exactly
+    // the form the base-reg + uimm12-offset rewrite below expects.
+    if (!User.mayLoadOrStore() || AArch64InstrInfo::isPairedLdSt(User) ||
+        AArch64InstrInfo::isPreLdSt(User) || // different operand layout
+        TII->hasUnscaledLdStOffset(User) ||  // rewrite below assumes scaled
+        User.getNumOperands() < 3 ||         // LRCPC3 pre/post have < 3
+        // SVE load/store use mul-vl addressing and getMemScale would assert.
+        User.getOpcode() == AArch64::LDR_ZXI ||
+        User.getOpcode() == AArch64::STR_ZXI ||
+        !AArch64InstrInfo::getLdStOffsetOp(User).isImm())
+      continue;
+    const MachineOperand &BaseOp = AArch64InstrInfo::getLdStBaseOp(User);
+    if (!BaseOp.isReg() || BaseOp.getReg() != BaseReg)
+      continue;
+    unsigned CIdx = Cands.size();
+    Cands.push_back({&MI, SrcReg, Opc, MI.getOperand(2).getImm(), BaseReg,
+                     &User, TII->getMemScale(User),
+                     AArch64InstrInfo::getLdStOffsetOp(User).getImm()});
+    Groups[{SrcReg, Opc}].push_back(CIdx);
+  }
+
+  auto Eff = [](const Cand &C) {
+    return C.Opc == AArch64::ADDXri ? C.C : -C.C;
+  };
+
+  for (auto &Group : Groups) {
+    auto &Idxs = Group.second;
+    if (Idxs.size() < 2)
+      continue;
+    unsigned PrimaryIdx = Idxs[0];
+    for (unsigned i : Idxs)
+      if (Eff(Cands[i]) < Eff(Cands[PrimaryIdx]))
+        PrimaryIdx = i;
+    const Cand &Primary = Cands[PrimaryIdx];
+    Register PrimaryBaseReg = Primary.BaseReg;
+    MachineInstr *PrimaryDef = Primary.DefMI;
+
+    for (unsigned i : Idxs) {
+      if (i == PrimaryIdx)
+        continue;
+      Cand &Sec = Cands[i];
+      int64_t Delta = Eff(Sec) - Eff(Primary);
+      if (Delta % Sec.Scale != 0)
+        continue;
+      int64_t NewOff = Sec.OldOff + Delta / Sec.Scale;
+      // The rewritten offset must still fit the 12-bit unsigned scaled
+      // immediate that LDRWui/STRXui/etc. encode (uimm12, [0, 0xFFF]).
+      if (NewOff < 0 || NewOff > 0xFFF)
+        continue;
+      if (Pos[PrimaryDef] >= Pos[Sec.UserMI])
+        continue;
+      bool IsPairOrPre = AArch64InstrInfo::isPairedLdSt(*Sec.UserMI) ||
+                         AArch64InstrInfo::isPreLdSt(*Sec.UserMI);
+      unsigned BaseIdx = IsPairOrPre ? 2 : 1;
+      unsigned OffIdx = IsPairOrPre ? 3 : 2;
+      MachineOperand &BaseOp = Sec.UserMI->getOperand(BaseIdx);
+      BaseOp.setReg(PrimaryBaseReg);
+      BaseOp.setIsKill(false);
+      Sec.UserMI->getOperand(OffIdx).setImm(NewOff);
+      MRI->clearKillFlags(PrimaryBaseReg);
+      LLVM_DEBUG(dbgs() << "Coalesced base address materialization "
+                        << *Sec.DefMI << "  into: " << *PrimaryDef);
+      Sec.DefMI->eraseFromParent();
+      Changed = true;
+    }
+  }
+  return Changed;
+}
+
 bool AArch64MIPeepholeOptImpl::run(MachineFunction &MF) {
   TII = static_cast<const AArch64InstrInfo *>(MF.getSubtarget().getInstrInfo());
   TRI = static_cast<const AArch64RegisterInfo *>(
@@ -968,6 +1085,7 @@ bool AArch64MIPeepholeOptImpl::run(MachineFunction &MF) {
   bool Changed = false;
 
   for (MachineBasicBlock &MBB : MF) {
+    Changed |= shareBaseAddresses(MBB);
     for (MachineInstr &MI : make_early_inc_range(MBB)) {
       switch (MI.getOpcode()) {
       default:
diff --git a/llvm/test/CodeGen/AArch64/base-address-cse.ll b/llvm/test/CodeGen/AArch64/base-address-cse.ll
new file mode 100644
index 0000000000000..ea1d24553dc2b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/base-address-cse.ll
@@ -0,0 +1,207 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs < %s | FileCheck %s --check-prefix=ENABLED
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -aarch64-base-address-cse=0 < %s | FileCheck %s --check-prefix=NOBASECSE
+;
+; End-to-end tests for AArch64MIPeepholeOptImpl::shareBaseAddresses.  When
+; ISel materializes a per-access SUBXri/ADDXri
+; base for far offsets it cannot fold into a single immediate, this pass
+; coalesces sibling materializations sharing a common source so that the
+; downstream load/store optimizer can form LDP/STP.
+;
+; The cases below use NEGATIVE far offsets, which (unlike positive far offsets)
+; cannot be expressed as a single unsigned scaled immediate and therefore
+; require base-address CSE to pair.  With the pass disabled (-aarch64-base-address-cse=0,
+; NOBASECSE) the two accesses stay as separate sub+ldr/str with no LDP/STP.
+
+define void @ldp_neg_far_offset_i32(ptr %p) {
+; ENABLED-LABEL: ldp_neg_far_offset_i32:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #400
+; ENABLED-NEXT:    ldp w9, w8, [x8]
+; ENABLED-NEXT:    str w9, [x8]
+; ENABLED-NEXT:    str w8, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: ldp_neg_far_offset_i32:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #400
+; NOBASECSE-NEXT:    sub x9, x0, #396
+; NOBASECSE-NEXT:    ldr w8, [x8]
+; NOBASECSE-NEXT:    ldr w9, [x9]
+; NOBASECSE-NEXT:    str w8, [x8]
+; NOBASECSE-NEXT:    str w9, [x8]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr i32, ptr %p, i64 -100
+  %gep1 = getelementptr i32, ptr %p, i64 -99
+  %v0 = load i32, ptr %gep0
+  %v1 = load i32, ptr %gep1
+  store volatile i32 %v0, ptr poison
+  store volatile i32 %v1, ptr poison
+  ret void
+}
+
+define void @ldp_neg_far_offset_i64(ptr %p) {
+; ENABLED-LABEL: ldp_neg_far_offset_i64:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #800
+; ENABLED-NEXT:    ldp x9, x8, [x8]
+; ENABLED-NEXT:    str x9, [x8]
+; ENABLED-NEXT:    str x8, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: ldp_neg_far_offset_i64:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #800
+; NOBASECSE-NEXT:    sub x9, x0, #792
+; NOBASECSE-NEXT:    ldr x8, [x8]
+; NOBASECSE-NEXT:    ldr x9, [x9]
+; NOBASECSE-NEXT:    str x8, [x8]
+; NOBASECSE-NEXT:    str x9, [x8]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr i64, ptr %p, i64 -100
+  %gep1 = getelementptr i64, ptr %p, i64 -99
+  %v0 = load i64, ptr %gep0
+  %v1 = load i64, ptr %gep1
+  store volatile i64 %v0, ptr poison
+  store volatile i64 %v1, ptr poison
+  ret void
+}
+
+define void @ldp_neg_far_offset_q(ptr %p) {
+; ENABLED-LABEL: ldp_neg_far_offset_q:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #1600
+; ENABLED-NEXT:    ldp q0, q1, [x8]
+; ENABLED-NEXT:    str q0, [x8]
+; ENABLED-NEXT:    str q1, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: ldp_neg_far_offset_q:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #1600
+; NOBASECSE-NEXT:    sub x9, x0, #1584
+; NOBASECSE-NEXT:    ldr q0, [x8]
+; NOBASECSE-NEXT:    ldr q1, [x9]
+; NOBASECSE-NEXT:    str q0, [x8]
+; NOBASECSE-NEXT:    str q1, [x8]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr <2 x i64>, ptr %p, i64 -100
+  %gep1 = getelementptr <2 x i64>, ptr %p, i64 -99
+  %v0 = load <2 x i64>, ptr %gep0
+  %v1 = load <2 x i64>, ptr %gep1
+  store volatile <2 x i64> %v0, ptr poison
+  store volatile <2 x i64> %v1, ptr poison
+  ret void
+}
+
+define void @ldp_neg_far_offset_large_i64(ptr %p) {
+; Offset = -500 * 8 = -4000 bytes (fits in shift=0 SUBXri, <= 4095).
+; ENABLED-LABEL: ldp_neg_far_offset_large_i64:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #4000
+; ENABLED-NEXT:    ldp x9, x8, [x8]
+; ENABLED-NEXT:    str x9, [x8]
+; ENABLED-NEXT:    str x8, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: ldp_neg_far_offset_large_i64:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #4000
+; NOBASECSE-NEXT:    sub x9, x0, #3992
+; NOBASECSE-NEXT:    ldr x8, [x8]
+; NOBASECSE-NEXT:    ldr x9, [x9]
+; NOBASECSE-NEXT:    str x8, [x8]
+; NOBASECSE-NEXT:    str x9, [x8]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr i64, ptr %p, i64 -500
+  %gep1 = getelementptr i64, ptr %p, i64 -499
+  %v0 = load i64, ptr %gep0
+  %v1 = load i64, ptr %gep1
+  store volatile i64 %v0, ptr poison
+  store volatile i64 %v1, ptr poison
+  ret void
+}
+
+define void @stp_neg_far_offset_i32(ptr %p, i32 %v0, i32 %v1) {
+; ENABLED-LABEL: stp_neg_far_offset_i32:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #400
+; ENABLED-NEXT:    stp w1, w2, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: stp_neg_far_offset_i32:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #400
+; NOBASECSE-NEXT:    sub x9, x0, #396
+; NOBASECSE-NEXT:    str w1, [x8]
+; NOBASECSE-NEXT:    str w2, [x9]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr i32, ptr %p, i64 -100
+  %gep1 = getelementptr i32, ptr %p, i64 -99
+  store i32 %v0, ptr %gep0
+  store i32 %v1, ptr %gep1
+  ret void
+}
+
+define void @stp_neg_far_offset_i64(ptr %p, i64 %v0, i64 %v1) {
+; ENABLED-LABEL: stp_neg_far_offset_i64:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #800
+; ENABLED-NEXT:    stp x1, x2, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: stp_neg_far_offset_i64:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #800
+; NOBASECSE-NEXT:    sub x9, x0, #792
+; NOBASECSE-NEXT:    str x1, [x8]
+; NOBASECSE-NEXT:    str x2, [x9]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr i64, ptr %p, i64 -100
+  %gep1 = getelementptr i64, ptr %p, i64 -99
+  store i64 %v0, ptr %gep0
+  store i64 %v1, ptr %gep1
+  ret void
+}
+
+define void @stp_neg_far_offset_q(ptr %p, <2 x i64> %v0, <2 x i64> %v1) {
+; ENABLED-LABEL: stp_neg_far_offset_q:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #1600
+; ENABLED-NEXT:    stp q0, q1, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: stp_neg_far_offset_q:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #1600
+; NOBASECSE-NEXT:    sub x9, x0, #1584
+; NOBASECSE-NEXT:    str q0, [x8]
+; NOBASECSE-NEXT:    str q1, [x9]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr <2 x i64>, ptr %p, i64 -100
+  %gep1 = getelementptr <2 x i64>, ptr %p, i64 -99
+  store <2 x i64> %v0, ptr %gep0
+  store <2 x i64> %v1, ptr %gep1
+  ret void
+}
+
+define void @stp_neg_far_offset_large_i64(ptr %p, i64 %v0, i64 %v1) {
+; ENABLED-LABEL: stp_neg_far_offset_large_i64:
+; ENABLED:       // %bb.0:
+; ENABLED-NEXT:    sub x8, x0, #4000
+; ENABLED-NEXT:    stp x1, x2, [x8]
+; ENABLED-NEXT:    ret
+;
+; NOBASECSE-LABEL: stp_neg_far_offset_large_i64:
+; NOBASECSE:       // %bb.0:
+; NOBASECSE-NEXT:    sub x8, x0, #4000
+; NOBASECSE-NEXT:    sub x9, x0, #3992
+; NOBASECSE-NEXT:    str x1, [x8]
+; NOBASECSE-NEXT:    str x2, [x9]
+; NOBASECSE-NEXT:    ret
+  %gep0 = getelementptr i64, ptr %p, i64 -500
+  %gep1 = getelementptr i64, ptr %p, i64 -499
+  store i64 %v0, ptr %gep0
+  store i64 %v1, ptr %gep1
+  ret void
+}
diff --git a/llvm/test/CodeGen/AArch64/base-address-cse.mir b/llvm/test/CodeGen/AArch64/base-address-cse.mir
new file mode 100644
index 0000000000000..11bed1e9fe56b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/base-address-cse.mir
@@ -0,0 +1,132 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=aarch64 -run-pass=aarch64-mi-peephole-opt \
+# RUN:   -verify-machineinstrs -o - %s | FileCheck %s --check-prefix=SHARED
+# RUN: llc -mtriple=aarch64 -run-pass=aarch64-mi-peephole-opt \
+# RUN:   -aarch64-base-address-cse=0 -o - %s | FileCheck %s --check-prefix=NOBASECSE
+
+---
+name: share_sub_i32
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $x0
+    ; SHARED-LABEL: name: share_sub_i32
+    ; SHARED: liveins: $x0
+    ; SHARED-NEXT: {{  $}}
+    ; SHARED-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
+    ; SHARED-NEXT: [[SUBXri:%[0-9]+]]:gpr64common = SUBXri [[COPY]], 400, 0
+    ; SHARED-NEXT: [[LDRWui:%[0-9]+]]:gpr32 = LDRWui [[SUBXri]], 0
+    ; SHARED-NEXT: [[LDRWui1:%[0-9]+]]:gpr32 = LDRWui [[SUBXri]], 1
+    ; SHARED-NEXT: $w0 = COPY [[LDRWui]]
+    ; SHARED-NEXT: $w1 = COPY [[LDRWui1]]
+    ; SHARED-NEXT: RET_ReallyLR
+    ;
+    ; NOBASECSE-LABEL: name: share_sub_i32
+    ; NOBASECSE: liveins: $x0
+    ; NOBASECSE-NEXT: {{  $}}
+    ; NOBASECSE-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
+    ; NOBASECSE-NEXT: [[SUBXri:%[0-9]+]]:gpr64common = SUBXri [[COPY]], 400, 0
+    ; NOBASECSE-NEXT: [[SUBXri1:%[0-9]+]]:gpr64common = SUBXri [[COPY]], 396, 0
+    ; NOBASECSE-NEXT: [[LDRWui:%[0-9]+]]:gpr32 = LDRWui killed [[SUBXri]], 0
+    ; NOBASECSE-NEXT: [[LDRWui1:%[0-9]+]]:gpr32 = LDRWui killed [[SUBXri1]], 0
+    ; NOBASECSE-NEXT: $w0 = COPY [[LDRWui]]
+    ; NOBASECSE-NEXT: $w1 = COPY [[LDRWui1]]
+    ; NOBASECSE-NEXT: RET_ReallyLR
+    %0:gpr64common = COPY $x0
+    %1:gpr64common = SUBXri %0, 400, 0
+    %2:gpr64common = SUBXri %0, 396, 0
+    %3:gpr32 = LDRWui killed %1, 0
+    %4:gpr32 = LDRWui killed %2, 0
+    $w0 = COPY %3
+    $w1 = COPY %4
+    RET_ReallyLR
+
+
+
+...
+---
+name: share_sub_i32_3sibling
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $x0
+    ; SHARED-LABEL: name: share_sub_i32_3sibling
+    ; SHARED: liveins: $x0
+    ; SHARED-NEXT: {{  $}}
+    ; SHARED-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
+    ; SHARED-NEXT: [[SUBXri:%[0-9]+]]:gpr64common = SUBXri [[COPY]], 400, 0
+    ; SHARED-NEXT: [[LDRWui:%[0-9]+]]:gpr32 = LDRWui [[SUBXri]], 0
+    ; SHARED-NEXT: [[LDRWui1:%[0-9]+]]:gpr32 = LDRWui [[SUBXri]], 1
+    ; SHARED-NEXT: [[LDRWui2:%[0-9]+]]:gpr32 = LDRWui [[SUBXri]], 2
+    ; SHARED-NEXT: $w0 = COPY [[LDRWui]]
+    ; SHARED-NEXT: $w1 = COPY [[LDRWui1]]
+    ; SHARED-NEXT: $w2 = COPY [[LDRWui2]]
+    ; SHARED-NEXT: RET_ReallyLR
+    ;
+    ; NOBASECSE-LABEL: name: share_sub_i32_3sibling
+    ; NOBASECSE: liveins: $x0
+    ; NOBASECSE-NEXT: {{  $}}
+    ; NOBASECSE-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
+    ; NOBASECSE-NEXT: [[SUBXri:%[0-9]+]]:gpr64common = SUBXri [[COPY]], 400, 0
+    ; NOBASECSE-NEXT: [[SUBXri1:%[0-9]+]]:gpr64common = SUBXri [[COPY]], 396, 0
+    ; NOBASECSE-NEXT: [[SUBXri2:%[0-9]+]]:gpr64common = SUBXri [[COPY]], 392, 0
+    ; NOBASECSE-NEXT: [[LDRWui:%[0-9]+]]:gpr32 = LDRWui killed [[SUBXri]], 0
+    ; NOBASECSE-NEXT: [[LDRWui1:%[0-9]+]]:gpr32 = LDRWui killed [[SUBXri1]], 0
+    ; NOBASECSE-NEXT: [[LDRWui2:%[0-9]+]]:gpr32 = LDRWui killed [[SUBXri2]], 0
+    ; NOBASECSE-NEXT: $w0 = COPY [[LDRWui]]
+    ; NOBASECSE-NEXT: $w1 = COPY [[LDRWui1]]
+    ; NOBASECSE-NEXT: $w2 = COPY [[LDRWui2]]
+    ; NOBASECSE-NEXT: RET_ReallyLR
+    %0:gpr64common = COPY $x0
+    %1:gpr64common = SUBXri %0, 400, 0
+    %2:gpr64common = SUBXri %0, 396, 0
+    %3:gpr64common = SUBXri %0, 392, 0
+    %4:gpr32 = LDRWui killed %1, 0
+    %5:gpr32 = LDRWui killed %2, 0
+    %6:gpr32 = LDRWui killed %3, 0
+    $w0 = COPY %4
+    $w1 = COPY %5
+    $w2 = COPY %6
+    RET_ReallyLR
+
+
+
+...
+---
+name: share_add_i64
+tracksRegLiveness: true
+body: |
+  bb.0:
+    liveins: $x0
+    ; SHARED-LABEL: name: share_add_i64
+    ; SHARED: liveins: $x0
+    ; SHARED-NEXT: {{  $}}
+    ; SHARED-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
+    ; SHARED-NEXT: [[ADDXri:%[0-9]+]]:gpr64common = ADDXri [[COPY]], 800, 0
+    ; SHARED-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADDXri]], 0
+    ; SHARED-NEXT: [[LDRXui1:%[0-9]+]]:gpr64 = LDRXui [[ADDXri]], 1
+    ; SHARED-NEXT: $x0 = COPY [[LDRXui]]
+    ; SHARED-NEXT: $x1 = COPY [[LDRXui1]]
+    ; SHARED-NEXT: RET_ReallyLR
+    ;
+    ; NOBASECSE-LABEL: name: share_add_i64
+    ; NOBASECSE: liveins: $x0
+    ; NOBASECSE-NEXT: {{  $}}
+    ; NOBASECSE-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
+    ; NOBASECSE-NEXT: [[ADDXri:%[0-9]+]]:gpr64common = ADDXri [[COPY]], 800, 0
+    ; NOBASECSE-NEXT: [[ADDXri1:%[0-9]+]]:gpr64common = ADDXri [[COPY]], 808, 0
+    ; NOBASECSE-NEXT: [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADDXri]], 0
+    ; NOBASECSE-NEXT: [[LDRXui1:%[0-9]+]]:gpr64 = LDRXui killed [[ADDXri1]], 0
+    ; NOBASECSE-NEXT: $x0 = COPY [[LDRXui]]
+    ; NOBASECSE-NEXT: $x1 = COPY [[LDRXui1]]
+    ; NOBASECSE-NEXT: RET_ReallyLR
+    %0:gpr64common = COPY $x0
+    %1:gpr64common = ADDXri %0, 800, 0
+    %2:gpr64common = ADDXri %0, 808, 0
+    %3:gpr64 = LDRXui killed %1, 0
+    %4:gpr64 = LDRXui killed %2, 0
+    $x0 = COPY %3
+    $x1 = COPY %4
+    RET_ReallyLR
+
+



More information about the llvm-commits mailing list