Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
123 changes: 119 additions & 4 deletions llvm/test/Transforms/InstCombine/sink_instruction.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]]
Expand Down Expand Up @@ -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 = !{}