[llvm-branch-commits] [llvm] [LoongArch] OptWInstrs: Sign-extend outer PHI operands to remove sext.w in loops (PR #232572)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Oct 16 00:32:44 PDT 2026


https://github.com/heiher updated https://github.com/llvm/llvm-project/pull/232572

>From 81b9bb26329f6dd1a97ce61d4803faab2cd4112c Mon Sep 17 00:00:00 2001
From: WANG Rui <wangrui at loongson.cn>
Date: Thu, 15 Oct 2026 21:38:21 +0800
Subject: [PATCH] [LoongArch] OptWInstrs: Sign-extend outer PHI operands to
 remove sext.w in loops

A sext.w inside a loop often cannot be removed only because one of the
values reaching it comes in through a PHI from outside the loop and is not
known to be sign-extended, e.g. an i32 argument that is only any-extended:

  preheader:
    ...
  loop:
    %p = PHI %x, %preheader, %next, %loop
    %s = ADDI_W %p, 0
    %next = ADD_D %p, ...

If every other value reaching the sext.w is sign-extended, sign-extend
those PHI operands in their incoming blocks instead and remove the sext.w.
This trades a sext.w executed on every iteration for one executed once per
entry into the loop.

Only incoming blocks with a smaller loop depth than the sext.w are
considered. Such a block can't be inside the sext.w's innermost loop, and
this also excludes sibling loops of the same depth that may be just as hot.

Sign-extending a PHI operand changes the value seen by every user of the
PHI, not just the sext.w being removed, so this is only done when all
(transitive) users of each affected PHI only use the lower 32 bits.

The transformation can be disabled with -loongarch-disable-sextw-hoisting.
---
 .../Target/LoongArch/LoongArchOptWInstrs.cpp  |  95 ++++++++-
 llvm/test/CodeGen/LoongArch/sextw-hoisting.ll | 188 ++++++++++++++++--
 llvm/test/CodeGen/LoongArch/sextw-removal.ll  |  12 +-
 3 files changed, 263 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp b/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp
index b91724e0112a94..a9b331c2e8bfb2 100644
--- a/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchOptWInstrs.cpp
@@ -32,10 +32,13 @@
 #include "LoongArch.h"
 #include "LoongArchMachineFunctionInfo.h"
 #include "LoongArchSubtarget.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineLoopInfo.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
+#include "llvm/InitializePasses.h"
 
 using namespace llvm;
 
@@ -45,11 +48,17 @@ using namespace llvm;
 STATISTIC(NumRemovedSExtW, "Number of removed sign-extensions");
 STATISTIC(NumTransformedToWInstrs,
           "Number of instructions transformed to W-ops");
+STATISTIC(NumHoistedSExtW,
+          "Number of sign-extensions hoisted into PHI predecessors");
 
 static cl::opt<bool>
     DisableSExtWRemoval("loongarch-disable-sextw-removal",
                         cl::desc("Disable removal of sign-extend insn"),
                         cl::init(false), cl::Hidden);
+static cl::opt<bool> DisableSExtWHoisting(
+    "loongarch-disable-sextw-hoisting",
+    cl::desc("Disable hoisting of sign-extend insn into outer PHI operands"),
+    cl::init(false), cl::Hidden);
 static cl::opt<bool>
     DisableCvtToDSuffix("loongarch-disable-cvt-to-d-suffix",
                         cl::desc("Disable convert to D suffix"),
@@ -65,8 +74,8 @@ class LoongArchOptWInstrs : public MachineFunctionPass {
 
   bool runOnMachineFunction(MachineFunction &MF) override;
   bool removeSExtWInstrs(MachineFunction &MF, const LoongArchInstrInfo &TII,
-                         const LoongArchSubtarget &ST,
-                         MachineRegisterInfo &MRI);
+                         const LoongArchSubtarget &ST, MachineRegisterInfo &MRI,
+                         const MachineLoopInfo &MLI);
   bool convertToDSuffixes(MachineFunction &MF, const LoongArchInstrInfo &TII,
                           const LoongArchSubtarget &ST,
                           MachineRegisterInfo &MRI);
@@ -76,6 +85,8 @@ class LoongArchOptWInstrs : public MachineFunctionPass {
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.setPreservesCFG();
+    AU.addRequired<MachineLoopInfoWrapperPass>();
+    AU.addPreserved<MachineLoopInfoWrapperPass>();
     MachineFunctionPass::getAnalysisUsage(AU);
   }
 
@@ -85,8 +96,11 @@ class LoongArchOptWInstrs : public MachineFunctionPass {
 } // end anonymous namespace
 
 char LoongArchOptWInstrs::ID = 0;
-INITIALIZE_PASS(LoongArchOptWInstrs, DEBUG_TYPE, LOONGARCH_OPT_W_INSTRS_NAME,
-                false, false)
+INITIALIZE_PASS_BEGIN(LoongArchOptWInstrs, DEBUG_TYPE,
+                      LOONGARCH_OPT_W_INSTRS_NAME, false, false)
+INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
+INITIALIZE_PASS_END(LoongArchOptWInstrs, DEBUG_TYPE,
+                    LOONGARCH_OPT_W_INSTRS_NAME, false, false)
 
 FunctionPass *llvm::createLoongArchOptWInstrsPass() {
   return new LoongArchOptWInstrs();
@@ -505,9 +519,19 @@ static bool isSignExtendingOpW(const MachineInstr &MI,
   return false;
 }
 
+using PHIOperand = std::pair<MachineInstr *, unsigned>;
+
+/// Return true if all definitions reaching \p SrcReg sign-extend their output.
+/// If \p PHIFixes is non-null, the incoming values of PHIs from blocks with a
+/// smaller loop depth than \p UseMBB are assumed to be sign-extended and the
+/// PHI operands are added to \p PHIFixes; the caller must then sign-extend
+/// them in their incoming blocks.
 static bool isSignExtendedW(Register SrcReg, const LoongArchSubtarget &ST,
                             const MachineRegisterInfo &MRI,
-                            SmallPtrSetImpl<MachineInstr *> &FixableDef) {
+                            SmallPtrSetImpl<MachineInstr *> &FixableDef,
+                            const MachineLoopInfo *MLI = nullptr,
+                            const MachineBasicBlock *UseMBB = nullptr,
+                            SmallSetVector<PHIOperand, 4> *PHIFixes = nullptr) {
   SmallSet<Register, 4> Visited;
   SmallVector<Register, 4> Worklist;
 
@@ -635,6 +659,16 @@ static bool isSignExtendedW(Register SrcReg, const LoongArchSubtarget &ST,
         if (!MI->getOperand(I).isReg())
           return false;
 
+        // A block with a smaller loop depth than UseMBB can't be inside
+        // UseMBB's innermost loop, so this also excludes sibling loops of the
+        // same depth that may be just as hot.
+        if (PHIFixes && MI->isPHI() &&
+            MLI->getLoopDepth(MI->getOperand(I + 1).getMBB()) <
+                MLI->getLoopDepth(UseMBB)) {
+          PHIFixes->insert({MI, I});
+          continue;
+        }
+
         if (!AddRegToWorkList(MI->getOperand(I).getReg()))
           return false;
       }
@@ -714,7 +748,8 @@ static unsigned getWOp(unsigned Opcode) {
 bool LoongArchOptWInstrs::removeSExtWInstrs(MachineFunction &MF,
                                             const LoongArchInstrInfo &TII,
                                             const LoongArchSubtarget &ST,
-                                            MachineRegisterInfo &MRI) {
+                                            MachineRegisterInfo &MRI,
+                                            const MachineLoopInfo &MLI) {
   if (DisableSExtWRemoval)
     return false;
 
@@ -728,13 +763,37 @@ bool LoongArchOptWInstrs::removeSExtWInstrs(MachineFunction &MF,
       Register SrcReg = MI.getOperand(1).getReg();
 
       SmallPtrSet<MachineInstr *, 4> FixableDefs;
+      SmallSetVector<PHIOperand, 4> PHIFixes;
 
       // If all users only use the lower bits, this sext.w is redundant.
       // Or if all definitions reaching MI sign-extend their output,
       // then sext.w is redundant.
       if (!hasAllWUsers(MI, ST, MRI) &&
-          !isSignExtendedW(SrcReg, ST, MRI, FixableDefs))
-        continue;
+          !isSignExtendedW(SrcReg, ST, MRI, FixableDefs)) {
+        // Otherwise, if the only values that are not known to be
+        // sign-extended reach MI through PHIs from outer loop levels,
+        // sign-extend them in their incoming blocks instead.
+        FixableDefs.clear();
+        if (DisableSExtWHoisting || MLI.getLoopDepth(&MBB) == 0 ||
+            !isSignExtendedW(SrcReg, ST, MRI, FixableDefs, &MLI, &MBB,
+                             &PHIFixes))
+          continue;
+        // Drop PHI operands that are already known to be sign-extended.
+        PHIFixes.remove_if([&](const PHIOperand &Op) {
+          SmallPtrSet<MachineInstr *, 4> OpFixableDefs;
+          if (!isSignExtendedW(Op.first->getOperand(Op.second).getReg(), ST,
+                               MRI, OpFixableDefs))
+            return false;
+          FixableDefs.insert_range(OpFixableDefs);
+          return true;
+        });
+        // Sign-extending a PHI operand changes the value seen by every user
+        // of the PHI, so all of them must only use the lower 32 bits.
+        if (any_of(PHIFixes, [&](const PHIOperand &Op) {
+              return !hasAllWUsers(*Op.first, ST, MRI);
+            }))
+          continue;
+      }
 
       Register DstReg = MI.getOperand(0).getReg();
       if (!SrcReg.isVirtual() ||
@@ -752,6 +811,22 @@ bool LoongArchOptWInstrs::removeSExtWInstrs(MachineFunction &MF,
         ++NumTransformedToWInstrs;
       }
 
+      // Sign-extend the PHI operands in their incoming blocks.
+      for (auto [PHI, OpIdx] : PHIFixes) {
+        MachineOperand &Op = PHI->getOperand(OpIdx);
+        MachineBasicBlock *InMBB = PHI->getOperand(OpIdx + 1).getMBB();
+        Register NewReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
+        BuildMI(*InMBB, InMBB->getFirstTerminator(), PHI->getDebugLoc(),
+                TII.get(LoongArch::ADDI_W), NewReg)
+            .addReg(Op.getReg())
+            .addImm(0);
+        LLVM_DEBUG(dbgs() << "Sign-extending PHI operand " << OpIdx << " of "
+                          << *PHI << " in " << printMBBReference(*InMBB)
+                          << "\n");
+        Op.setReg(NewReg);
+        ++NumHoistedSExtW;
+      }
+
       LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n");
       MRI.replaceRegWith(DstReg, SrcReg);
       MRI.clearKillFlags(SrcReg);
@@ -854,7 +929,9 @@ bool LoongArchOptWInstrs::runOnMachineFunction(MachineFunction &MF) {
     return false;
 
   bool MadeChange = false;
-  MadeChange |= removeSExtWInstrs(MF, TII, ST, MRI);
+  const MachineLoopInfo &MLI =
+      getAnalysis<MachineLoopInfoWrapperPass>().getLI();
+  MadeChange |= removeSExtWInstrs(MF, TII, ST, MRI, MLI);
 
   if (!(DisableCvtToDSuffix || ST.preferWInst()))
     MadeChange |= convertToDSuffixes(MF, TII, ST, MRI);
diff --git a/llvm/test/CodeGen/LoongArch/sextw-hoisting.ll b/llvm/test/CodeGen/LoongArch/sextw-hoisting.ll
index 6767154f1eb944..c6724e24976f9b 100644
--- a/llvm/test/CodeGen/LoongArch/sextw-hoisting.ll
+++ b/llvm/test/CodeGen/LoongArch/sextw-hoisting.ll
@@ -1,5 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc < %s --mtriple=loongarch64 | FileCheck %s
+; RUN: llc < %s --mtriple=loongarch64 --loongarch-disable-sextw-hoisting | \
+; RUN:   FileCheck %s --check-prefix=NOHOIST
 
 declare void @use(i32 signext)
 
@@ -13,15 +15,15 @@ define void @hoist_simple(i32 %x, i32 signext %n) nounwind {
 ; CHECK-NEXT:    st.d $s0, $sp, 8 # 8-byte Folded Spill
 ; CHECK-NEXT:    st.d $s1, $sp, 0 # 8-byte Folded Spill
 ; CHECK-NEXT:    move $fp, $a1
-; CHECK-NEXT:    move $s0, $a0
 ; CHECK-NEXT:    move $s1, $zero
+; CHECK-NEXT:    addi.w $s0, $a0, 0
 ; CHECK-NEXT:    .p2align 4, , 16
 ; CHECK-NEXT:  .LBB0_1: # %loop
 ; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    addi.w $a0, $s0, 0
+; CHECK-NEXT:    move $a0, $s0
 ; CHECK-NEXT:    pcaddu18i $ra, %call36(use)
 ; CHECK-NEXT:    jirl $ra, $ra, 0
-; CHECK-NEXT:    add.d $s0, $s0, $s1
+; CHECK-NEXT:    add.w $s0, $s0, $s1
 ; CHECK-NEXT:    addi.w $s1, $s1, 1
 ; CHECK-NEXT:    blt $s1, $fp, .LBB0_1
 ; CHECK-NEXT:  # %bb.2: # %exit
@@ -31,6 +33,33 @@ define void @hoist_simple(i32 %x, i32 signext %n) nounwind {
 ; CHECK-NEXT:    ld.d $ra, $sp, 24 # 8-byte Folded Reload
 ; CHECK-NEXT:    addi.d $sp, $sp, 32
 ; CHECK-NEXT:    ret
+;
+; NOHOIST-LABEL: hoist_simple:
+; NOHOIST:       # %bb.0: # %entry
+; NOHOIST-NEXT:    addi.d $sp, $sp, -32
+; NOHOIST-NEXT:    st.d $ra, $sp, 24 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $fp, $sp, 16 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s0, $sp, 8 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s1, $sp, 0 # 8-byte Folded Spill
+; NOHOIST-NEXT:    move $fp, $a1
+; NOHOIST-NEXT:    move $s0, $a0
+; NOHOIST-NEXT:    move $s1, $zero
+; NOHOIST-NEXT:    .p2align 4, , 16
+; NOHOIST-NEXT:  .LBB0_1: # %loop
+; NOHOIST-NEXT:    # =>This Inner Loop Header: Depth=1
+; NOHOIST-NEXT:    addi.w $a0, $s0, 0
+; NOHOIST-NEXT:    pcaddu18i $ra, %call36(use)
+; NOHOIST-NEXT:    jirl $ra, $ra, 0
+; NOHOIST-NEXT:    add.d $s0, $s0, $s1
+; NOHOIST-NEXT:    addi.w $s1, $s1, 1
+; NOHOIST-NEXT:    blt $s1, $fp, .LBB0_1
+; NOHOIST-NEXT:  # %bb.2: # %exit
+; NOHOIST-NEXT:    ld.d $s1, $sp, 0 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s0, $sp, 8 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $fp, $sp, 16 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $ra, $sp, 24 # 8-byte Folded Reload
+; NOHOIST-NEXT:    addi.d $sp, $sp, 32
+; NOHOIST-NEXT:    ret
 entry:
   br label %loop
 
@@ -58,30 +87,62 @@ define void @hoist_two_incoming(i1 %cond, i32 %a, i32 %b, i32 signext %n) nounwi
 ; CHECK-NEXT:    st.d $s1, $sp, 0 # 8-byte Folded Spill
 ; CHECK-NEXT:    andi $a0, $a0, 1
 ; CHECK-NEXT:    move $fp, $a3
-; CHECK-NEXT:    beqz $a0, .LBB1_2
-; CHECK-NEXT:  # %bb.1:
-; CHECK-NEXT:    move $s0, $a1
-; CHECK-NEXT:    b .LBB1_3
-; CHECK-NEXT:  .LBB1_2: # %else
-; CHECK-NEXT:    move $s0, $a2
-; CHECK-NEXT:  .LBB1_3: # %loop.preheader
+; CHECK-NEXT:    bnez $a0, .LBB1_2
+; CHECK-NEXT:  # %bb.1: # %else
+; CHECK-NEXT:    move $a1, $a2
+; CHECK-NEXT:  .LBB1_2: # %loop.preheader
 ; CHECK-NEXT:    move $s1, $zero
+; CHECK-NEXT:    addi.w $s0, $a1, 0
 ; CHECK-NEXT:    .p2align 4, , 16
-; CHECK-NEXT:  .LBB1_4: # %loop
+; CHECK-NEXT:  .LBB1_3: # %loop
 ; CHECK-NEXT:    # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    addi.w $a0, $s0, 0
+; CHECK-NEXT:    move $a0, $s0
 ; CHECK-NEXT:    pcaddu18i $ra, %call36(use)
 ; CHECK-NEXT:    jirl $ra, $ra, 0
-; CHECK-NEXT:    add.d $s0, $s0, $s1
+; CHECK-NEXT:    add.w $s0, $s0, $s1
 ; CHECK-NEXT:    addi.w $s1, $s1, 1
-; CHECK-NEXT:    blt $s1, $fp, .LBB1_4
-; CHECK-NEXT:  # %bb.5: # %exit
+; CHECK-NEXT:    blt $s1, $fp, .LBB1_3
+; CHECK-NEXT:  # %bb.4: # %exit
 ; CHECK-NEXT:    ld.d $s1, $sp, 0 # 8-byte Folded Reload
 ; CHECK-NEXT:    ld.d $s0, $sp, 8 # 8-byte Folded Reload
 ; CHECK-NEXT:    ld.d $fp, $sp, 16 # 8-byte Folded Reload
 ; CHECK-NEXT:    ld.d $ra, $sp, 24 # 8-byte Folded Reload
 ; CHECK-NEXT:    addi.d $sp, $sp, 32
 ; CHECK-NEXT:    ret
+;
+; NOHOIST-LABEL: hoist_two_incoming:
+; NOHOIST:       # %bb.0: # %entry
+; NOHOIST-NEXT:    addi.d $sp, $sp, -32
+; NOHOIST-NEXT:    st.d $ra, $sp, 24 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $fp, $sp, 16 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s0, $sp, 8 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s1, $sp, 0 # 8-byte Folded Spill
+; NOHOIST-NEXT:    andi $a0, $a0, 1
+; NOHOIST-NEXT:    move $fp, $a3
+; NOHOIST-NEXT:    beqz $a0, .LBB1_2
+; NOHOIST-NEXT:  # %bb.1:
+; NOHOIST-NEXT:    move $s0, $a1
+; NOHOIST-NEXT:    b .LBB1_3
+; NOHOIST-NEXT:  .LBB1_2: # %else
+; NOHOIST-NEXT:    move $s0, $a2
+; NOHOIST-NEXT:  .LBB1_3: # %loop.preheader
+; NOHOIST-NEXT:    move $s1, $zero
+; NOHOIST-NEXT:    .p2align 4, , 16
+; NOHOIST-NEXT:  .LBB1_4: # %loop
+; NOHOIST-NEXT:    # =>This Inner Loop Header: Depth=1
+; NOHOIST-NEXT:    addi.w $a0, $s0, 0
+; NOHOIST-NEXT:    pcaddu18i $ra, %call36(use)
+; NOHOIST-NEXT:    jirl $ra, $ra, 0
+; NOHOIST-NEXT:    add.d $s0, $s0, $s1
+; NOHOIST-NEXT:    addi.w $s1, $s1, 1
+; NOHOIST-NEXT:    blt $s1, $fp, .LBB1_4
+; NOHOIST-NEXT:  # %bb.5: # %exit
+; NOHOIST-NEXT:    ld.d $s1, $sp, 0 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s0, $sp, 8 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $fp, $sp, 16 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $ra, $sp, 24 # 8-byte Folded Reload
+; NOHOIST-NEXT:    addi.d $sp, $sp, 32
+; NOHOIST-NEXT:    ret
 entry:
   br i1 %cond, label %then, label %else
 
@@ -125,14 +186,15 @@ define void @hoist_nested(i32 %x, i32 signext %n, i32 signext %m) nounwind {
 ; CHECK-NEXT:    # =>This Loop Header: Depth=1
 ; CHECK-NEXT:    # Child Loop BB2_2 Depth 2
 ; CHECK-NEXT:    move $s3, $zero
+; CHECK-NEXT:    addi.w $s1, $s1, 0
 ; CHECK-NEXT:    .p2align 4, , 16
 ; CHECK-NEXT:  .LBB2_2: # %inner
 ; CHECK-NEXT:    # Parent Loop BB2_1 Depth=1
 ; CHECK-NEXT:    # => This Inner Loop Header: Depth=2
-; CHECK-NEXT:    addi.w $a0, $s1, 0
+; CHECK-NEXT:    move $a0, $s1
 ; CHECK-NEXT:    pcaddu18i $ra, %call36(use)
 ; CHECK-NEXT:    jirl $ra, $ra, 0
-; CHECK-NEXT:    add.d $s1, $s1, $s3
+; CHECK-NEXT:    add.w $s1, $s1, $s3
 ; CHECK-NEXT:    addi.w $s3, $s3, 1
 ; CHECK-NEXT:    blt $s3, $s0, .LBB2_2
 ; CHECK-NEXT:  # %bb.3: # %outer.latch
@@ -148,6 +210,48 @@ define void @hoist_nested(i32 %x, i32 signext %n, i32 signext %m) nounwind {
 ; CHECK-NEXT:    ld.d $ra, $sp, 40 # 8-byte Folded Reload
 ; CHECK-NEXT:    addi.d $sp, $sp, 48
 ; CHECK-NEXT:    ret
+;
+; NOHOIST-LABEL: hoist_nested:
+; NOHOIST:       # %bb.0: # %entry
+; NOHOIST-NEXT:    addi.d $sp, $sp, -48
+; NOHOIST-NEXT:    st.d $ra, $sp, 40 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $fp, $sp, 32 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s0, $sp, 24 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s1, $sp, 16 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s2, $sp, 8 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s3, $sp, 0 # 8-byte Folded Spill
+; NOHOIST-NEXT:    move $fp, $a2
+; NOHOIST-NEXT:    move $s0, $a1
+; NOHOIST-NEXT:    move $s1, $a0
+; NOHOIST-NEXT:    move $s2, $zero
+; NOHOIST-NEXT:    .p2align 4, , 16
+; NOHOIST-NEXT:  .LBB2_1: # %outer
+; NOHOIST-NEXT:    # =>This Loop Header: Depth=1
+; NOHOIST-NEXT:    # Child Loop BB2_2 Depth 2
+; NOHOIST-NEXT:    move $s3, $zero
+; NOHOIST-NEXT:    .p2align 4, , 16
+; NOHOIST-NEXT:  .LBB2_2: # %inner
+; NOHOIST-NEXT:    # Parent Loop BB2_1 Depth=1
+; NOHOIST-NEXT:    # => This Inner Loop Header: Depth=2
+; NOHOIST-NEXT:    addi.w $a0, $s1, 0
+; NOHOIST-NEXT:    pcaddu18i $ra, %call36(use)
+; NOHOIST-NEXT:    jirl $ra, $ra, 0
+; NOHOIST-NEXT:    add.d $s1, $s1, $s3
+; NOHOIST-NEXT:    addi.w $s3, $s3, 1
+; NOHOIST-NEXT:    blt $s3, $s0, .LBB2_2
+; NOHOIST-NEXT:  # %bb.3: # %outer.latch
+; NOHOIST-NEXT:    # in Loop: Header=BB2_1 Depth=1
+; NOHOIST-NEXT:    addi.w $s2, $s2, 1
+; NOHOIST-NEXT:    blt $s2, $fp, .LBB2_1
+; NOHOIST-NEXT:  # %bb.4: # %exit
+; NOHOIST-NEXT:    ld.d $s3, $sp, 0 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s2, $sp, 8 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s1, $sp, 16 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s0, $sp, 24 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $fp, $sp, 32 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $ra, $sp, 40 # 8-byte Folded Reload
+; NOHOIST-NEXT:    addi.d $sp, $sp, 48
+; NOHOIST-NEXT:    ret
 entry:
   br label %outer
 
@@ -192,6 +296,22 @@ define i64 @no_hoist_i64_phi(i64 %x, ptr %q, ptr %out, i32 signext %n) nounwind
 ; CHECK-NEXT:  # %bb.2: # %exit
 ; CHECK-NEXT:    move $a0, $a4
 ; CHECK-NEXT:    ret
+;
+; NOHOIST-LABEL: no_hoist_i64_phi:
+; NOHOIST:       # %bb.0: # %entry
+; NOHOIST-NEXT:    move $a5, $zero
+; NOHOIST-NEXT:    .p2align 4, , 16
+; NOHOIST-NEXT:  .LBB3_1: # %loop
+; NOHOIST-NEXT:    # =>This Inner Loop Header: Depth=1
+; NOHOIST-NEXT:    move $a4, $a0
+; NOHOIST-NEXT:    addi.w $a0, $a0, 0
+; NOHOIST-NEXT:    st.d $a0, $a2, 0
+; NOHOIST-NEXT:    ld.w $a0, $a1, 0
+; NOHOIST-NEXT:    addi.w $a5, $a5, 1
+; NOHOIST-NEXT:    blt $a5, $a3, .LBB3_1
+; NOHOIST-NEXT:  # %bb.2: # %exit
+; NOHOIST-NEXT:    move $a0, $a4
+; NOHOIST-NEXT:    ret
 entry:
   br label %loop
 
@@ -246,6 +366,40 @@ define void @no_hoist_i64_use(i64 %x, ptr %q, ptr %out, i32 signext %n) nounwind
 ; CHECK-NEXT:    ld.d $ra, $sp, 40 # 8-byte Folded Reload
 ; CHECK-NEXT:    addi.d $sp, $sp, 48
 ; CHECK-NEXT:    ret
+;
+; NOHOIST-LABEL: no_hoist_i64_use:
+; NOHOIST:       # %bb.0: # %entry
+; NOHOIST-NEXT:    addi.d $sp, $sp, -48
+; NOHOIST-NEXT:    st.d $ra, $sp, 40 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $fp, $sp, 32 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s0, $sp, 24 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s1, $sp, 16 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s2, $sp, 8 # 8-byte Folded Spill
+; NOHOIST-NEXT:    st.d $s3, $sp, 0 # 8-byte Folded Spill
+; NOHOIST-NEXT:    move $fp, $a3
+; NOHOIST-NEXT:    move $s0, $a2
+; NOHOIST-NEXT:    move $s1, $a1
+; NOHOIST-NEXT:    move $s2, $a0
+; NOHOIST-NEXT:    move $s3, $zero
+; NOHOIST-NEXT:    .p2align 4, , 16
+; NOHOIST-NEXT:  .LBB4_1: # %loop
+; NOHOIST-NEXT:    # =>This Inner Loop Header: Depth=1
+; NOHOIST-NEXT:    addi.w $a0, $s2, 0
+; NOHOIST-NEXT:    pcaddu18i $ra, %call36(use)
+; NOHOIST-NEXT:    jirl $ra, $ra, 0
+; NOHOIST-NEXT:    st.d $s2, $s0, 0
+; NOHOIST-NEXT:    ld.w $s2, $s1, 0
+; NOHOIST-NEXT:    addi.w $s3, $s3, 1
+; NOHOIST-NEXT:    blt $s3, $fp, .LBB4_1
+; NOHOIST-NEXT:  # %bb.2: # %exit
+; NOHOIST-NEXT:    ld.d $s3, $sp, 0 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s2, $sp, 8 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s1, $sp, 16 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $s0, $sp, 24 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $fp, $sp, 32 # 8-byte Folded Reload
+; NOHOIST-NEXT:    ld.d $ra, $sp, 40 # 8-byte Folded Reload
+; NOHOIST-NEXT:    addi.d $sp, $sp, 48
+; NOHOIST-NEXT:    ret
 entry:
   br label %loop
 
diff --git a/llvm/test/CodeGen/LoongArch/sextw-removal.ll b/llvm/test/CodeGen/LoongArch/sextw-removal.ll
index 8097acfd842ad6..3894a5ff7d3782 100644
--- a/llvm/test/CodeGen/LoongArch/sextw-removal.ll
+++ b/llvm/test/CodeGen/LoongArch/sextw-removal.ll
@@ -716,12 +716,12 @@ define signext i32 @test14b(i32 %0, i32 signext %1) {
 ; CHECK-NEXT:  # %bb.1: # %.preheader
 ; CHECK-NEXT:    ori $a2, $zero, 1
 ; CHECK-NEXT:    ori $a3, $zero, 1000
+; CHECK-NEXT:    addi.w $a0, $a0, 0
 ; CHECK-NEXT:    .p2align 4, , 16
 ; CHECK-NEXT:  .LBB14_2: # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    addi.w $a4, $a0, 0
-; CHECK-NEXT:    blt $a3, $a4, .LBB14_5
+; CHECK-NEXT:    blt $a3, $a0, .LBB14_5
 ; CHECK-NEXT:  # %bb.3: # in Loop: Header=BB14_2 Depth=1
-; CHECK-NEXT:    add.d $a0, $a2, $a0
+; CHECK-NEXT:    add.w $a0, $a2, $a0
 ; CHECK-NEXT:    addi.w $a2, $a2, 1
 ; CHECK-NEXT:    blt $a2, $a1, .LBB14_2
 ; CHECK-NEXT:  .LBB14_4:
@@ -784,12 +784,12 @@ define signext i32 @test14c(i32 zeroext %0, i32 signext %1) {
 ; CHECK-NEXT:  # %bb.1: # %.preheader
 ; CHECK-NEXT:    ori $a2, $zero, 1
 ; CHECK-NEXT:    ori $a3, $zero, 1000
+; CHECK-NEXT:    addi.w $a0, $a0, 0
 ; CHECK-NEXT:    .p2align 4, , 16
 ; CHECK-NEXT:  .LBB15_2: # =>This Inner Loop Header: Depth=1
-; CHECK-NEXT:    addi.w $a4, $a0, 0
-; CHECK-NEXT:    blt $a3, $a4, .LBB15_5
+; CHECK-NEXT:    blt $a3, $a0, .LBB15_5
 ; CHECK-NEXT:  # %bb.3: # in Loop: Header=BB15_2 Depth=1
-; CHECK-NEXT:    add.d $a0, $a2, $a0
+; CHECK-NEXT:    add.w $a0, $a2, $a0
 ; CHECK-NEXT:    addi.w $a2, $a2, 1
 ; CHECK-NEXT:    blt $a2, $a1, .LBB15_2
 ; CHECK-NEXT:  .LBB15_4:



More information about the llvm-branch-commits mailing list