Bug type: crash
Component: Local
Bug location: llvm/lib/Transforms/Utils/Local.cpp: llvm::canReplaceOperandWithVariable
Issue title: Assertion failure with gvn-sink
Labels: crash-on-valid
llvm:GVN
Reported by: ilovepi

I tried to enable GVN hoist/sink when compiling Fuchsia at -Oz, since that should improve size slightly, and ran into this. I know those passes have had some issues, but I figured they had some attention a while back and we should try again. Probably some value as a regression test, if nothing else.

Assertion:
```console
'llvm/lib/Analysis/LazyValueInfo.cpp:679: std::optional<ValueLatticeElement> llvm::LazyValueInfoImpl::solveBlockValueNonLocal(Value *, BasicBlock *): Assertion `isa<Argument>(Val) && "Unknown live-in to the entry block"' failed.
```

Here's a reduced test case where the assertion triggers.

```LLVM
; RUN:  opt -passes="gvn-sink,correlated-propagation" -disable-output %s

target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

define void @c(i64 %0) {
entry:
  switch i64 %0, label %sw.epilog [
    i64 1, label %sw.bb
    i64 0, label %sw.bb1
  ]

sw.bb:                                            ; preds = %entry
  %1 = load i8, ptr null, align 1
  call void asm sideeffect "", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 %1, ptr @c)
  br label %sw.epilog

sw.bb1:                                           ; preds = %entry
  %2 = load i8, ptr null, align 1
  call void asm sideeffect "movdqu 0 %xmm0           \0A\09", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 %2, ptr @c)
  br label %sw.epilog

sw.epilog:                                        ; preds = %sw.bb1, %sw.bb, %entry
  ret void
}
```

From Clang:

```c++
// RUN: clang -cc1 -Os -mllvm -enable-gvn-hoist -mllvm -enable-gvn-sink -mllvm -wholeprogramdevirt-branch-funnel-threshold=0 -emit-llvm %s
long a;
char b;
void c() {
  switch (a) {
  case 8:
    __asm("" : : "r"(b), "r"(c));
    break;
  case 6:
    __asm("movdqu 0 %%xmm0           \n\t" : : "r"(b), "r"(c));
  }
}
```


Fix patch:
commit 43eafc0c4aca0b2fd159c09d4b162c1941b4f4ed
Author: Paul Kirth <paulkirth@google.com>
Date:   Mon May 5 18:16:33 2025 -0700

    [llvm][gvn-sink] Don't try to sink inline asm (#138414)
    
    Fixes #138345. Before this patch, gvn-sink would try to sink inline
    assembly statements. Other GVN passes avoid them (see
    https://github.com/llvm/llvm-project/blob/b4fac94181c4cf17dbb7ecc2ae975712b0e4a6d1/llvm/lib/Transforms/Scalar/GVN.cpp#L2932
    Similarly, gvn-sink should skip these instructions, since they are not
    safe to move. To do this, we update the early exit in
    canReplaceOperandWithVariable, since it should have caught this case.
    It's more efficient to also skip numbering in GVNSink if the instruction
    is InlineAsm, but that should be infrequent.
    
    The test added is reduced from a failure when compiling Fuchsia with
    gvn-sink.

diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 809a0d7ebeea..ce03bc066c6e 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -4225,8 +4225,9 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) {
     return false;
 
   // Early exit.
-  if (!isa<Constant>(I->getOperand(OpIdx)))
+  if (!isa<Constant, InlineAsm>(I->getOperand(OpIdx))) {
     return true;
+  }
 
   switch (I->getOpcode()) {
   default:


Regression tests:
file: llvm/test/Transforms/GVNSink/pr138345.ll
commands: opt -passes="gvn-sink" -S %s
tests: test_name: <module>
test_body: 
;; See https://github.com/llvm/llvm-project/issues/138345 for details.
;; The program below used to crash due to taking the address of the inline asm.
;; gvn-sink shouldn't do anything in this case, so test that the pass no longer
;; generates invalid IR and no longer crashes.

define void @c(i64 %num, ptr %ptr) {
;
entry:
  switch i64 %num, label %sw.epilog [
  i64 1, label %sw.bb
  i64 0, label %sw.bb1
  ]

sw.bb:                                            ; preds = %entry
  %1 = load i8, ptr %ptr, align 1
  call void asm sideeffect "", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 %1, ptr @c)
  br label %sw.epilog

sw.bb1:                                           ; preds = %entry
  %2 = load i8, ptr %ptr, align 1
  call void asm sideeffect "movdqu 0 %xmm0           \0A\09", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 %2, ptr @c)
  br label %sw.epilog

sw.epilog:                                        ; preds = %sw.bb1, %sw.bb, %entry
  ret void
}