Skip to content

Conversation

@heiher
Copy link
Member

@heiher heiher commented Oct 16, 2025

This patch introduces a new virtual method TargetInstrInfo::isSafeToMove() to allow backends to control whether a machine instruction can be safely moved by optimization passes.

The BranchFolder pass now respects this hook when hoisting common code. By default, all instructions are considered safe to to move.

For LoongArch, isSafeToMove() is overridden to prevent relocation-related instruction sequences (e.g. PC-relative addressing and calls) from being broken by instruction motion. Correspondingly, isSchedulingBoundary() is updated to reuse this logic for consistency.

Fixes #163681

This patch introduces a new virtual method `TargetInstrInfo::isSafeToMove()`
to allow backends to control whether a machine instruction can be safely
moved by optimization passes.

The `BranchFolder` pass now respects this hook when hoisting common code.
By default, all instructions are considered safe to to move.

For LoongArch, `isSafeToMove()` is overridden to prevent relocation-related
instruction sequences (e.g. PC-relative addressing and calls) from being
broken by instruction motion. Correspondingly, `isSchedulingBoundary()` is
updated to reuse this logic for consistency.
@llvmbot
Copy link
Member

llvmbot commented Oct 16, 2025

@llvm/pr-subscribers-backend-loongarch

Author: hev (heiher)

Changes

This patch introduces a new virtual method TargetInstrInfo::isSafeToMove() to allow backends to control whether a machine instruction can be safely moved by optimization passes.

The BranchFolder pass now respects this hook when hoisting common code. By default, all instructions are considered safe to to move.

For LoongArch, isSafeToMove() is overridden to prevent relocation-related instruction sequences (e.g. PC-relative addressing and calls) from being broken by instruction motion. Correspondingly, isSchedulingBoundary() is updated to reuse this logic for consistency.

Fixes #163681


Full diff: https://github.com/llvm/llvm-project/pull/163725.diff

5 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/TargetInstrInfo.h (+11)
  • (modified) llvm/lib/CodeGen/BranchFolding.cpp (+7-2)
  • (modified) llvm/lib/CodeGen/BranchFolding.h (+1-1)
  • (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp (+27-18)
  • (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.h (+3)
diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
index 175f205328361..2dcedfb40f3e6 100644
--- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h
+++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h
@@ -1761,6 +1761,17 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
     return true;
   }
 
+  /// Return true if it's safe to move a machine instruction.
+  /// This allows the backend to prevent certain special instruction
+  /// sequences from being broken by instruction motion in optimization
+  /// passes.
+  /// By default, this returns true for every instruction.
+  virtual bool isSafeToMove(const MachineInstr &MI,
+                            const MachineBasicBlock *MBB,
+                            const MachineFunction &MF) const {
+    return true;
+  }
+
   /// Test if the given instruction should be considered a scheduling boundary.
   /// This primarily includes labels and terminators.
   virtual bool isSchedulingBoundary(const MachineInstr &MI,
diff --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index 7292bc2be0df2..8213a91a7750d 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -1818,7 +1818,7 @@ bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) {
 bool BranchFolder::HoistCommonCode(MachineFunction &MF) {
   bool MadeChange = false;
   for (MachineBasicBlock &MBB : llvm::make_early_inc_range(MF))
-    MadeChange |= HoistCommonCodeInSuccs(&MBB);
+    MadeChange |= HoistCommonCodeInSuccs(&MBB, MF);
 
   return MadeChange;
 }
@@ -1948,7 +1948,8 @@ MachineBasicBlock::iterator findHoistingInsertPosAndDeps(MachineBasicBlock *MBB,
   return PI;
 }
 
-bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
+bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB,
+                                          MachineFunction &MF) {
   MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
   SmallVector<MachineOperand, 4> Cond;
   if (TII->analyzeBranch(*MBB, TBB, FBB, Cond, true) || !TBB || Cond.empty())
@@ -1993,6 +1994,10 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
       // Hard to reason about register liveness with predicated instruction.
       break;
 
+    if (!TII->isSafeToMove(*TIB, MBB, MF))
+      // Don't hoist the instruction if it isn't safe to move.
+      break;
+
     bool IsSafe = true;
     for (MachineOperand &MO : TIB->operands()) {
       // Don't attempt to hoist instructions with register masks.
diff --git a/llvm/lib/CodeGen/BranchFolding.h b/llvm/lib/CodeGen/BranchFolding.h
index ff2bbe06c0488..8f0f14367e0eb 100644
--- a/llvm/lib/CodeGen/BranchFolding.h
+++ b/llvm/lib/CodeGen/BranchFolding.h
@@ -196,7 +196,7 @@ class TargetRegisterInfo;
 
     /// If the successors of MBB has common instruction sequence at the start of
     /// the function, move the instructions before MBB terminator if it's legal.
-    bool HoistCommonCodeInSuccs(MachineBasicBlock *MBB);
+    bool HoistCommonCodeInSuccs(MachineBasicBlock *MBB, MachineFunction &MF);
   };
 
 } // end namespace llvm
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
index c89212dae72d9..2b792184087cd 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
@@ -378,12 +378,9 @@ bool LoongArchInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
   }
 }
 
-bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
-                                              const MachineBasicBlock *MBB,
-                                              const MachineFunction &MF) const {
-  if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
-    return true;
-
+bool LoongArchInstrInfo::isSafeToMove(const MachineInstr &MI,
+                                      const MachineBasicBlock *MBB,
+                                      const MachineFunction &MF) const {
   auto MII = MI.getIterator();
   auto MIE = MBB->end();
 
@@ -429,25 +426,25 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
     auto MO2 = Lu32I->getOperand(2).getTargetFlags();
     if (MO0 == LoongArchII::MO_PCREL_HI && MO1 == LoongArchII::MO_PCREL_LO &&
         MO2 == LoongArchII::MO_PCREL64_LO)
-      return true;
+      return false;
     if ((MO0 == LoongArchII::MO_GOT_PC_HI || MO0 == LoongArchII::MO_LD_PC_HI ||
          MO0 == LoongArchII::MO_GD_PC_HI) &&
         MO1 == LoongArchII::MO_GOT_PC_LO && MO2 == LoongArchII::MO_GOT_PC64_LO)
-      return true;
+      return false;
     if (MO0 == LoongArchII::MO_IE_PC_HI && MO1 == LoongArchII::MO_IE_PC_LO &&
         MO2 == LoongArchII::MO_IE_PC64_LO)
-      return true;
+      return false;
     if (MO0 == LoongArchII::MO_DESC_PC_HI &&
         MO1 == LoongArchII::MO_DESC_PC_LO &&
         MO2 == LoongArchII::MO_DESC64_PC_LO)
-      return true;
+      return false;
     break;
   }
   case LoongArch::LU52I_D: {
     auto MO = MI.getOperand(2).getTargetFlags();
     if (MO == LoongArchII::MO_PCREL64_HI || MO == LoongArchII::MO_GOT_PC64_HI ||
         MO == LoongArchII::MO_IE_PC64_HI || MO == LoongArchII::MO_DESC64_PC_HI)
-      return true;
+      return false;
     break;
   }
   default:
@@ -487,7 +484,7 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
         auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
         auto MO2 = LoongArchII::getDirectFlags(Ld->getOperand(2));
         if (MO1 == LoongArchII::MO_DESC_PC_LO && MO2 == LoongArchII::MO_DESC_LD)
-          return true;
+          return false;
         break;
       }
       if (SecondOp == MIE ||
@@ -496,34 +493,34 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
       auto MO1 = LoongArchII::getDirectFlags(SecondOp->getOperand(2));
       if (MO0 == LoongArchII::MO_PCREL_HI && SecondOp->getOpcode() == AddiOp &&
           MO1 == LoongArchII::MO_PCREL_LO)
-        return true;
+        return false;
       if (MO0 == LoongArchII::MO_GOT_PC_HI && SecondOp->getOpcode() == LdOp &&
           MO1 == LoongArchII::MO_GOT_PC_LO)
-        return true;
+        return false;
       if ((MO0 == LoongArchII::MO_LD_PC_HI ||
            MO0 == LoongArchII::MO_GD_PC_HI) &&
           SecondOp->getOpcode() == AddiOp && MO1 == LoongArchII::MO_GOT_PC_LO)
-        return true;
+        return false;
       break;
     }
     case LoongArch::ADDI_W:
     case LoongArch::ADDI_D: {
       auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
       if (MO == LoongArchII::MO_PCREL_LO || MO == LoongArchII::MO_GOT_PC_LO)
-        return true;
+        return false;
       break;
     }
     case LoongArch::LD_W:
     case LoongArch::LD_D: {
       auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
       if (MO == LoongArchII::MO_GOT_PC_LO)
-        return true;
+        return false;
       break;
     }
     case LoongArch::PseudoDESC_CALL: {
       auto MO = LoongArchII::getDirectFlags(MI.getOperand(2));
       if (MO == LoongArchII::MO_DESC_CALL)
-        return true;
+        return false;
       break;
     }
     default:
