[llvm] InstCombine: sink loads with invariant.load metadata (PR #112692)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 17 04:23:51 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Ramkumar Ramachandra (artagnon)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/112692.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstructionCombining.cpp (+2-1)
- (modified) llvm/test/Transforms/InstCombine/sink_instruction.ll (+119-4)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 954c4cf19c2077..c8b9f166b16020 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -4822,7 +4822,8 @@ bool InstCombinerImpl::tryToSinkInstruction(Instruction *I,
// We can only sink load instructions if there is nothing between the load and
// the end of block that could change the value.
- if (I->mayReadFromMemory()) {
+ if (I->mayReadFromMemory() &&
+ !I->hasMetadata(LLVMContext::MD_invariant_load)) {
// We don't want to do any sophisticated alias analysis, so we only check
// the instructions after I in I's parent block if we try to sink to its
// successor block.
diff --git a/llvm/test/Transforms/InstCombine/sink_instruction.ll b/llvm/test/Transforms/InstCombine/sink_instruction.ll
index c938002788bc28..9341f29c2bdd98 100644
--- a/llvm/test/Transforms/InstCombine/sink_instruction.ll
+++ b/llvm/test/Transforms/InstCombine/sink_instruction.ll
@@ -86,8 +86,8 @@ define i32 @test3(ptr nocapture readonly %P, i32 %i) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: switch i32 [[I:%.*]], label [[SW_EPILOG:%.*]] [
-; CHECK-NEXT: i32 5, label [[SW_BB:%.*]]
-; CHECK-NEXT: i32 2, label [[SW_BB]]
+; CHECK-NEXT: i32 5, label [[SW_BB:%.*]]
+; CHECK-NEXT: i32 2, label [[SW_BB]]
; CHECK-NEXT: ]
; CHECK: sw.bb:
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
@@ -190,8 +190,8 @@ define i32 @test6(ptr nocapture readonly %P, i32 %i, i1 %cond) {
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDXPROM]]
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
; CHECK-NEXT: switch i32 [[I]], label [[SW_BB:%.*]] [
-; CHECK-NEXT: i32 5, label [[SW_EPILOG:%.*]]
-; CHECK-NEXT: i32 2, label [[SW_EPILOG]]
+; CHECK-NEXT: i32 5, label [[SW_EPILOG:%.*]]
+; CHECK-NEXT: i32 2, label [[SW_EPILOG]]
; CHECK-NEXT: ]
; CHECK: sw.bb:
; CHECK-NEXT: br label [[SW_EPILOG]]
@@ -272,3 +272,118 @@ abort:
call void @abort()
unreachable
}
+
+; Loads marked invariant can be sunk across critical edges.
+
+define <4 x float> @invariant_load_metadata(ptr %p, i32 %cond) {
+; CHECK-LABEL: @invariant_load_metadata(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[COND:%.*]], 0
+; CHECK-NEXT: br i1 [[C]], label [[BLOCK:%.*]], label [[END:%.*]]
+; CHECK: block:
+; CHECK-NEXT: call void @fn()
+; CHECK-NEXT: br label [[END]]
+; CHECK: end:
+; CHECK-NEXT: [[V:%.*]] = load <4 x float>, ptr [[P:%.*]], align 16, !invariant.load [[META0:![0-9]+]]
+; CHECK-NEXT: ret <4 x float> [[V]]
+;
+entry:
+ %v = load <4 x float>, ptr %p, !invariant.load !0
+ %c = icmp eq i32 %cond, 0
+ br i1 %c, label %block, label %end
+block:
+ call void @fn()
+ br label %end
+end:
+ ret <4 x float> %v
+}
+
+; Loads not marked invariant cannot be sunk across critical edges.
+
+define <4 x float> @invariant_load_neg(ptr %p, i32 %cond) {
+; CHECK-LABEL: @invariant_load_neg(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[V:%.*]] = load <4 x float>, ptr [[P:%.*]], align 16
+; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[COND:%.*]], 0
+; CHECK-NEXT: br i1 [[C]], label [[BLOCK:%.*]], label [[END:%.*]]
+; CHECK: block:
+; CHECK-NEXT: call void @fn()
+; CHECK-NEXT: br label [[END]]
+; CHECK: end:
+; CHECK-NEXT: ret <4 x float> [[V]]
+;
+entry:
+ %v = load <4 x float>, ptr %p
+ %c = icmp eq i32 %cond, 0
+ br i1 %c, label %block, label %end
+block:
+ call void @fn()
+ br label %end
+end:
+ ret <4 x float> %v
+}
+
+; Loads that aren't marked invariant but used in one branch
+; can be sunk to that branch.
+
+define void @invariant_load_use_in_br(ptr %p, i1 %cond) {
+; CHECK-LABEL: @invariant_load_use_in_br(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]]
+; CHECK: true.br:
+; CHECK-NEXT: call void @fn()
+; CHECK-NEXT: br label [[EXIT:%.*]]
+; CHECK: false.br:
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4
+; CHECK-NEXT: call void @fn(i32 [[VAL]])
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ %val = load i32, ptr %p
+ br i1 %cond, label %true.br, label %false.br
+true.br:
+ call void @fn()
+ br label %exit
+false.br:
+ call void @fn(i32 %val)
+ br label %exit
+exit:
+ ret void
+}
+
+; Invariant loads marked with metadata can be sunk past calls.
+
+define void @invariant_load_metadata_call(ptr %p, i1 %cond) {
+; CHECK-LABEL: @invariant_load_metadata_call(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @fn()
+; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]]
+; CHECK: true.br:
+; CHECK-NEXT: call void @fn()
+; CHECK-NEXT: br label [[EXIT:%.*]]
+; CHECK: false.br:
+; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0]]
+; CHECK-NEXT: call void @fn(i32 [[VAL]])
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ %val = load i32, ptr %p, !invariant.load !0
+ call void @fn()
+ br i1 %cond, label %true.br, label %false.br
+true.br:
+ call void @fn()
+ br label %exit
+false.br:
+ call void @fn(i32 %val)
+ br label %exit
+exit:
+ ret void
+}
+
+declare void @fn()
+
+!0 = !{}
``````````
</details>
https://github.com/llvm/llvm-project/pull/112692
More information about the llvm-commits
mailing list