[llvm] [LoopSplitUtils] Do not clone loops which are unsafe to clone (PR #214258)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 08:34:54 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Sean Clarke (xarkenz)
<details>
<summary>Changes</summary>
Splitting a loop clones it; however, some instructions are not allowed to be cloned, e.g. `indirectbr` and calls to `noduplicate` functions. Use `Loop::isSafeToClone` to bail in such cases.
---
Full diff: https://github.com/llvm/llvm-project/pull/214258.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/Utils/LoopSplitUtils.cpp (+6)
- (added) llvm/test/Transforms/LoopSplit/unsafe-clone.ll (+84)
``````````diff
diff --git a/llvm/lib/Transforms/Utils/LoopSplitUtils.cpp b/llvm/lib/Transforms/Utils/LoopSplitUtils.cpp
index db07e3f571f66..7e96367400904 100644
--- a/llvm/lib/Transforms/Utils/LoopSplitUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopSplitUtils.cpp
@@ -223,6 +223,12 @@ bool LoopSplitUtils::isLegal() {
return false;
}
+ // Splitting a loop clones it, so cloning must be safe.
+ if (!L->isSafeToClone()) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE ": loop not safe to clone\n");
+ return false;
+ }
+
// A computable backedge-taken count fixes the iteration space we rebuild.
const SCEV *BTC = SE->getBackedgeTakenCount(L);
if (isa<SCEVCouldNotCompute>(BTC)) {
diff --git a/llvm/test/Transforms/LoopSplit/unsafe-clone.ll b/llvm/test/Transforms/LoopSplit/unsafe-clone.ll
new file mode 100644
index 0000000000000..64c6abbd924ea
--- /dev/null
+++ b/llvm/test/Transforms/LoopSplit/unsafe-clone.ll
@@ -0,0 +1,84 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=loop-split-utils -loop-split-points=4 -S < %s | FileCheck %s
+
+declare void @use(i32)
+declare void @prevent_clone(i32) noduplicate
+
+define void @cannot_clone_noduplicate_call(i32 %n) {
+; CHECK-LABEL: define void @cannot_clone_noduplicate_call(
+; CHECK-SAME: i32 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY_LS1:.*]]:
+; CHECK-NEXT: br label %[[LOOP_LS1:.*]]
+; CHECK: [[LOOP_LS1]]:
+; CHECK-NEXT: [[IV_LS1:%.*]] = phi i32 [ 0, %[[ENTRY_LS1]] ], [ [[IV_NEXT_LS1:%.*]], %[[LOOP_LS1]] ]
+; CHECK-NEXT: call void @prevent_clone(i32 [[IV_LS1]])
+; CHECK-NEXT: [[IV_NEXT_LS1]] = add i32 [[IV_LS1]], 1
+; CHECK-NEXT: [[ITR_CHK3:%.*]] = icmp slt i32 [[IV_NEXT_LS1]], [[N]]
+; CHECK-NEXT: br i1 [[ITR_CHK3]], label %[[LOOP_LS1]], label %[[LS_EXIT1:.*]]
+; CHECK: [[LS_EXIT1]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
+ call void @prevent_clone(i32 %iv)
+ %iv.next = add i32 %iv, 1
+ %cmp = icmp slt i32 %iv.next, %n
+ br i1 %cmp, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+define i32 @cannot_clone_indirectbr(i32 %n, i1 %which) {
+; CHECK-LABEL: define i32 @cannot_clone_indirectbr(
+; CHECK-SAME: i32 [[N:%.*]], i1 [[WHICH:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[BR_ADDR:%.*]] = select i1 [[WHICH]], ptr blockaddress(@cannot_clone_indirectbr, %[[BLOCK_A:.*]]), ptr blockaddress(@cannot_clone_indirectbr, %[[BLOCK_B:.*]])
+; CHECK-NEXT: br label %[[LOOP:.*]]
+; CHECK: [[LOOP]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LS1:.*]] ]
+; CHECK-NEXT: indirectbr ptr [[BR_ADDR]], [label %[[BLOCK_A]], label %[[BLOCK_B]]]
+; CHECK: [[BLOCK_A]]:
+; CHECK-NEXT: [[VAL_A:%.*]] = add i32 [[IV]], 100
+; CHECK-NEXT: br label %[[LOOP_LS1]]
+; CHECK: [[BLOCK_B]]:
+; CHECK-NEXT: [[VAL_B:%.*]] = add i32 [[IV]], 200
+; CHECK-NEXT: br label %[[LOOP_LS1]]
+; CHECK: [[LOOP_LS1]]:
+; CHECK-NEXT: [[VAL_LS1:%.*]] = phi i32 [ [[VAL_A]], %[[BLOCK_A]] ], [ [[VAL_B]], %[[BLOCK_B]] ]
+; CHECK-NEXT: call void @use(i32 [[VAL_LS1]])
+; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[LS_FINAL_EXIT:.*]]
+; CHECK: [[LS_FINAL_EXIT]]:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ %br.addr = select i1 %which, ptr blockaddress(@cannot_clone_indirectbr, %block.a), ptr blockaddress(@cannot_clone_indirectbr, %block.b)
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %latch ]
+ indirectbr ptr %br.addr, [label %block.a, label %block.b]
+
+block.a:
+ %val.a = add i32 %iv, 100
+ br label %latch
+
+block.b:
+ %val.b = add i32 %iv, 200
+ br label %latch
+
+latch:
+ %val = phi i32 [ %val.a, %block.a ], [ %val.b, %block.b ]
+ call void @use(i32 %val)
+ %iv.next = add i32 %iv, 1
+ %cmp = icmp slt i32 %iv.next, %n
+ br i1 %cmp, label %loop, label %exit
+
+exit:
+ ret i32 0
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/214258
More information about the llvm-commits
mailing list