[llvm] [Sink] Allow sinking of loads to distant blocks (PR #135986)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 29 07:16:47 PDT 2025
================
@@ -0,0 +1,198 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S < %s -passes=sink | FileCheck %s
+
+; Test that loads can be sunk to a non-immediate successor block by analyzing
+; paths for conflicting stores.
+
+declare void @readfunc() readonly willreturn
+declare void @maywritefunc() willreturn
+
+; Load can be sunk to non-immediate successor
+define void @load_can_sink(i1 %condA, i1 %condB, ptr %a, ptr %b) {
+; CHECK-LABEL: @load_can_sink(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[MERGEA:%.*]]
+; CHECK: mergeA:
+; CHECK-NEXT: br i1 [[CONDA:%.*]], label [[THENA:%.*]], label [[MERGEB:%.*]]
+; CHECK: thenA:
+; CHECK-NEXT: call void @readfunc()
+; CHECK-NEXT: br label [[MERGEB]]
+; CHECK: mergeB:
+; CHECK-NEXT: br i1 [[CONDB:%.*]], label [[THENB:%.*]], label [[MERGEC:%.*]]
+; CHECK: thenB:
+; CHECK-NEXT: [[VALUE:%.*]] = load i32, ptr [[A:%.*]], align 4
+; CHECK-NEXT: store i32 [[VALUE]], ptr [[B:%.*]], align 4
+; CHECK-NEXT: br label [[MERGEC]]
+; CHECK: mergeC:
+; CHECK-NEXT: ret void
+;
+entry:
+ %value = load i32, ptr %a, align 4
+ br label %mergeA
+mergeA:
+ br i1 %condA, label %thenA, label %mergeB
+thenA:
+ call void @readfunc()
+ br label %mergeB
+mergeB:
+ br i1 %condB, label %thenB, label %mergeC
+thenB:
+ store i32 %value, ptr %b
+ br label %mergeC
+mergeC:
+ ret void
+}
+
+; Call may store so load cannot be sunk
+define void @load_cannot_sink(i1 %condA, i1 %condB, ptr %a, ptr %b) {
+; CHECK-LABEL: @load_cannot_sink(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[MERGEA:%.*]]
+; CHECK: mergeA:
+; CHECK-NEXT: [[VALUE:%.*]] = load i32, ptr [[A:%.*]], align 4
+; CHECK-NEXT: br i1 [[CONDA:%.*]], label [[THENA:%.*]], label [[MERGEB:%.*]]
+; CHECK: thenA:
+; CHECK-NEXT: call void @maywritefunc()
+; CHECK-NEXT: br label [[MERGEB]]
+; CHECK: mergeB:
+; CHECK-NEXT: br i1 [[CONDB:%.*]], label [[THENB:%.*]], label [[MERGEC:%.*]]
+; CHECK: thenB:
+; CHECK-NEXT: store i32 [[VALUE]], ptr [[B:%.*]], align 4
+; CHECK-NEXT: br label [[MERGEC]]
+; CHECK: mergeC:
+; CHECK-NEXT: ret void
+;
+entry:
+ %value = load i32, ptr %a, align 4
+ br label %mergeA
+mergeA:
+ br i1 %condA, label %thenA, label %mergeB
+thenA:
+ call void @maywritefunc()
+ br label %mergeB
+mergeB:
+ br i1 %condB, label %thenB, label %mergeC
+thenB:
+ store i32 %value, ptr %b
+ br label %mergeC
+mergeC:
+ ret void
+}
+
+; Load can be sunk to non-immediate successor because load ptr is noalias
+define void @load_can_sink_noalias(i1 %condA, i1 %condB, ptr noalias %a, ptr %b) {
+; CHECK-LABEL: @load_can_sink_noalias(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[MERGEA:%.*]]
+; CHECK: mergeA:
+; CHECK-NEXT: br i1 [[CONDA:%.*]], label [[THENA:%.*]], label [[MERGEB:%.*]]
+; CHECK: thenA:
+; CHECK-NEXT: store i32 0, ptr [[B:%.*]], align 4
+; CHECK-NEXT: br label [[MERGEB]]
+; CHECK: mergeB:
+; CHECK-NEXT: br i1 [[CONDB:%.*]], label [[THENB:%.*]], label [[MERGEC:%.*]]
+; CHECK: thenB:
+; CHECK-NEXT: [[VALUE:%.*]] = load i32, ptr [[A:%.*]], align 4
+; CHECK-NEXT: store i32 [[VALUE]], ptr [[B]], align 4
+; CHECK-NEXT: br label [[MERGEC]]
+; CHECK: mergeC:
+; CHECK-NEXT: ret void
+;
+entry:
+ %value = load i32, ptr %a, align 4
+ br label %mergeA
+mergeA:
+ br i1 %condA, label %thenA, label %mergeB
+thenA:
+ store i32 0, ptr %b
+ br label %mergeB
+mergeB:
+ br i1 %condB, label %thenB, label %mergeC
+thenB:
+ store i32 %value, ptr %b
+ br label %mergeC
+mergeC:
+ ret void
+}
+
+; Load cannot be sunk to non-immediate successor because load ptr may alias
+define void @load_cannot_sink_alias(i1 %condA, i1 %condB, ptr %a, ptr %b) {
+; CHECK-LABEL: @load_cannot_sink_alias(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[MERGEA:%.*]]
+; CHECK: mergeA:
+; CHECK-NEXT: [[VALUE:%.*]] = load i32, ptr [[A:%.*]], align 4
+; CHECK-NEXT: br i1 [[CONDA:%.*]], label [[THENA:%.*]], label [[MERGEB:%.*]]
+; CHECK: thenA:
+; CHECK-NEXT: store i32 0, ptr [[B:%.*]], align 4
+; CHECK-NEXT: br label [[MERGEB]]
+; CHECK: mergeB:
+; CHECK-NEXT: br i1 [[CONDB:%.*]], label [[THENB:%.*]], label [[MERGEC:%.*]]
+; CHECK: thenB:
+; CHECK-NEXT: store i32 [[VALUE]], ptr [[B]], align 4
+; CHECK-NEXT: br label [[MERGEC]]
+; CHECK: mergeC:
+; CHECK-NEXT: ret void
+;
+entry:
+ %value = load i32, ptr %a, align 4
+ br label %mergeA
+mergeA:
+ br i1 %condA, label %thenA, label %mergeB
+thenA:
+ store i32 0, ptr %b
+ br label %mergeB
+mergeB:
+ br i1 %condB, label %thenB, label %mergeC
+thenB:
+ store i32 %value, ptr %b
+ br label %mergeC
+mergeC:
+ ret void
+}
+
+; Load can be sunk, but not all the way to the use.
+define void @load_can_sink_part_of_the_way(i1 %condA, i1 %condB, i1 %condC, ptr noalias %a, ptr %b) {
+; CHECK-LABEL: @load_can_sink_part_of_the_way(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[MERGEA:%.*]]
+; CHECK: mergeA:
+; CHECK-NEXT: br i1 [[CONDA:%.*]], label [[THENA:%.*]], label [[MERGEB:%.*]]
+; CHECK: thenA:
+; CHECK-NEXT: store i32 0, ptr [[B:%.*]], align 4
+; CHECK-NEXT: br label [[MERGEB]]
+; CHECK: mergeB:
+; CHECK-NEXT: [[VALUE:%.*]] = load i32, ptr [[A:%.*]], align 4
+; CHECK-NEXT: br i1 [[CONDB:%.*]], label [[THENB:%.*]], label [[MERGEC:%.*]]
+; CHECK: thenB:
+; CHECK-NEXT: call void @maywritefunc()
+; CHECK-NEXT: br label [[MERGEC]]
+; CHECK: mergeC:
+; CHECK-NEXT: br i1 [[CONDC:%.*]], label [[THENC:%.*]], label [[MERGED:%.*]]
+; CHECK: thenC:
+; CHECK-NEXT: store i32 [[VALUE]], ptr [[B]], align 4
+; CHECK-NEXT: br label [[MERGEC]]
+; CHECK: mergeD:
+; CHECK-NEXT: ret void
+;
+entry:
+ %value = load i32, ptr %a, align 4
+ br label %mergeA
+mergeA:
+ br i1 %condA, label %thenA, label %mergeB
+thenA:
+ store i32 0, ptr %b
+ br label %mergeB
+mergeB:
+ br i1 %condB, label %thenB, label %mergeC
+thenB:
+ call void @maywritefunc()
+ br label %mergeC
+mergeC:
+ br i1 %condC, label %thenC, label %mergeD
+thenC:
+ store i32 %value, ptr %b
+ br label %mergeC
+mergeD:
+ ret void
+}
----------------
LU-JOHN wrote:
Added testcase for limit.
https://github.com/llvm/llvm-project/pull/135986
More information about the llvm-commits
mailing list