Bug type: crash
Component: GVN
Bug location: llvm/lib/Transforms/Scalar/GVN.cpp: GVNPass::performScalarPRE
Issue title: [HLSL] Assert & crash in OpLowerer when resolving `llvm.dx.resource.casthandle` on a phi node
Labels: crash
HLSL
llvm:GVN
Reported by: hekota

```
RWStructuredBuffer<int> Out[4] : register(u0);

[numthreads(4,1,1)]
void main(uint GI : SV_GroupIndex) {
  for (int i = 0; i < GI; i++)
    Out[GI].IncrementCounter();
  
  Out[GI][0] = Out[GI].IncrementCounter();
}
```

https://godbolt.org/z/Ezjdfadj1

`OpLowerer::cleanupHandleCasts` is expecting the operand of `@llvm.dx.resource.casthandle` to be a `CallInst` and it is a phi node:
```
  %.pre-phi = phi target("dx.RawBuffer", i32, 1, 0) [ %1, %entry._Z4mainj.exit_crit_edge ], [ %3, %for.body.i ]

  %6 = call %dx.types.Handle @llvm.dx.resource.casthandle.s_dx.types.Handles.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %.pre-phi)
```

```
 #0 0x0000000003cff348 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/compiler-explorer/clang-trunk/bin/clang+0x3cff348)
 #1 0x0000000003cfcd1c llvm::sys::CleanupOnSignal(unsigned long) (/opt/compiler-explorer/clang-trunk/bin/clang+0x3cfcd1c)
 #2 0x0000000003c4cfd8 CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
 #3 0x00007a5b5fe42520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00000000036cca1c llvm::Value::doRAUW(llvm::Value*, llvm::Value::ReplaceMetadataUses) (/opt/compiler-explorer/clang-trunk/bin/clang+0x36cca1c)
 #5 0x0000000002b3e445 (anonymous namespace)::OpLowerer::lowerIntrinsics() (.constprop.0) DXILOpLowering.cpp:0:0
 #6 0x0000000002b40de5 (anonymous namespace)::DXILOpLoweringLegacy::runOnModule(llvm::Module&) DXILOpLowering.cpp:0:0
 #7 0x0000000003644709 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/opt/compiler-explorer/clang-trunk/bin/clang+0x3644709)
 #8 0x0000000003fa339d clang::emitBackendOutput(clang::CompilerInstance&, clang::CodeGenOptions&, llvm::StringRef, llvm::Module*, clang::BackendAction, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream>>, clang::BackendConsumer*) (/opt/compiler-explorer/clang-trunk/bin/clang+0x3fa339d)
 #9 0x000000000464753c clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/opt/compiler-explorer/clang-trunk/bin/clang+0x464753c)
#10 0x00000000062ce46c clang::ParseAST(clang::Sema&, bool, bool) (/opt/compiler-explorer/clang-trunk/bin/clang+0x62ce46c)
#11 0x0000000004647d2d clang::CodeGenAction::ExecuteAction() (/opt/compiler-explorer/clang-trunk/bin/clang+0x4647d2d)
#12 0x0000000004953a3a clang::FrontendAction::Execute() (/opt/compiler-explorer/clang-trunk/bin/clang+0x4953a3a)
#13 0x00000000048ccd7b clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/opt/compiler-explorer/clang-trunk/bin/clang+0x48ccd7b)
#14 0x0000000004a44df3 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/opt/compiler-explorer/clang-trunk/bin/clang+0x4a44df3)
#15 0x0000000000dc0775 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/opt/compiler-explorer/clang-trunk/bin/clang+0xdc0775)
#16 0x0000000000db871d ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&, llvm::ToolContext const&) driver.cpp:0:0
#17 0x00000000046ba419 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const::'lambda'()>(long) Job.cpp:0:0
#18 0x0000000003c4d3f3 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/opt/compiler-explorer/clang-trunk/bin/clang+0x3c4d3f3)
#19 0x00000000046ba639 clang::driver::CC1Command::Execute(llvm::ArrayRef<std::optional<llvm::StringRef>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, bool*) const (.part.0) Job.cpp:0:0
#20 0x000000000467d5bd clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+0x467d5bd)
#21 0x000000000467e571 clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&, bool) const (/opt/compiler-explorer/clang-trunk/bin/clang+0x467e571)
#22 0x000000000468860c clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*>>&) (/opt/compiler-explorer/clang-trunk/bin/clang+0x468860c)
#23 0x0000000000dbcf81 clang_main(int, char**, llvm::ToolContext const&) (/opt/compiler-explorer/clang-trunk/bin/clang+0xdbcf81)
#24 0x0000000000c6bb44 main (/opt/compiler-explorer/clang-trunk/bin/clang+0xc6bb44)
#25 0x00007a5b5fe29d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#26 0x00007a5b5fe29e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#27 0x0000000000db81b5 _start (/opt/compiler-explorer/clang-trunk/bin/clang+0xdb81b5)
```


