[llvm] [SimplifyCFG][JumpThreading] Don't duplicate inline-asm instructions (PR #71571)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 7 10:35:53 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Cameron McInally (mcinally)
<details>
<summary>Changes</summary>
Conservatively, don't duplicate an inline-asm instruction during Threading. In this particular case, a label is defined in the inline-asm instruction. Duplicating that inline-asm instruction will result in 2 identical labels being defined, which causes an assembler error.
---
Full diff: https://github.com/llvm/llvm-project/pull/71571.diff
4 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/JumpThreading.cpp (+3-1)
- (modified) llvm/lib/Transforms/Utils/SimplifyCFG.cpp (+3-2)
- (added) llvm/test/Transforms/JumpThreading/inline-asm.ll (+47)
- (added) llvm/test/Transforms/SimplifyCFG/inline-asm-threading.ll (+49)
``````````diff
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 7a8128c5b6c0901..18d5b7b45ad2618 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -491,8 +491,10 @@ static unsigned getJumpThreadDuplicationCost(const TargetTransformInfo *TTI,
// Blocks with NoDuplicate are modelled as having infinite cost, so they
// are never duplicated.
+ // Conservatively disallow inline-asm instructions. Duplicating inline-asm
+ // instructions can potentially create duplicate labels.
if (const CallInst *CI = dyn_cast<CallInst>(I))
- if (CI->cannotDuplicate() || CI->isConvergent())
+ if (CI->cannotDuplicate() || CI->isConvergent() || CI->isInlineAsm())
return ~0U;
if (TTI->getInstructionCost(&*I, TargetTransformInfo::TCK_SizeAndLatency) ==
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 5ef3a5292af545c..b5ddc2d54fb6a2b 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -3170,9 +3170,10 @@ static bool BlockIsSimpleEnoughToThreadThrough(BasicBlock *BB) {
// Walk the loop in reverse so that we can identify ephemeral values properly
// (values only feeding assumes).
for (Instruction &I : reverse(BB->instructionsWithoutDebug(false))) {
- // Can't fold blocks that contain noduplicate or convergent calls.
+ // Can't fold blocks that contain noduplicate, convergent calls, or
+ // inline assembly.
if (CallInst *CI = dyn_cast<CallInst>(&I))
- if (CI->cannotDuplicate() || CI->isConvergent())
+ if (CI->cannotDuplicate() || CI->isConvergent() || CI->isInlineAsm())
return false;
// Ignore ephemeral values which are deleted during codegen.
diff --git a/llvm/test/Transforms/JumpThreading/inline-asm.ll b/llvm/test/Transforms/JumpThreading/inline-asm.ll
new file mode 100644
index 000000000000000..2e698e934547807
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/inline-asm.ll
@@ -0,0 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt -S -passes=jump-threading < %s | FileCheck %s
+
+; Jump threading should not be able to duplicate a block containing inline
+; assembly, since we do not know what is in the inline-asm instruction.
+
+define void @foo(i32 %n.arg, ptr %b.arg, ptr %c.arg) {
+; CHECK-LABEL: define void @foo(
+; CHECK-SAME: i32 [[N_ARG:%.*]], ptr [[B_ARG:%.*]], ptr [[C_ARG:%.*]]) {
+; CHECK-NEXT: L.entry:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[N_ARG]], 0
+; CHECK-NEXT: br i1 [[TMP0]], label [[L_B0000:%.*]], label [[L_B0002:%.*]]
+; CHECK: L.B0002:
+; CHECK-NEXT: store ptr null, ptr [[C_ARG]], align 8
+; CHECK-NEXT: store ptr null, ptr [[B_ARG]], align 8
+; CHECK-NEXT: br label [[L_B0000]]
+; CHECK: L.B0000:
+; CHECK-NEXT: call void asm sideeffect " .LABEL: \0A\09", ""()
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[N_ARG]], 0
+; CHECK-NEXT: br i1 [[TMP1]], label [[L_B0001:%.*]], label [[L_B0003:%.*]]
+; CHECK: L.B0003:
+; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[B_ARG]], align 8
+; CHECK-NEXT: call void @bar(ptr [[TMP2]])
+; CHECK-NEXT: br label [[L_B0001]]
+; CHECK: L.B0001:
+; CHECK-NEXT: ret void
+;
+L.entry:
+ %0 = icmp eq i32 %n.arg, 0
+ br i1 %0, label %L.B0000, label %L.B0002
+L.B0002:
+ store ptr null, ptr %c.arg
+ store ptr null, ptr %b.arg
+ br label %L.B0000
+L.B0000:
+ call void asm sideeffect " .LABEL: \0A\09", "" ()
+ %1 = icmp eq i32 %n.arg, 0
+ br i1 %1, label %L.B0001, label %L.B0003
+L.B0003:
+ %2 = load ptr, ptr %b.arg
+ call void @bar (ptr %2)
+ br label %L.B0001
+L.B0001:
+ ret void
+}
+
+declare void @bar(ptr)
diff --git a/llvm/test/Transforms/SimplifyCFG/inline-asm-threading.ll b/llvm/test/Transforms/SimplifyCFG/inline-asm-threading.ll
new file mode 100644
index 000000000000000..7ea7f373b3d9f88
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/inline-asm-threading.ll
@@ -0,0 +1,49 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
+
+; Jump threading should not be able to duplicate a block containing inline
+; assembly, since we do not know what is in the inline-asm instruction.
+
+define void @foo(i32 %n.arg, ptr %b.arg, ptr %c.arg) {
+; CHECK-LABEL: define void @foo(
+; CHECK-SAME: i32 [[N_ARG:%.*]], ptr [[B_ARG:%.*]], ptr [[C_ARG:%.*]]) {
+; CHECK-NEXT: L.entry:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i32 [[N_ARG]], 0
+; CHECK-NEXT: br i1 [[TMP0]], label [[L_B0000:%.*]], label [[L_B0002:%.*]]
+; CHECK: L.B0002:
+; CHECK-NEXT: store ptr null, ptr [[C_ARG]], align 8
+; CHECK-NEXT: store ptr null, ptr [[B_ARG]], align 8
+; CHECK-NEXT: br label [[L_B0000]]
+; CHECK: L.B0000:
+; CHECK-NEXT: call void asm sideeffect " .LABEL: \0A\09", ""()
+; CHECK-NEXT: br i1 [[TMP0]], label [[L_B0001:%.*]], label [[L_B0003:%.*]]
+; CHECK: L.B0003:
+; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[B_ARG]], align 8
+; CHECK-NEXT: call void @bar(ptr [[TMP1]])
+; CHECK-NEXT: br label [[L_B0001]]
+; CHECK: L.B0001:
+; CHECK-NEXT: ret void
+;
+L.entry:
+ %0 = icmp eq i32 %n.arg, 0
+ br i1 %0, label %L.B0000, label %L.B0002
+
+L.B0002: ; preds = %L.entry
+ store ptr null, ptr %c.arg
+ store ptr null, ptr %b.arg
+ br label %L.B0000
+
+L.B0000: ; preds = %L.B0002, %L.entry
+ call void asm sideeffect " .LABEL: \0A\09", ""()
+ br i1 %0, label %L.B0001, label %L.B0003
+
+L.B0003: ; preds = %L.B0000
+ %1 = load ptr, ptr %b.arg
+ call void @bar(ptr %1)
+ br label %L.B0001
+
+L.B0001: ; preds = %L.B0003, %L.B0000
+ ret void
+}
+
+declare void @bar(ptr)
``````````
</details>
https://github.com/llvm/llvm-project/pull/71571
More information about the llvm-commits
mailing list