[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
b4fac94181/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.
This commit is contained in:
Paul Kirth
2025-05-05 18:16:33 -07:00
committed by GitHub
parent 1c1238d361
commit 43eafc0c4a
2 changed files with 48 additions and 1 deletions

View File

@@ -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:

View File

@@ -0,0 +1,46 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes="gvn-sink" -S %s | FileCheck %s
;; 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) {
; CHECK-LABEL: define void @c(
; CHECK-SAME: i64 [[NUM:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: switch i64 [[NUM]], label %[[SW_EPILOG:.*]] [
; CHECK-NEXT: i64 1, label %[[SW_BB:.*]]
; CHECK-NEXT: i64 0, label %[[SW_BB1:.*]]
; CHECK-NEXT: ]
; CHECK: [[SW_BB]]:
; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[PTR]], align 1
; CHECK-NEXT: call void asm sideeffect "", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 [[TMP1]], ptr @c)
; CHECK-NEXT: br label %[[SW_EPILOG]]
; CHECK: [[SW_BB1]]:
; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[PTR]], align 1
; CHECK-NEXT: call void asm sideeffect "movdqu 0 [[XMM0:%.*]] \0A\09", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 [[TMP2]], ptr @c)
; CHECK-NEXT: br label %[[SW_EPILOG]]
; CHECK: [[SW_EPILOG]]:
; CHECK-NEXT: ret void
;
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
}