Fix patch:
commit 49fcfaa15aeeed147280e6e39d802ac712ed3d74
Author: Farzon Lotfi <farzonlotfi@microsoft.com>
Date:   Tue Sep 2 17:16:42 2025 -0400

    [GVN] Turn off ScalarPRE for TokenLike Types (#156513)
    
    fixes #154407
    
    In HLSL the GVNPass was adding a phi node on
    a target extention type.
    https://hlsl.godbolt.org/z/sc14YenEe
    
    This is something we cleaned up in a past PR
    (https://github.com/llvm/llvm-project/pull/154620) by introducing
    `isTokenLikeTy`. In the case of the GVN pass the target extention type
    was still making its way through. This change makes it so if we see this
    type we don't do PRE.

diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 4baa3b3eb824..26e17cc849bf 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -2982,7 +2982,8 @@ bool GVNPass::performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred,
 bool GVNPass::performScalarPRE(Instruction *CurInst) {
   if (isa<AllocaInst>(CurInst) || CurInst->isTerminator() ||
       isa<PHINode>(CurInst) || CurInst->getType()->isVoidTy() ||
-      CurInst->mayReadFromMemory() || CurInst->mayHaveSideEffects())
+      CurInst->mayReadFromMemory() || CurInst->mayHaveSideEffects() ||
+      CurInst->getType()->isTokenLikeTy())
     return false;
 
   // Don't do PRE on compares. The PHI would prevent CodeGenPrepare from


Regression tests:
file: llvm/test/Transforms/GVN/PRE/no-phi-translate.ll
commands: opt -S -passes=gvn %s
tests: test_name: <module>
test_body: 

%"$Globals" = type { i32 }
@CBV = external constant %"$Globals"
@Out.str = private unnamed_addr constant [4 x i8] c"Out\00", align 1

define i32 @CSMain() local_unnamed_addr {
;
entry:
  %loadGlobal = load i32, ptr @CBV, align 4
  %cmp.i1.not = icmp eq i32 %loadGlobal, 0
  br i1 %cmp.i1.not, label %CSMain.exit, label %for.body.i.lr.ph

for.body.i.lr.ph:
  %buf = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 4, i32 %loadGlobal, ptr nonnull @Out.str)
  br label %for.body.i

for.body.i:
  %loopPhi = phi i32 [ 0, %for.body.i.lr.ph ], [ %inc.i, %for.body.i ]
  %updateCnt = tail call noundef i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", i32, 1, 0) %buf, i8 1)
  %inc.i = add nuw nsw i32 %loopPhi, 1
  %exitcond = icmp ne i32 %inc.i, %loadGlobal
  br i1 %exitcond, label %for.body.i, label %CSMain.exit

CSMain.exit:
  %bufExit = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 4, i32 %loadGlobal, ptr nonnull @Out.str)
  %updateCntExit = tail call noundef i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", i32, 1, 0) %bufExit, i8 1)
  ret i32 %updateCntExit
}