[llvm] [GlobalIsel] Combine G_PTR_ADD. (PR #95647)

Thorsten Schütt via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 15 01:25:47 PDT 2024


https://github.com/tschuett created https://github.com/llvm/llvm-project/pull/95647

Hints from https://reviews.llvm.org/D109528

>From 47ddeed49fc85e41f9363aef7aadf73c289ca465 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thorsten=20Sch=C3=BCtt?= <schuett at gmail.com>
Date: Thu, 6 Jun 2024 15:09:55 +0200
Subject: [PATCH] [GlobalIsel] Combine G_PTR_ADD.

Hints from https://reviews.llvm.org/D109528
---
 .../llvm/CodeGen/GlobalISel/CombinerHelper.h  |  10 +
 .../include/llvm/Target/GlobalISel/Combine.td |  71 ++++-
 .../lib/CodeGen/GlobalISel/CombinerHelper.cpp | 209 ++++++++++++++
 .../GlobalISel/CombinerHelperVectorOps.cpp    |  49 ++++
 .../AArch64/GlobalISel/combine-ptradd.mir     | 273 ++++++++++++++++++
 .../AArch64/GlobalISel/combine-vscale.mir     |  48 +++
 6 files changed, 659 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-ptradd.mir

diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index 43659564d5ace..2bce6ba470f67 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -879,6 +879,16 @@ class CombinerHelper {
 
   bool matchShlOfVScale(const MachineOperand &MO, BuildFnTy &MatchInfo);
 
+  bool matchPtrAddWithSub(const MachineOperand &MO, BuildFnTy &MatchInfo);
+  bool matchPtrAddWithAdd(const MachineOperand &MO, BuildFnTy &MatchInfo);
+  bool matchPtrAddsFoldConstants(MachineOperand &MO, BuildFnTy &MatchInfo);
+  bool matchPtrAddWFoldDistributedConstants(const MachineOperand &MO,
+                                            BuildFnTy &MatchInfo);
+  bool matchPtrAddMoveInner(MachineOperand &MO, BuildFnTy &MatchInfo);
+
+  bool matchPtrAddWithAddVScale(const MachineOperand &MO, BuildFnTy &MatchInfo);
+  bool matchPtrAddWithSubVScale(const MachineOperand &MO, BuildFnTy &MatchInfo);
+
 private:
   /// Checks for legality of an indexed variant of \p LdSt.
   bool isIndexedLoadStoreLegal(GLoadStore &LdSt) const;
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index bd43b95899030..a35200de105b3 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1675,6 +1675,75 @@ shl_of_vscale,
 sub_of_vscale,
 ]>;
 
+def PtrAddWithSub : GICombineRule<
+   (defs root:$root, build_fn_matchinfo:$matchinfo),
+   (match (G_CONSTANT $right, $imm),
+          (G_SUB $offset, $left, $right),
+          (G_PTR_ADD $root, $base, $offset),
+   [{ return Helper.matchPtrAddWithSub(${root}, ${matchinfo}); }]),
+   (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+def PtrAddWithAdd : GICombineRule<
+   (defs root:$root, build_fn_matchinfo:$matchinfo),
+   (match (G_CONSTANT $right, $imm),
+          (G_ADD $offset, $left, $right),
+          (G_PTR_ADD $root, $base, $offset),
+   [{ return Helper.matchPtrAddWithAdd(${root}, ${matchinfo}); }]),
+   (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+def PtrAdd2DistributedConstOffsets : GICombineRule<
+   (defs root:$root, build_fn_matchinfo:$matchinfo),
+   (match (G_CONSTANT $const2, $imm2),
+          (G_CONSTANT $const1, $imm1),
+          (G_PTR_ADD $pointer1, $base, $const2),
+          (G_PTR_ADD $pointer, $pointer1, $nonconst),
+          (G_PTR_ADD $root, $pointer, $const1),
+   [{ return Helper.matchPtrAddWFoldDistributedConstants(${root}, ${matchinfo}); }]),
+   (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+def PtrAdd2ConstOffsets : GICombineRule<
+   (defs root:$root, build_fn_matchinfo:$matchinfo),
+   (match (G_CONSTANT $const2, $imm2),
+          (G_CONSTANT $const1, $imm1),
+          (G_PTR_ADD $pointer, $base, $const2),
+          (G_PTR_ADD $root, $pointer, $const1),
+   [{ return Helper.matchPtrAddsFoldConstants(${root}, ${matchinfo}); }]),
+   (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+def PtrAddMoveInner : GICombineRule<
+   (defs root:$root, build_fn_matchinfo:$matchinfo),
+   (match (G_CONSTANT $const, $imm),
+          (G_PTR_ADD $pointer, $base, $const),
+          (G_PTR_ADD $root, $pointer, $nonconst),
+   [{ return Helper.matchPtrAddMoveInner(${root}, ${matchinfo}); }]),
+   (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+def PtrAddWithAddVScale : GICombineRule<
+   (defs root:$root, build_fn_matchinfo:$matchinfo),
+   (match (G_VSCALE $right, $imm),
+          (G_ADD $offset, $left, $right),
+          (G_PTR_ADD $root, $base, $offset),
+   [{ return Helper.matchPtrAddWithAddVScale(${root}, ${matchinfo}); }]),
+   (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+def PtrSubWithSubVScale : GICombineRule<
+   (defs root:$root, build_fn_matchinfo:$matchinfo),
+   (match (G_VSCALE $right, $imm),
+          (G_SUB $offset, $left, $right),
+          (G_PTR_ADD $root, $base, $offset),
+   [{ return Helper.matchPtrAddWithSubVScale(${root}, ${matchinfo}); }]),
+   (apply [{ Helper.applyBuildFnMO(${root}, ${matchinfo}); }])>;
+
+
+def ptradd_combines: GICombineGroup<[
+PtrAddWithSub,
+PtrAddWithAdd,
+PtrAdd2ConstOffsets,
+PtrAdd2DistributedConstOffsets,
+PtrAddMoveInner,
+PtrAddWithAddVScale,
+PtrSubWithSubVScale
+]>;
 
 // fold ((0-A) + B) -> B-A
 def ZeroMinusAPlusB : GICombineRule<
@@ -1818,7 +1887,7 @@ def constant_fold_binops : GICombineGroup<[constant_fold_binop,
 def prefer_sign_combines : GICombineGroup<[nneg_zext]>;
 
 def all_combines : GICombineGroup<[integer_reassoc_combines, trivial_combines,
-    vector_ops_combines, freeze_combines,
+    vector_ops_combines, freeze_combines, ptradd_combines,
     insert_vec_elt_combines, extract_vec_elt_combines, combines_for_extload,
     combine_extracted_vector_load,
     undef_combines, identity_combines, phi_combines,
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 02d85958fc7be..55588e41bdb14 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -7444,3 +7444,212 @@ bool CombinerHelper::matchNonNegZext(const MachineOperand &MO,
 
   return false;
 }
+
+bool CombinerHelper::matchPtrAddWithSub(const MachineOperand &MO,
+                                        BuildFnTy &MatchInfo) {
+  GPtrAdd *Inner = cast<GPtrAdd>(MRI.getVRegDef(MO.getReg()));
+  GSub *Sub = cast<GSub>(MRI.getVRegDef(Inner->getOffsetReg()));
+
+  // sub(x, c) -> add(x, -c)
+
+  // one-use check
+  if (!MRI.hasOneNonDBGUse(Sub->getReg(0)))
+    return false;
+
+  // Cannot fail due to pattern.
+  std::optional<APInt> MaybeImm = getIConstantVRegVal(Sub->getRHSReg(), MRI);
+  if (!MaybeImm)
+    return false;
+
+  LLT ConstTy = MRI.getType(Inner->getOffsetReg());
+
+  if (!isConstantLegalOrBeforeLegalizer(ConstTy))
+    return false;
+
+  Register Dst = MO.getReg();
+  LLT DstTy = MRI.getType(Dst);
+
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto Base = B.buildConstant(ConstTy, -(*MaybeImm));
+    auto PtrAdd = B.buildPtrAdd(DstTy, Inner->getBaseReg(), Sub->getLHSReg());
+    B.buildPtrAdd(Dst, PtrAdd, Base);
+  };
+
+  return true;
+}
+
+bool CombinerHelper::matchPtrAddWithAdd(const MachineOperand &MO,
+                                        BuildFnTy &MatchInfo) {
+  GPtrAdd *Inner = cast<GPtrAdd>(MRI.getVRegDef(MO.getReg()));
+  GAdd *Add = cast<GAdd>(MRI.getVRegDef(Inner->getOffsetReg()));
+
+  // one-use check
+  if (!MRI.hasOneNonDBGUse(Add->getReg(0)))
+    return false;
+
+  Register Dst = MO.getReg();
+  LLT DstTy = MRI.getType(Dst);
+
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto PtrAdd = B.buildPtrAdd(DstTy, Inner->getBaseReg(), Add->getLHSReg());
+    B.buildPtrAdd(Dst, PtrAdd, Add->getRHSReg());
+  };
+
+  return true;
+}
+
+bool CombinerHelper::matchPtrAddsFoldConstants(MachineOperand &MO,
+                                               BuildFnTy &MatchInfo) {
+  GPtrAdd *Inner = cast<GPtrAdd>(MRI.getVRegDef(MO.getReg()));
+  GPtrAdd *Second = cast<GPtrAdd>(MRI.getVRegDef(Inner->getBaseReg()));
+
+  // one-use check
+  if (!MRI.hasOneNonDBGUse(Second->getReg(0)))
+    return false;
+
+  // Cannot fail due to pattern.
+  std::optional<APInt> MaybeImm1 =
+      getIConstantVRegVal(Inner->getOffsetReg(), MRI);
+  if (!MaybeImm1)
+    return false;
+
+  // Cannot fail due to pattern.
+  std::optional<APInt> MaybeImm2 =
+      getIConstantVRegVal(Second->getOffsetReg(), MRI);
+  if (!MaybeImm2)
+    return false;
+
+  // Check if we can combine the two offsets into a legal addressing mode.
+  // To do so, we first need to find a load/store user of the pointer to get
+  // the access type. We cannot put the memory access into the MIR pattern.
+  Type *AccessTy = nullptr;
+  auto &MF = *MO.getParent()->getMF();
+  for (auto &UseMI :
+       MRI.use_nodbg_instructions(Inner->getOperand(0).getReg())) {
+    if (auto *LdSt = dyn_cast<GLoadStore>(&UseMI)) {
+      AccessTy = getTypeForLLT(LdSt->getMMO().getMemoryType(),
+                               MF.getFunction().getContext());
+      break;
+    }
+  }
+
+  // Did we found a memory access?
+  if (!AccessTy)
+    return false;
+
+  TargetLoweringBase::AddrMode AM;
+  AM.HasBaseReg = true;
+  AM.BaseOffs = (*MaybeImm1 + *MaybeImm2).getSExtValue();
+
+  Register Dst = MO.getReg();
+  LLT DstTy = MRI.getType(Dst);
+
+  unsigned AS = DstTy.getAddressSpace();
+
+  const auto &TLI = getTargetLowering();
+
+  // Can we combine the two offsets?
+  if (!TLI.isLegalAddressingMode(MF.getDataLayout(), AM, AccessTy, AS))
+    return false;
+
+  LLT ConstTy = MRI.getType(Second->getOffsetReg());
+
+  if (!isConstantLegalOrBeforeLegalizer(ConstTy))
+    return false;
+
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto Offset = B.buildConstant(ConstTy, AM.BaseOffs);
+    B.buildPtrAdd(Dst, Second->getBaseReg(), Offset);
+  };
+
+  return true;
+}
+
+bool CombinerHelper::matchPtrAddWFoldDistributedConstants(
+    const MachineOperand &MO, BuildFnTy &MatchInfo) {
+  GPtrAdd *Inner = cast<GPtrAdd>(MRI.getVRegDef(MO.getReg()));
+  GPtrAdd *Second = cast<GPtrAdd>(MRI.getVRegDef(Inner->getBaseReg()));
+  GPtrAdd *Third = cast<GPtrAdd>(MRI.getVRegDef(Second->getBaseReg()));
+
+  if (!MRI.hasOneNonDBGUse(Second->getReg(0)) ||
+      !MRI.hasOneNonDBGUse(Third->getReg(0)))
+    return false;
+
+  // Cannot fail due to pattern.
+  std::optional<APInt> MaybeImm1 =
+      getIConstantVRegVal(Inner->getOffsetReg(), MRI);
+  if (!MaybeImm1)
+    return false;
+
+  // Cannot fail due to pattern.
+  std::optional<APInt> MaybeImm2 =
+      getIConstantVRegVal(Third->getOffsetReg(), MRI);
+  if (!MaybeImm2)
+    return false;
+
+  // Check if we can combine the two offsets into a legal addressing mode.
+  // To do so, we first need to find a load/store user of the pointer to get
+  // the access type. We cannot put the memory access into the MIR pattern.
+  Type *AccessTy = nullptr;
+  auto &MF = *MO.getParent()->getMF();
+  for (auto &UseMI :
+       MRI.use_nodbg_instructions(Inner->getOperand(0).getReg())) {
+    if (auto *LdSt = dyn_cast<GLoadStore>(&UseMI)) {
+      AccessTy = getTypeForLLT(LdSt->getMMO().getMemoryType(),
+                               MF.getFunction().getContext());
+      break;
+    }
+  }
+
+  // Did we found a memory access?
+  if (!AccessTy)
+    return false;
+
+  TargetLoweringBase::AddrMode AM;
+  AM.HasBaseReg = true;
+  AM.BaseOffs = (*MaybeImm1 + *MaybeImm2).getSExtValue();
+
+  Register Dst = MO.getReg();
+  LLT DstTy = MRI.getType(Dst);
+  unsigned AS = DstTy.getAddressSpace();
+
+  const auto &TLI = getTargetLowering();
+
+  // Can we combine the two offsets?
+  if (!TLI.isLegalAddressingMode(MF.getDataLayout(), AM, AccessTy, AS))
+    return false;
+
+  LLT ConstTy = MRI.getType(Third->getOffsetReg());
+
+  if (!isConstantLegalOrBeforeLegalizer(ConstTy))
+    return false;
+
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto Offset = B.buildConstant(ConstTy, AM.BaseOffs);
+    auto PtrAdd =
+        B.buildPtrAdd(DstTy, Third->getBaseReg(), Second->getOffsetReg());
+    B.buildPtrAdd(Dst, PtrAdd, Offset);
+  };
+
+  return true;
+}
+
+bool CombinerHelper::matchPtrAddMoveInner(MachineOperand &MO,
+                                          BuildFnTy &MatchInfo) {
+  GPtrAdd *Inner = cast<GPtrAdd>(MRI.getVRegDef(MO.getReg()));
+  GPtrAdd *Second = cast<GPtrAdd>(MRI.getVRegDef(Inner->getBaseReg()));
+
+  if (!MRI.hasOneNonDBGUse(Second->getReg(0)))
+    return false;
+
+  Register Dst = MO.getReg();
+  LLT DstTy = MRI.getType(Dst);
+
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto PtrAdd =
+        B.buildPtrAdd(DstTy, Second->getBaseReg(), Inner->getOffsetReg());
+    B.buildPtrAdd(Dst, PtrAdd, Second->getOffsetReg());
+  };
+
+  return true;
+}
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp
index 66b1c5f8ca82c..4c962342e631a 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelperVectorOps.cpp
@@ -484,3 +484,52 @@ bool CombinerHelper::matchShlOfVScale(const MachineOperand &MO,
 
   return true;
 }
+
+bool CombinerHelper::matchPtrAddWithAddVScale(const MachineOperand &MO,
+                                              BuildFnTy &MatchInfo) {
+  GPtrAdd *Inner = cast<GPtrAdd>(MRI.getVRegDef(MO.getReg()));
+  GAdd *Add = cast<GAdd>(MRI.getVRegDef(Inner->getOffsetReg()));
+  GVScale *VScale = cast<GVScale>(MRI.getVRegDef(Add->getRHSReg()));
+
+  // one-use check
+  if (!MRI.hasOneNonDBGUse(Add->getReg(0)) ||
+      !MRI.hasOneNonDBGUse(VScale->getReg(0)))
+    return false;
+
+  Register Dst = MO.getReg();
+  LLT DstTy = MRI.getType(Dst);
+
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto PtrAdd = B.buildPtrAdd(DstTy, Inner->getBaseReg(), Add->getLHSReg());
+    B.buildPtrAdd(Dst, PtrAdd, Add->getRHSReg());
+  };
+
+  return true;
+}
+
+bool CombinerHelper::matchPtrAddWithSubVScale(const MachineOperand &MO,
+                                              BuildFnTy &MatchInfo) {
+  GPtrAdd *Inner = cast<GPtrAdd>(MRI.getVRegDef(MO.getReg()));
+  GSub *Sub = cast<GSub>(MRI.getVRegDef(Inner->getOffsetReg()));
+  GVScale *VScale = cast<GVScale>(MRI.getVRegDef(Sub->getRHSReg()));
+
+  // one-use check
+  if (!MRI.hasOneNonDBGUse(Sub->getReg(0)) ||
+      !MRI.hasOneNonDBGUse(VScale->getReg(0)))
+    return false;
+
+  Register Dst = MO.getReg();
+  LLT DstTy = MRI.getType(Dst);
+  LLT VScaleTy = MRI.getType(Inner->getOffsetReg());
+
+  if (!isLegalOrBeforeLegalizer({TargetOpcode::G_VSCALE, VScaleTy}))
+    return false;
+
+  MatchInfo = [=](MachineIRBuilder &B) {
+    auto VScaleMI = B.buildVScale(VScaleTy, -VScale->getSrc());
+    auto PtrAdd = B.buildPtrAdd(DstTy, Inner->getBaseReg(), Sub->getLHSReg());
+    B.buildPtrAdd(Dst, PtrAdd, VScaleMI);
+  };
+
+  return true;
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-ptradd.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-ptradd.mir
new file mode 100644
index 0000000000000..31e975f66d07b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-ptradd.mir
@@ -0,0 +1,273 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s
+
+---
+name:            ptradd_with_sub
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: ptradd_with_sub
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x0
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1600
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[COPY1]](s64)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTR_ADD]], [[C]](s64)
+    ; CHECK-NEXT: $x0 = COPY [[PTR_ADD1]](p0)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x0
+    %2:_(s64) = G_CONSTANT i64 1600
+    %10:_(s64) = G_SUB %1, %2(s64)
+    %11:_(p0) = G_PTR_ADD %0, %10(s64)
+    $x0 = COPY %11(p0)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            ptradd_with_sub_multiple_use
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: ptradd_with_sub_multiple_use
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x0
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1600
+    ; CHECK-NEXT: [[SUB:%[0-9]+]]:_(s64) = G_SUB [[COPY1]], [[C]]
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[SUB]](s64)
+    ; CHECK-NEXT: $x0 = COPY [[PTR_ADD]](p0)
+    ; CHECK-NEXT: $x1 = COPY [[SUB]](s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x0
+    %2:_(s64) = G_CONSTANT i64 1600
+    %10:_(s64) = G_SUB %1, %2(s64)
+    %11:_(p0) = G_PTR_ADD %0, %10(s64)
+    $x0 = COPY %11(p0)
+    $x1 = COPY %10(s64)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            ptradd_with_add
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: ptradd_with_add
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1600
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[COPY1]](s64)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = G_PTR_ADD [[PTR_ADD]], [[C]](s64)
+    ; CHECK-NEXT: $x0 = COPY [[PTR_ADD1]](p0)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x1
+    %2:_(s64) = G_CONSTANT i64 1600
+    %10:_(s64) = G_ADD %1, %2(s64)
+    %11:_(p0) = G_PTR_ADD %0, %10(s64)
+    $x0 = COPY %11(p0)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            load_with_two_constants
+alignment:       4
+tracksRegLiveness: true
+liveins:
+  - { reg: '$x0' }
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: load_with_two_constants
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 17
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nsw G_PTR_ADD [[COPY]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[PTR_ADD]](p0) :: (load (s64))
+    ; CHECK-NEXT: $x0 = COPY [[LOAD]](s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x0
+    %3:_(s64) = G_CONSTANT i64 16
+    %4:_(s64) = G_CONSTANT i64 1
+    %13:_(p0) = G_PTR_ADD %0, %3(s64)
+    %12:_(p0) = nsw G_PTR_ADD %13, %4(s64)
+    %14:_(s64) = G_LOAD %12(p0) :: (load (s64))
+    $x0 = COPY %14(s64)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            load_with_two_constants_large
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: load_with_two_constants_large
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 3000
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nsw G_PTR_ADD [[COPY]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[PTR_ADD]](p0) :: (load (s64))
+    ; CHECK-NEXT: $x0 = COPY [[LOAD]](s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x1
+    %3:_(s64) = G_CONSTANT i64 1000
+    %4:_(s64) = G_CONSTANT i64 2000
+    %13:_(p0) = G_PTR_ADD %0, %3(s64)
+    %12:_(p0) = nsw G_PTR_ADD %13, %4(s64)
+    %14:_(s64) = G_LOAD %12(p0) :: (load (s64))
+    $x0 = COPY %14(s64)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            load_with_two_distributed_constants
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: load_with_two_distributed_constants
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[COPY1]](s64)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 17
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nsw G_PTR_ADD [[PTR_ADD]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[PTR_ADD1]](p0) :: (load (s64))
+    ; CHECK-NEXT: $x0 = COPY [[LOAD]](s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x1
+    %3:_(s64) = G_CONSTANT i64 16
+    %4:_(s64) = G_CONSTANT i64 1
+    %14:_(p0) = G_PTR_ADD %0, %3(s64)
+    %13:_(p0) = G_PTR_ADD %14, %1(s64)
+    %12:_(p0) = nsw G_PTR_ADD %13, %4(s64)
+    %15:_(s64) = G_LOAD %12(p0) :: (load (s64))
+    $x0 = COPY %15(s64)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            move_inner
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: move_inner
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[COPY1]](s64)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nsw G_PTR_ADD [[PTR_ADD]], [[C]](s64)
+    ; CHECK-NEXT: $x0 = COPY [[PTR_ADD1]](p0)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x1
+    %3:_(s64) = G_CONSTANT i64 16
+    %13:_(p0) = G_PTR_ADD %0, %3(s64)
+    %12:_(p0) = nsw G_PTR_ADD %13, %1(s64)
+    $x0 = COPY %12(p0)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            move_inner_rotate
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: move_inner_rotate
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
+    ; CHECK-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 32
+    ; CHECK-NEXT: [[CONSTANT_FOLD_BARRIER:%[0-9]+]]:_(s64) = G_CONSTANT_FOLD_BARRIER [[C1]]
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[CONSTANT_FOLD_BARRIER]](s64)
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nsw G_PTR_ADD [[PTR_ADD]], [[C]](s64)
+    ; CHECK-NEXT: $x0 = COPY [[PTR_ADD1]](p0)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x1
+    %3:_(s64) = G_CONSTANT i64 16
+    %4:_(s64) = G_CONSTANT i64 32
+    %5:_(s64) = G_CONSTANT_FOLD_BARRIER %4
+    %13:_(p0) = G_PTR_ADD %0, %3(s64)
+    %12:_(p0) = nsw G_PTR_ADD %13, %5(s64)
+    $x0 = COPY %12(p0)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            load_with_three_constants
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: load_with_three_constants
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 60
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nsw G_PTR_ADD [[COPY]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[PTR_ADD]](p0) :: (load (s64))
+    ; CHECK-NEXT: $x0 = COPY [[LOAD]](s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x1
+    %2:_(s64) = G_CONSTANT i64 10
+    %3:_(s64) = G_CONSTANT i64 20
+    %4:_(s64) = G_CONSTANT i64 30
+    %12:_(p0) = G_PTR_ADD %0, %2(s64)
+    %13:_(p0) = G_PTR_ADD %12, %3(s64)
+    %14:_(p0) = nsw G_PTR_ADD %13, %4(s64)
+    %15:_(s64) = G_LOAD %14(p0) :: (load (s64))
+    $x0 = COPY %15(s64)
+    RET_ReallyLR implicit $x0
+
+...
+---
+name:            load_with_two_constants_and_sub
+body:             |
+  bb.1:
+    liveins: $x0
+
+    ; CHECK-LABEL: name: load_with_two_constants_and_sub
+    ; CHECK: liveins: $x0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(p0) = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD [[COPY]], [[COPY1]](s64)
+    ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 20
+    ; CHECK-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nsw G_PTR_ADD [[PTR_ADD]], [[C]](s64)
+    ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(s64) = G_LOAD [[PTR_ADD1]](p0) :: (load (s64))
+    ; CHECK-NEXT: $x0 = COPY [[LOAD]](s64)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:_(p0) = COPY $x0
+    %1:_(s64) = COPY $x1
+    %2:_(s64) = G_CONSTANT i64 10
+    %4:_(s64) = G_CONSTANT i64 30
+    %12:_(s64) = G_SUB %1, %2(s64)
+    %13:_(p0) = G_PTR_ADD %0, %12(s64)
+    %14:_(p0) = nsw G_PTR_ADD %13, %4(s64)
+    %15:_(s64) = G_LOAD %14(p0) :: (load (s64))
+    $x0 = COPY %15(s64)
+    RET_ReallyLR implicit $x0
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-vscale.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-vscale.mir
index 9b7a44954afdb..6ae93d6dbea5e 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-vscale.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-vscale.mir
@@ -111,3 +111,51 @@ body:             |
     %shl:_(s64) = nuw G_SHL %lhs(s64), %rhs(s64)
     $x0 = COPY %shl(s64)
     RET_ReallyLR implicit $x0
+...
+---
+name:            ptradd_add_vscale
+body:             |
+  bb.1:
+    liveins: $x0, $x1
+    ; CHECK-LABEL: name: ptradd_add_vscale
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %p:_(p0) = COPY $x0
+    ; CHECK-NEXT: %opaque:_(s64) = COPY $x0
+    ; CHECK-NEXT: %vs:_(s64) = G_VSCALE i64 11
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD %p, %opaque(s64)
+    ; CHECK-NEXT: %ptradd:_(p0) = G_PTR_ADD [[PTR_ADD]], %vs(s64)
+    ; CHECK-NEXT: $x0 = COPY %ptradd(p0)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %p:_(p0) = COPY $x0
+    %opaque:_(s64) = COPY $x0
+    %cons:_(s64) = G_CONSTANT i64 2
+    %vs:_(s64) = G_VSCALE i64 11
+    %rhs:_(s64) = G_ADD  %opaque(s64), %vs(s64)
+    %ptradd:_(p0) = nuw G_PTR_ADD %p(p0), %rhs(s64)
+    $x0 = COPY %ptradd(p0)
+    RET_ReallyLR implicit $x0
+...
+---
+name:            ptradd_sub_vscale
+body:             |
+  bb.1:
+    liveins: $x0, $x1
+    ; CHECK-LABEL: name: ptradd_sub_vscale
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: %p:_(p0) = COPY $x0
+    ; CHECK-NEXT: %opaque:_(s64) = COPY $x0
+    ; CHECK-NEXT: [[VSCALE:%[0-9]+]]:_(s64) = G_VSCALE i64 -11
+    ; CHECK-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = G_PTR_ADD %p, %opaque(s64)
+    ; CHECK-NEXT: %ptradd:_(p0) = G_PTR_ADD [[PTR_ADD]], [[VSCALE]](s64)
+    ; CHECK-NEXT: $x0 = COPY %ptradd(p0)
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %p:_(p0) = COPY $x0
+    %opaque:_(s64) = COPY $x0
+    %cons:_(s64) = G_CONSTANT i64 2
+    %vs:_(s64) = G_VSCALE i64 11
+    %rhs:_(s64) = G_SUB %opaque(s64), %vs(s64)
+    %ptradd:_(p0) = nuw G_PTR_ADD %p(p0), %rhs(s64)
+    $x0 = COPY %ptradd(p0)
+    RET_ReallyLR implicit $x0



More information about the llvm-commits mailing list