Skip to content

Conversation

@shiltian
Copy link
Contributor

Fixes #167500.

Copy link
Contributor Author

shiltian commented Nov 22, 2025

@llvmbot
Copy link
Member

llvmbot commented Nov 22, 2025

@llvm/pr-subscribers-llvm-ir

@llvm/pr-subscribers-backend-amdgpu

Author: Shilei Tian (shiltian)

Changes

Fixes #167500.


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

2 Files Affected:

  • (modified) llvm/lib/IR/ReplaceConstant.cpp (+9-1)
  • (added) llvm/test/CodeGen/AMDGPU/same-lds-variable-multiple-use-in-one-phi-node.ll (+51)
diff --git a/llvm/lib/IR/ReplaceConstant.cpp b/llvm/lib/IR/ReplaceConstant.cpp
index b3586b45a23f2..f3d1914a8dc82 100644
--- a/llvm/lib/IR/ReplaceConstant.cpp
+++ b/llvm/lib/IR/ReplaceConstant.cpp
@@ -91,6 +91,11 @@ bool llvm::convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts,
 
   // Replace those expandable operands with instructions
   bool Changed = false;
+  // We need to cache the instructions we've already expanded to avoid expanding
+  // the same constant multiple times in the same basic block, which is
+  // problematic when the same constant is used in a phi node multiple times.
+  DenseMap<std::pair<Constant *, BasicBlock *>, SmallVector<Instruction *, 4>>
+      ConstantToInstructionMap;
   while (!InstructionWorklist.empty()) {
     Instruction *I = InstructionWorklist.pop_back_val();
     DebugLoc Loc = I->getDebugLoc();
@@ -105,7 +110,10 @@ bool llvm::convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts,
       if (auto *C = dyn_cast<Constant>(U.get())) {
         if (ExpandableUsers.contains(C)) {
           Changed = true;
-          auto NewInsts = expandUser(BI, C);
+          SmallVector<Instruction *, 4> &NewInsts =
+              ConstantToInstructionMap[std::make_pair(C, BI->getParent())];
+          if (NewInsts.empty())
+            NewInsts = expandUser(BI, C);
           for (auto *NI : NewInsts)
             NI->setDebugLoc(Loc);
           InstructionWorklist.insert_range(NewInsts);
diff --git a/llvm/test/CodeGen/AMDGPU/same-lds-variable-multiple-use-in-one-phi-node.ll b/llvm/test/CodeGen/AMDGPU/same-lds-variable-multiple-use-in-one-phi-node.ll
new file mode 100644
index 0000000000000..35a9bee03411f
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/same-lds-variable-multiple-use-in-one-phi-node.ll
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -amdgpu-lower-module-lds %s -o - | FileCheck %s
+; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -passes=amdgpu-lower-module-lds %s -o - | FileCheck %s
+
+@lds = internal unnamed_addr addrspace(3) global [6144 x half] poison, align 2
+
+define amdgpu_kernel void @test(ptr addrspace(1) %out) {
+; CHECK-LABEL: define amdgpu_kernel void @test(
+; CHECK-SAME: ptr addrspace(1) [[OUT:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    switch i32 0, label %[[BB_3:.*]] [
+; CHECK-NEXT:      i32 18, label %[[BB_2:.*]]
+; CHECK-NEXT:      i32 1, label %[[BB_2]]
+; CHECK-NEXT:      i32 0, label %[[BB_3]]
+; CHECK-NEXT:    ]
+; CHECK:       [[BB_1:.*]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr addrspace(3) @llvm.amdgcn.kernel.test.lds to ptr
+; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[TMP0]] to i64
+; CHECK-NEXT:    switch i32 0, label %[[BB_3]] [
+; CHECK-NEXT:      i32 18, label %[[BB_2]]
+; CHECK-NEXT:      i32 1, label %[[BB_2]]
+; CHECK-NEXT:      i32 0, label %[[BB_3]]
+; CHECK-NEXT:    ]
+; CHECK:       [[BB_2]]:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ [[TMP1]], %[[BB_1]] ], [ [[TMP1]], %[[BB_1]] ], [ 10, %[[ENTRY]] ], [ 10, %[[ENTRY]] ]
+; CHECK-NEXT:    store i64 [[PHI]], ptr addrspace(1) [[OUT]], align 8
+; CHECK-NEXT:    br label %[[BB_3]]
+; CHECK:       [[BB_3]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  switch i32 0, label %bb.3 [
+  i32 18, label %bb.2
+  i32 1, label %bb.2
+  i32 0, label %bb.3
+  ]
+bb.1:
+  switch i32 0, label %bb.3 [
+  i32 18, label %bb.2
+  i32 1, label %bb.2
+  i32 0, label %bb.3
+  ]
+
+bb.2:
+  %phi = phi i64 [ ptrtoint (ptr addrspacecast (ptr addrspace(3) @lds to ptr) to i64), %bb.1 ], [ ptrtoint (ptr addrspacecast (ptr addrspace(3) @lds to ptr) to i64), %bb.1 ], [10, %entry], [10, %entry]
+  store i64 %phi, ptr addrspace(1) %out, align 8
+  br label %bb.3
+
+bb.3:
+  ret void
+}

// We need to cache the instructions we've already expanded to avoid expanding
// the same constant multiple times in the same basic block, which is
// problematic when the same constant is used in a phi node multiple times.
DenseMap<std::pair<Constant *, BasicBlock *>, SmallVector<Instruction *, 4>>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suppose the expansion of the SmallVector will not cause any trouble in the map, since it is fixed size, and when it needs expansion, it uses heap and its original location will not be moved.

@github-actions
Copy link

🐧 Linux x64 Test Results

  • 166228 tests passed
  • 2861 tests skipped
  • 2 tests failed

Failed Tests

(click on a test name to see its output)

LLVM

LLVM.CodeGen/AMDGPU/lower-kernel-lds-constexpr.ll
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 2
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt -S -mtriple=amdgcn-- -amdgpu-lower-module-lds --amdgpu-lower-module-lds-strategy=module < /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-kernel-lds-constexpr.ll | /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-kernel-lds-constexpr.ll
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt -S -mtriple=amdgcn-- -amdgpu-lower-module-lds --amdgpu-lower-module-lds-strategy=module
# .---command stderr------------
# | Instruction does not dominate all uses!
# |   %2 = getelementptr inbounds [4 x i32], ptr addrspace(3) @llvm.amdgcn.kernel.k6.lds, i32 0, i32 2
# |   %1 = ptrtoint ptr addrspace(3) %2 to i32
# | in function k6
# | LLVM ERROR: Broken function found, compilation aborted!
# | 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.	Program arguments: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt -S -mtriple=amdgcn-- -amdgpu-lower-module-lds --amdgpu-lower-module-lds-strategy=module
# | 1.	Running pass 'Function Pass Manager' on module '<stdin>'.
# | 2.	Running pass 'Module Verifier' on function '@k6'
# |  #0 0x0000000004f4c528 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/Unix/Signals.inc:834:13
# |  #1 0x0000000004f49b25 llvm::sys::RunSignalHandlers() /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/Signals.cpp:105:18
# |  #2 0x0000000004f4d5e1 SignalHandler(int, siginfo_t*, void*) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/Unix/Signals.inc:426:38
# |  #3 0x00007b8b54bdd330 (/lib/x86_64-linux-gnu/libc.so.6+0x45330)
# |  #4 0x00007b8b54c36b2c pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x9eb2c)
# |  #5 0x00007b8b54bdd27e raise (/lib/x86_64-linux-gnu/libc.so.6+0x4527e)
# |  #6 0x00007b8b54bc08ff abort (/lib/x86_64-linux-gnu/libc.so.6+0x288ff)
# |  #7 0x0000000004f125a5 llvm::report_fatal_error(llvm::Twine const&, bool) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/ErrorHandling.cpp:137:5
# |  #8 0x0000000004f123e6 (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt+0x4f123e6)
# |  #9 0x00000000055f0430 void llvm::VerifierSupport::WriteTs<llvm::Instruction const*, llvm::MDNode const*>(llvm::Instruction const* const&, llvm::MDNode const* const&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/Verifier.cpp:272:0
# | #10 0x0000000005192725 llvm::FPPassManager::runOnFunction(llvm::Function&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1398:27
# | #11 0x000000000519a6d2 llvm::FPPassManager::runOnModule(llvm::Module&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1444:13
# | #12 0x00000000051931cc runOnModule /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1513:27
# | #13 0x00000000051931cc llvm::legacy::PassManagerImpl::run(llvm::Module&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:531:44
# | #14 0x0000000004eef9b4 optMain /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/opt/optdriver.cpp:929:20
# | #15 0x00007b8b54bc21ca (/lib/x86_64-linux-gnu/libc.so.6+0x2a1ca)
# | #16 0x00007b8b54bc228b __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28b)
# | #17 0x0000000004ee82e5 _start (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt+0x4ee82e5)
# `-----------------------------
# error: command failed with exit status: -6
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-kernel-lds-constexpr.ll
# .---command stderr------------
# | FileCheck error: '<stdin>' is empty.
# | FileCheck command line:  /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-kernel-lds-constexpr.ll
# `-----------------------------
# error: command failed with exit status: 2

--

LLVM.CodeGen/AMDGPU/lower-module-lds-constantexpr.ll
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 1
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt -S -mtriple=amdgcn-- -amdgpu-lower-module-lds --amdgpu-lower-module-lds-strategy=module < /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-module-lds-constantexpr.ll | /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-module-lds-constantexpr.ll
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt -S -mtriple=amdgcn-- -amdgpu-lower-module-lds --amdgpu-lower-module-lds-strategy=module
# .---command stderr------------
# | Instruction does not dominate all uses!
# |   %6 = ptrtoint ptr %5 to i64
# |   %1 = add i64 %6, %4
# | Instruction does not dominate all uses!
# |   %4 = ptrtoint ptr %3 to i64
# |   %1 = add i64 %6, %4
# | in function timestwo
# | LLVM ERROR: Broken function found, compilation aborted!
# | 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.	Program arguments: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt -S -mtriple=amdgcn-- -amdgpu-lower-module-lds --amdgpu-lower-module-lds-strategy=module
# | 1.	Running pass 'Function Pass Manager' on module '<stdin>'.
# | 2.	Running pass 'Module Verifier' on function '@timestwo'
# |  #0 0x0000000004f4c528 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/Unix/Signals.inc:834:13
# |  #1 0x0000000004f49b25 llvm::sys::RunSignalHandlers() /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/Signals.cpp:105:18
# |  #2 0x0000000004f4d5e1 SignalHandler(int, siginfo_t*, void*) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/Unix/Signals.inc:426:38
# |  #3 0x00007ca8e3cc2330 (/lib/x86_64-linux-gnu/libc.so.6+0x45330)
# |  #4 0x00007ca8e3d1bb2c pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x9eb2c)
# |  #5 0x00007ca8e3cc227e raise (/lib/x86_64-linux-gnu/libc.so.6+0x4527e)
# |  #6 0x00007ca8e3ca58ff abort (/lib/x86_64-linux-gnu/libc.so.6+0x288ff)
# |  #7 0x0000000004f125a5 llvm::report_fatal_error(llvm::Twine const&, bool) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/Support/ErrorHandling.cpp:137:5
# |  #8 0x0000000004f123e6 (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt+0x4f123e6)
# |  #9 0x00000000055f0430 void llvm::VerifierSupport::WriteTs<llvm::Instruction const*, llvm::MDNode const*>(llvm::Instruction const* const&, llvm::MDNode const* const&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/Verifier.cpp:272:0
# | #10 0x0000000005192725 llvm::FPPassManager::runOnFunction(llvm::Function&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1398:27
# | #11 0x000000000519a6d2 llvm::FPPassManager::runOnModule(llvm::Module&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1444:13
# | #12 0x00000000051931cc runOnModule /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:1513:27
# | #13 0x00000000051931cc llvm::legacy::PassManagerImpl::run(llvm::Module&) /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/lib/IR/LegacyPassManager.cpp:531:44
# | #14 0x0000000004eef9b4 optMain /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/tools/opt/optdriver.cpp:929:20
# | #15 0x00007ca8e3ca71ca (/lib/x86_64-linux-gnu/libc.so.6+0x2a1ca)
# | #16 0x00007ca8e3ca728b __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28b)
# | #17 0x0000000004ee82e5 _start (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/opt+0x4ee82e5)
# `-----------------------------
# error: command failed with exit status: -6
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-module-lds-constantexpr.ll
# .---command stderr------------
# | FileCheck error: '<stdin>' is empty.
# | FileCheck command line:  /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/AMDGPU/lower-module-lds-constantexpr.ll
# `-----------------------------
# error: command failed with exit status: 2

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

]

bb.2:
%phi = phi i64 [ ptrtoint (ptr addrspacecast (ptr addrspace(3) @lds to ptr) to i64), %bb.1 ], [ ptrtoint (ptr addrspacecast (ptr addrspace(3) @lds to ptr) to i64), %bb.1 ], [10, %entry], [10, %entry]
Copy link
Contributor Author

@shiltian shiltian Nov 22, 2025

Choose a reason for hiding this comment

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

On a second thought, should we deduplicate the incoming BBs when we construct a phi node? In this way we don't need to fix anything else.

SmallVector<Instruction *, 4> &NewInsts =
ConstantToInstructionMap[std::make_pair(C, BI->getParent())];
if (NewInsts.empty())
NewInsts = expandUser(BI, C);
Copy link
Contributor

Choose a reason for hiding this comment

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

when NewInsts.empty() is true, there will be a copy to NewInsts after it is default constructed. Can we avoid the copy?

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.

[AMDGPU] invalid PHI node generated after AMDGPULowerModuleLDS Pass

4 participants