[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