@@ -531,6 +528,18 @@ bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
     }
   }
 
+  return true;
+}
+
+bool LoongArchInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
+                                              const MachineBasicBlock *MBB,
+                                              const MachineFunction &MF) const {
+  if (TargetInstrInfo::isSchedulingBoundary(MI, MBB, MF))
+    return true;
+
+  if (!isSafeToMove(MI, MBB, MF))
+    return true;
+
   return false;
 }
 
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
index f25958a32bec4..8457d1446ed5e 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h
@@ -64,6 +64,9 @@ class LoongArchInstrInfo : public LoongArchGenInstrInfo {
   bool isBranchOffsetInRange(unsigned BranchOpc,
                              int64_t BrOffset) const override;
 
+  bool isSafeToMove(const MachineInstr &MI, const MachineBasicBlock *MBB,
+                    const MachineFunction &MF) const override;
+
   bool isSchedulingBoundary(const MachineInstr &MI,
                             const MachineBasicBlock *MBB,
                             const MachineFunction &MF) const override;

@heiher heiher requested a review from OCHyams October 29, 2025 12:02
Copy link
Contributor

@wangleiat wangleiat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks.
This fixes #163681 and looks good for LoongArch. Let’s wait for other’s feedback before merging.

if (!TII->isSafeToMove(*TIB, MBB, MF))
// Don't hoist the instruction if it isn't safe to move.
break;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@OCHyams mind taking a look at the changes here when you get a chance? Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not best placed to review a target hook change - I'm not sure of best practice there. Your change here in BranchFolding.cpp STGM though.

@heiher heiher merged commit cdc3cb2 into main Nov 7, 2025
10 checks passed
@heiher heiher deleted the users/hev/issue-163681 branch November 7, 2025 13:01
vinay-deshmukh pushed a commit to vinay-deshmukh/llvm-project that referenced this pull request Nov 8, 2025
…ion (llvm#163725)

This patch introduces a new virtual method
`TargetInstrInfo::isSafeToMove()` to allow backends to control whether a
machine instruction can be safely moved by optimization passes.

The `BranchFolder` pass now respects this hook when hoisting common
code. By default, all instructions are considered safe to to move.

For LoongArch, `isSafeToMove()` is overridden to prevent
relocation-related instruction sequences (e.g. PC-relative addressing
and calls) from being broken by instruction motion. Correspondingly,
`isSchedulingBoundary()` is updated to reuse this logic for consistency.

Fixes llvm#163681
@nathanchance
Copy link
Member

nathanchance commented Nov 10, 2025

I am seeing a crash when building the Linux kernel with ARCH=loongarch allmodconfig and CONFIG_LTO_CLANG_THIN=y after this change. I reduced it down with cvise:

$ cat s2250-board.i
int write_regs_fp_i;
short *write_regs_fp_regs;
long s2250_s_std_norm;
void write_reg_fp(short);
void s2250_s_std() {
  if (s2250_s_std_norm)
    for (write_regs_fp_i = 0;;)
      write_reg_fp(write_regs_fp_regs[0]);
  {
    for (write_regs_fp_i = 0;;)
      write_reg_fp(write_regs_fp_regs[write_regs_fp_i]);
  }
}

$ clang --target=loongarch64-linux-gnusf -flto=thin -fno-strict-overflow -mno-relax -O2 -Wall -Werror -c -o s2250-board.o s2250-board.i

$ ld.lld -m elf64loongarch -mllvm -import-instr-limit=5 -z noexecstack -r -o s2250.o s2250-board.o

$ clang --target=loongarch64-linux-gnusf -flto=thin -fno-strict-overflow -mno-relax -O2 -Wall -Werror -c -o s2250-board.o s2250-board.i -fsanitize=kernel-address -mllvm -asan-instrumentation-with-call-threshold=0

$ ld.lld -m elf64loongarch -mllvm -import-instr-limit=5 -z noexecstack -r -o s2250.o s2250-board.o
ld.lld: llvm/include/llvm/ADT/ilist_iterator.h:168: reference llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::MachineInstr, true, true, void, false, void>, false, true>::operator*() const [OptionsT = llvm::ilist_detail::node_options<llvm::MachineInstr, true, true, void, false, void>, IsReverse = false, IsConst = true]: Assertion `!NodePtr->isKnownSentinel()' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace and instructions to reproduce the bug.
Stack dump:
0.	Running pass 'Function Pass Manager' on module 's2250-board.o'.
1.	Running pass 'Control Flow Optimizer' on function '@s2250_s_std'
 #0 0x0000aaaadc7693e8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (lld+0x36393e8)
 #1 0x0000aaaadc766d2c llvm::sys::RunSignalHandlers() (lld+0x3636d2c)
 #2 0x0000aaaadc76a210 SignalHandler(int, siginfo_t*, void*) Signals.cpp:0:0
 #3 0x0000ffff9e4699e4 (linux-vdso.so.1+0x9e4)
 #4 0x0000ffff9de4229c __pthread_kill_implementation (/lib64/libc.so.6+0x9229c)
 #5 0x0000ffff9ddec37c gsignal (/lib64/libc.so.6+0x3c37c)
 #6 0x0000ffff9ddd6660 abort (/lib64/libc.so.6+0x26660)
 #7 0x0000ffff9de34d38 __libc_message_impl (/lib64/libc.so.6+0x84d38)
 #8 0x0000ffff9dde4ef8 __assert_fail (/lib64/libc.so.6+0x34ef8)
 #9 0x0000aaaaddc92b7c llvm::LoongArchInstrInfo::isSchedulingBoundary(llvm::MachineInstr const&, llvm::MachineBasicBlock const*, llvm::MachineFunction const&) const LoongArchInstrInfo.cpp:0:0
#10 0x0000aaaade30a1c0 llvm::BranchFolder::HoistCommonCodeInSuccs(llvm::MachineBasicBlock*) BranchFolding.cpp:0:0
#11 0x0000aaaade302a24 llvm::BranchFolder::OptimizeFunction(llvm::MachineFunction&, llvm::TargetInstrInfo const*, llvm::TargetRegisterInfo const*, llvm::MachineLoopInfo*, bool) BranchFolding.cpp:0:0
#12 0x0000aaaade30ba00 (anonymous namespace)::BranchFolderLegacy::runOnMachineFunction(llvm::MachineFunction&) BranchFolding.cpp:0:0
#13 0x0000aaaade4be110 llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (lld+0x538e110)
#14 0x0000aaaadffac864 llvm::FPPassManager::runOnFunction(llvm::Function&) (lld+0x6e7c864)
#15 0x0000aaaadffb3e7c llvm::FPPassManager::runOnModule(llvm::Module&) (lld+0x6e83e7c)
#16 0x0000aaaadffad1b4 llvm::legacy::PassManagerImpl::run(llvm::Module&) (lld+0x6e7d1b4)
#17 0x0000aaaadddd99e8 codegen(llvm::lto::Config const&, llvm::TargetMachine*, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, unsigned int, llvm::Module&, llvm::ModuleSummaryIndex const&) LTOBackend.cpp:0:0
#18 0x0000aaaadddda974 llvm::lto::thinBackend(llvm::lto::Config const&, unsigned int, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::Module&, llvm::ModuleSummaryIndex const&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>*, bool, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, std::vector<unsigned char, std::allocator<unsigned char>> const&)::$_1::operator()(llvm::Module&, llvm::TargetMachine*, llvm::LLVMRemarkFileHandle) const LTOBackend.cpp:0:0
#19 0x0000aaaadddda6d4 llvm::lto::thinBackend(llvm::lto::Config const&, unsigned int, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::Module&, llvm::ModuleSummaryIndex const&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>*, bool, std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, std::vector<unsigned char, std::allocator<unsigned char>> const&) (lld+0x4caa6d4)
#20 0x0000aaaadddcda90 (anonymous namespace)::InProcessThinBackend::runThinLTOBackendThread(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::FileCache, unsigned int, llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&)::'lambda'(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>)::operator()(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>) const LTO.cpp:0:0
#21 0x0000aaaadddcd000 (anonymous namespace)::InProcessThinBackend::runThinLTOBackendThread(std::function<llvm::Expected<std::unique_ptr<llvm::CachedFileStream, std::default_delete<llvm::CachedFileStream>>> (unsigned int, llvm::Twine const&)>, llvm::FileCache, unsigned int, llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&) LTO.cpp:0:0
#22 0x0000aaaadddcd6f4 void llvm::detail::UniqueFunctionBase<void>::CallImpl<std::_Bind<(anonymous namespace)::InProcessThinBackend::start(unsigned int, llvm::BitcodeModule, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&)::'lambda'(llvm::BitcodeModule, llvm::ModuleSummaryIndex&, llvm::FunctionImporter::ImportMapTy const&, llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const&, std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const&, llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const&, llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>&) (llvm::BitcodeModule, std::reference_wrapper<llvm::ModuleSummaryIndex>, std::reference_wrapper<llvm::FunctionImporter::ImportMapTy const>, std::reference_wrapper<llvm::DenseSet<llvm::ValueInfo, llvm::DenseMapInfo<llvm::ValueInfo, void>> const>, std::reference_wrapper<std::map<unsigned long, llvm::GlobalValue::LinkageTypes, std::less<unsigned long>, std::allocator<std::pair<unsigned long const, llvm::GlobalValue::LinkageTypes>>> const>, std::reference_wrapper<llvm::DenseMap<unsigned long, llvm::GlobalValueSummary*, llvm::DenseMapInfo<unsigned long, void>, llvm::detail::DenseMapPair<unsigned long, llvm::GlobalValueSummary*>> const>, std::reference_wrapper<llvm::MapVector<llvm::StringRef, llvm::BitcodeModule, llvm::DenseMap<llvm::StringRef, unsigned int, llvm::DenseMapInfo<llvm::StringRef, void>, llvm::detail::DenseMapPair<llvm::StringRef, unsigned int>>, llvm::SmallVector<std::pair<llvm::StringRef, llvm::BitcodeModule>, 0u>>>)>>(void*) LTO.cpp:0:0
#23 0x0000aaaadcadfac0 std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_Task_setter<std::unique_ptr<std::__future_base::_Result<void>, std::__future_base::_Result_base::_Deleter>, std::thread::_Invoker<std::tuple<llvm::unique_function<void ()>>>, void>>::_M_invoke(std::_Any_data const&) BalancedPartitioning.cpp:0:0
#24 0x0000aaaadc7ac584 std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) Driver.cpp:0:0
#25 0x0000ffff9de45de4 __pthread_once_slow.isra.0 (/lib64/libc.so.6+0x95de4)
#26 0x0000ffff9de45ea4 pthread_once@@GLIBC_2.34 (/lib64/libc.so.6+0x95ea4)
#27 0x0000aaaadcadff90 std::__future_base::_Deferred_state<std::thread::_Invoker<std::tuple<llvm::unique_function<void ()>>>, void>::_M_complete_async() BalancedPartitioning.cpp:0:0
#28 0x0000aaaadcae0024 void llvm::detail::UniqueFunctionBase<void>::CallImpl<std::shared_future<void> llvm::ThreadPoolInterface::asyncImpl<void>(llvm::unique_function<void ()>, llvm::ThreadPoolTaskGroup*)::'lambda'()>(void*) BalancedPartitioning.cpp:0:0
#29 0x0000aaaadcae6a38 llvm::StdThreadPool::processTasks(llvm::ThreadPoolTaskGroup*) (lld+0x39b6a38)
#30 0x0000aaaadcae8820 void* llvm::thread::ThreadProxy<std::tuple<llvm::StdThreadPool::grow(int)::$_0>>(void*) ThreadPool.cpp:0:0
#31 0x0000ffff9de40414 start_thread (/lib64/libc.so.6+0x90414)
#32 0x0000ffff9deab71c thread_start (/lib64/libc.so.6+0xfb71c)

@heiher
Copy link
Member Author

heiher commented Nov 11, 2025

I am seeing a crash when building the Linux kernel with ARCH=loongarch allmodconfig and CONFIG_LTO_CLANG_THIN=y after this change.

Thanks for your report. The issue was caused by a typo. I'll re-land the corrected patch.

heiher added a commit that referenced this pull request Nov 11, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Nov 11, 2025
heiher added a commit that referenced this pull request Nov 12, 2025
…tion motion" (#167465)

This patch introduces a new virtual method
`TargetInstrInfo::isSafeToMove()` to allow backends to control whether a
machine instruction can be safely moved by optimization passes.

The `BranchFolder` pass now respects this hook when hoisting common
code. By default, all instructions are considered safe to to move.

For LoongArch, `isSafeToMove()` is overridden to prevent
relocation-related instruction sequences (e.g. PC-relative addressing
and calls) from being broken by instruction motion. Correspondingly,
`isSchedulingBoundary()` is updated to reuse this logic for consistency.

Relands #163725
heiher added a commit to llvmbot/llvm-project that referenced this pull request Nov 12, 2025
…tion motion" (llvm#167465)

This patch introduces a new virtual method
`TargetInstrInfo::isSafeToMove()` to allow backends to control whether a
machine instruction can be safely moved by optimization passes.

The `BranchFolder` pass now respects this hook when hoisting common
code. By default, all instructions are considered safe to to move.

For LoongArch, `isSafeToMove()` is overridden to prevent
relocation-related instruction sequences (e.g. PC-relative addressing
and calls) from being broken by instruction motion. Correspondingly,
`isSchedulingBoundary()` is updated to reuse this logic for consistency.

Relands llvm#163725

(cherry picked from commit ea10026)
dyung pushed a commit to llvmbot/llvm-project that referenced this pull request Nov 12, 2025
…tion motion" (llvm#167465)

This patch introduces a new virtual method
`TargetInstrInfo::isSafeToMove()` to allow backends to control whether a
machine instruction can be safely moved by optimization passes.

The `BranchFolder` pass now respects this hook when hoisting common
code. By default, all instructions are considered safe to to move.

For LoongArch, `isSafeToMove()` is overridden to prevent
relocation-related instruction sequences (e.g. PC-relative addressing
and calls) from being broken by instruction motion. Correspondingly,
`isSchedulingBoundary()` is updated to reuse this logic for consistency.

Relands llvm#163725

(cherry picked from commit ea10026)
dyung pushed a commit to llvmbot/llvm-project that referenced this pull request Nov 13, 2025
…tion motion" (llvm#167465)

This patch introduces a new virtual method
`TargetInstrInfo::isSafeToMove()` to allow backends to control whether a
machine instruction can be safely moved by optimization passes.

The `BranchFolder` pass now respects this hook when hoisting common
code. By default, all instructions are considered safe to to move.

For LoongArch, `isSafeToMove()` is overridden to prevent
relocation-related instruction sequences (e.g. PC-relative addressing
and calls) from being broken by instruction motion. Correspondingly,
`isSchedulingBoundary()` is updated to reuse this logic for consistency.

Relands llvm#163725

(cherry picked from commit ea10026)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[LoongArch] Unable to constrain instruction placement when using the large code model

7 participants