From 170ab2924b1f11357a1f92179aa55cee9286d290 Mon Sep 17 00:00:00 2001 From: Paul Kirth Date: Sat, 3 May 2025 16:55:30 +0000 Subject: [PATCH] [llvm][gvn-sink] Don't try to sink inline asm 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. --- llvm/lib/Transforms/Utils/Local.cpp | 3 +- llvm/test/Transforms/GVNSink/pr138345.ll | 46 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/GVNSink/pr138345.ll diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index b3204da93049b..c171c421c5098 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -4220,8 +4220,9 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { return false; // Early exit. - if (!isa(I->getOperand(OpIdx))) + if (!isa(I->getOperand(OpIdx))) { return true; + } switch (I->getOpcode()) { default: diff --git a/llvm/test/Transforms/GVNSink/pr138345.ll b/llvm/test/Transforms/GVNSink/pr138345.ll new file mode 100644 index 0000000000000..7a29d25d84eeb --- /dev/null +++ b/llvm/test/Transforms/GVNSink/pr138345.ll @@ -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 +}