Skip to content

Commit e680ddb

Browse files
committed
[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. We also update the early exit in canReplaceOperandWithVariable, since it should have caught this case. We keep the new logic in GVNSink.cpp, since its more efficient to skip numbering those instructions. The test added is reduced from a failure when compiling Fuchsia. There were two distinct failure modes. One occurred when only running gvn-sink alone, but a different failure happened when running correlated-propagation afterwards.
1 parent 060f3f0 commit e680ddb

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

llvm/lib/Transforms/Scalar/GVNSink.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,9 @@ class GVNSink {
548548
if (isa<PHINode>(I) || I->isEHPad() || isa<AllocaInst>(I) ||
549549
I->getType()->isTokenTy())
550550
return true;
551+
// Inline asm can't be sunk either.
552+
if (auto *CB = dyn_cast<CallBase>(I); CB->isInlineAsm())
553+
return true;
551554
return false;
552555
}
553556

llvm/lib/Transforms/Utils/Local.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -4220,8 +4220,11 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) {
42204220
return false;
42214221

42224222
// Early exit.
4223-
if (!isa<Constant>(I->getOperand(OpIdx)))
4223+
if (!isa<Constant>(I->getOperand(OpIdx))) {
4224+
if(const auto *CB = dyn_cast<CallBase>(I))
4225+
return !CB->isInlineAsm();
42244226
return true;
4227+
}
42254228

42264229
switch (I->getOpcode()) {
42274230
default:
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes="gvn-sink" -S %s | FileCheck %s
3+
4+
;; See https://github.com/llvm/llvm-project/issues/138345 for details.
5+
;; The program below used to crash due to taking the address of the inline asm.
6+
;; gvn-sink shouldn't do anything in this case, so test that the pass no longer
7+
;; generates invalid IR and no longer crashes.
8+
9+
define void @c(i64 %num, ptr %ptr) {
10+
; CHECK-LABEL: define void @c(
11+
; CHECK-SAME: i64 [[NUM:%.*]], ptr [[PTR:%.*]]) {
12+
; CHECK-NEXT: [[ENTRY:.*:]]
13+
; CHECK-NEXT: switch i64 [[NUM]], label %[[SW_EPILOG:.*]] [
14+
; CHECK-NEXT: i64 1, label %[[SW_BB:.*]]
15+
; CHECK-NEXT: i64 0, label %[[SW_BB1:.*]]
16+
; CHECK-NEXT: ]
17+
; CHECK: [[SW_BB]]:
18+
; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[PTR]], align 1
19+
; CHECK-NEXT: call void asm sideeffect "", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 [[TMP1]], ptr @c)
20+
; CHECK-NEXT: br label %[[SW_EPILOG]]
21+
; CHECK: [[SW_BB1]]:
22+
; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[PTR]], align 1
23+
; CHECK-NEXT: call void asm sideeffect "movdqu 0 [[XMM0:%.*]] \0A\09", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 [[TMP2]], ptr @c)
24+
; CHECK-NEXT: br label %[[SW_EPILOG]]
25+
; CHECK: [[SW_EPILOG]]:
26+
; CHECK-NEXT: ret void
27+
;
28+
entry:
29+
switch i64 %num, label %sw.epilog [
30+
i64 1, label %sw.bb
31+
i64 0, label %sw.bb1
32+
]
33+
34+
sw.bb: ; preds = %entry
35+
%1 = load i8, ptr %ptr, align 1
36+
call void asm sideeffect "", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 %1, ptr @c)
37+
br label %sw.epilog
38+
39+
sw.bb1: ; preds = %entry
40+
%2 = load i8, ptr %ptr, align 1
41+
call void asm sideeffect "movdqu 0 %xmm0 \0A\09", "r,r,~{dirflag},~{fpsr},~{flags}"(i8 %2, ptr @c)
42+
br label %sw.epilog
43+
44+
sw.epilog: ; preds = %sw.bb1, %sw.bb, %entry
45+
ret void
46+
}

0 commit comments

Comments
 (0)