1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 05:01:59 +01:00
Alina Sbirlea 1542bebc55 [LoopPassManager + MemorySSA] Only enable use of MemorySSA for LPMs known to preserve it.
Summary:
Add a flag to the FunctionToLoopAdaptor that allows enabling MemorySSA only for the loop pass managers that are known to preserve it.

If an LPM is known to have only loop transforms that *all* preserve MemorySSA, then use MemorySSA if `EnableMSSALoopDependency` is set.
If an LPM has loop passes that do not preserve MemorySSA, then the flag passed is `false`, regardless of the value of `EnableMSSALoopDependency`.

When using a custom loop pass pipeline via `passes=...`, use keyword `loop` vs `loop-mssa` to use MemorySSA in that LPM. If a loop that does not preserve MemorySSA is added while using the `loop-mssa` keyword, that's an error.

Add the new `loop-mssa` keyword to a few tests where a difference occurs when enabling MemorySSA.

Reviewers: chandlerc

Subscribers: mehdi_amini, Prazek, george.burgess.iv, sanjoy.google, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D66376

llvm-svn: 369548
2019-08-21 17:00:57 +00:00

1521 lines
38 KiB
LLVM

; RUN: opt -S -licm < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
; RUN: opt -S -licm -licm-control-flow-hoisting=1 < %s | FileCheck %s -check-prefixes=CHECK,CHECK-ENABLED
; RUN: opt -S -licm -licm-control-flow-hoisting=0 < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
; RUN: opt -passes='require<opt-remark-emit>,loop(licm)' -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
; RUN: opt -passes='require<opt-remark-emit>,loop(licm)' -licm-control-flow-hoisting=1 -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-ENABLED
; RUN: opt -passes='require<opt-remark-emit>,loop(licm)' -licm-control-flow-hoisting=0 -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
; RUN: opt -passes='require<opt-remark-emit>,loop-mssa(licm)' -licm-control-flow-hoisting=1 -verify-memoryssa -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-ENABLED
; Enable run below when adding promotion. e.g. "store i32 %phi, i32* %p" is promoted to phi.lcssa.
; opt -passes='require<opt-remark-emit>,loop-mssa(licm)' -licm-control-flow-hoisting=0 -verify-memoryssa -S < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
; CHECK-LABEL: @triangle_phi
define void @triangle_phi(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK: %cmp1 = icmp sgt i32 %x, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK: %add = add i32 %x, 1
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: phi i32 [ %add, %[[IF_LICM]] ], [ %x, %entry ]
; CHECK-ENABLED: store i32 %phi, i32* %p
; CHECK-ENABLED: %cmp2 = icmp ne i32 %phi, 0
; CHECK: br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %then
if:
%add = add i32 %x, 1
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %x, %loop ]
; CHECK-DISABLED: %cmp2 = icmp ne i32 %phi, 0
then:
%phi = phi i32 [ %add, %if ], [ %x, %loop ]
store i32 %phi, i32* %p
%cmp2 = icmp ne i32 %phi, 0
br i1 %cmp2, label %loop, label %end
; CHECK-LABEL: end:
; CHECK-DISABLED: %[[PHI_LCSSA:.*]] = phi i32 [ %phi, %then ]
; CHECK-DISABLED: store i32 %[[PHI_LCSSA]], i32* %p
end:
ret void
}
; CHECK-LABEL: @diamond_phi
define void @diamond_phi(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK: %cmp1 = icmp sgt i32 %x, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-DAG: %add = add i32 %x, 1
; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
; CHECK-ENABLED: [[ELSE_LICM]]:
; CHECK-DAG: %sub = sub i32 %x, 1
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]
; CHECK-ENABLED: %phi = phi i32 [ %add, %[[IF_LICM]] ], [ %sub, %[[ELSE_LICM]] ]
; CHECK-ENABLED: store i32 %phi, i32* %p
; CHECK-ENABLED: %cmp2 = icmp ne i32 %phi, 0
; CHECK: br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %else
if:
%add = add i32 %x, 1
br label %then
else:
%sub = sub i32 %x, 1
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %sub, %else ]
; CHECK-DISABLED: %cmp2 = icmp ne i32 %phi, 0
then:
%phi = phi i32 [ %add, %if ], [ %sub, %else ]
store i32 %phi, i32* %p
%cmp2 = icmp ne i32 %phi, 0
br i1 %cmp2, label %loop, label %end
; CHECK-LABEL: end:
; CHECK-DISABLED: %[[PHI_LCSSA:.*]] = phi i32 [ %phi, %then ]
; CHECK-DISABLED: store i32 %[[PHI_LCSSA]], i32* %p
end:
ret void
}
; TODO: This is currently too complicated for us to be able to hoist the phi.
; CHECK-LABEL: @three_way_phi
define void @three_way_phi(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
; CHECK-DAG: %add = add i32 %x, 1
; CHECK-DAG: %cmp2 = icmp sgt i32 %add, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK: %sub = sub i32 %x, 1
; CHECK: br label %loop
entry:
br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %then
if:
%add = add i32 %x, 1
%cmp2 = icmp sgt i32 %add, 0
br i1 %cmp2, label %if.if, label %then
if.if:
%sub = sub i32 %x, 1
br label %then
then:
%phi = phi i32 [ 0, %loop ], [ %add, %if ], [ %sub, %if.if ]
store i32 %phi, i32* %p
%cmp3 = icmp ne i32 %phi, 0
br i1 %cmp3, label %loop, label %end
end:
ret void
}
; TODO: This is currently too complicated for us to be able to hoist the phi.
; CHECK-LABEL: @tree_phi
define void @tree_phi(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
; CHECK-DAG: %add = add i32 %x, 1
; CHECK-DAG: %cmp2 = icmp sgt i32 %add, 0
; CHECK-DAG: %sub = sub i32 %x, 1
; CHECK: br label %loop
entry:
br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %else
if:
%add = add i32 %x, 1
%cmp2 = icmp sgt i32 %add, 0
br i1 %cmp2, label %if.if, label %if.else
if.if:
br label %then
if.else:
br label %then
else:
%sub = sub i32 %x, 1
br label %then
then:
%phi = phi i32 [ %add, %if.if ], [ 0, %if.else ], [ %sub, %else ]
store i32 %phi, i32* %p
%cmp3 = icmp ne i32 %phi, 0
br i1 %cmp3, label %loop, label %end
end:
ret void
}
; TODO: We can hoist the first phi, but not the second.
; CHECK-LABEL: @phi_phi
define void @phi_phi(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
; CHECK-DAG: %add = add i32 %x, 1
; CHECK-DAG: %cmp2 = icmp sgt i32 %add, 0
; CHECK-DAG: %sub = sub i32 %x, 1
; CHECK-ENABLED: br i1 %cmp2, label %[[IF_IF_LICM:.*]], label %[[IF_ELSE_LICM:.*]]
; CHECK-ENABLED: [[IF_IF_LICM]]:
; CHECK-ENABLED: br label %[[IF_THEN_LICM:.*]]
; CHECK-ENABLED: [[IF_ELSE_LICM]]:
; CHECK-ENABLED: br label %[[IF_THEN_LICM]]
; CHECK-ENABLED: [[IF_THEN_LICM]]:
; CHECK-ENABLED: %phi1 = phi i32 [ %add, %[[IF_IF_LICM]] ], [ 0, %[[IF_ELSE_LICM]] ]
; CHECK: br label %loop
entry:
br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %else
if:
%add = add i32 %x, 1
%cmp2 = icmp sgt i32 %add, 0
br i1 %cmp2, label %if.if, label %if.else
if.if:
br label %if.then
if.else:
br label %if.then
; CHECK-LABEL: if.then:
; CHECK-DISABLED: %phi1 = phi i32 [ %add, %if.if ], [ 0, %if.else ]
if.then:
%phi1 = phi i32 [ %add, %if.if ], [ 0, %if.else ]
br label %then
else:
%sub = sub i32 %x, 1
br label %then
; CHECK-LABEL: then:
; CHECK: %phi2 = phi i32 [ %phi1, %if.then ], [ %sub, %else ]
then:
%phi2 = phi i32 [ %phi1, %if.then ], [ %sub, %else ]
store i32 %phi2, i32* %p
%cmp3 = icmp ne i32 %phi2, 0
br i1 %cmp3, label %loop, label %end
end:
ret void
}
; Check that we correctly duplicate empty control flow.
; CHECK-LABEL: @empty_triangle_phi
define i8 @empty_triangle_phi(i32 %x, i32 %y) {
; CHECK-LABEL: entry:
; CHECK: %cmp1 = icmp eq i32 %x, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
; CHECK: %cmp2 = icmp eq i32 %y, 0
; CHECK: br label %loop
loop:
%cmp1 = icmp eq i32 %x, 0
br i1 %cmp1, label %if, label %then
if:
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %loop ]
then:
%phi = phi i8 [ 0, %if ], [ 1, %loop ]
%cmp2 = icmp eq i32 %y, 0
br i1 %cmp2, label %end, label %loop
end:
ret i8 %phi
}
; CHECK-LABEL: @empty_diamond_phi
define i8 @empty_diamond_phi(i32 %x, i32 %y) {
; CHECK-LABEL: entry:
; CHECK: %cmp1 = icmp eq i32 %x, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
; CHECK-ENABLED: [[ELSE_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %[[ELSE_LICM]] ]
; CHECK: %cmp2 = icmp eq i32 %y, 0
; CHECK: br label %loop
loop:
%cmp1 = icmp eq i32 %x, 0
br i1 %cmp1, label %if, label %else
if:
br label %then
else:
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %else ]
then:
%phi = phi i8 [ 0, %if ], [ 1, %else ]
%cmp2 = icmp eq i32 %y, 0
br i1 %cmp2, label %end, label %loop
end:
ret i8 %phi
}
; Check that we correctly handle the case that the first thing we try to hoist is a phi.
; CHECK-LABEL: @empty_triangle_phi_first
define i8 @empty_triangle_phi_first(i32 %x, i1 %cond) {
; CHECK-LABEL: entry:
; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
; CHECK: %cmp = icmp eq i32 %x, 0
; CHECK: br label %loop
loop:
br i1 %cond, label %if, label %then
if:
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %loop ]
then:
%phi = phi i8 [ 0, %if ], [ 1, %loop ]
%cmp = icmp eq i32 %x, 0
br i1 %cmp, label %end, label %loop
end:
ret i8 %phi
}
; CHECK-LABEL: @empty_diamond_phi
define i8 @empty_diamond_phi_first(i32 %x, i1 %cond) {
; CHECK-LABEL: entry:
; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
; CHECK-ENABLED: [[ELSE_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %[[ELSE_LICM]] ]
; CHECK: %cmp = icmp eq i32 %x, 0
; CHECK: br label %loop
loop:
br i1 %cond, label %if, label %else
if:
br label %then
else:
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %else ]
then:
%phi = phi i8 [ 0, %if ], [ 1, %else ]
%cmp = icmp eq i32 %x, 0
br i1 %cmp, label %end, label %loop
end:
ret i8 %phi
}
; CHECK-LABEL: @empty_triangle_phi_first
define i8 @empty_triangle_phi_first_empty_loop_head(i32 %x, i1 %cond) {
; CHECK-LABEL: entry:
; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
; CHECK: %cmp = icmp eq i32 %x, 0
; CHECK: br label %loop
loop:
br label %test
test:
br i1 %cond, label %if, label %then
if:
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %test ]
then:
%phi = phi i8 [ 0, %if ], [ 1, %test ]
%cmp = icmp eq i32 %x, 0
br i1 %cmp, label %end, label %loop
end:
ret i8 %phi
}
; CHECK-LABEL: @empty_diamond_phi_first_empty_loop_head
define i8 @empty_diamond_phi_first_empty_loop_head(i32 %x, i1 %cond) {
; CHECK-LABEL: entry:
; CHECK-ENABLED: br i1 %cond, label %[[IF_LICM:.*]], label %[[ELSE_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
; CHECK-ENABLED: [[ELSE_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i8 [ 0, %[[IF_LICM]] ], [ 1, %[[ELSE_LICM]] ]
; CHECK: %cmp = icmp eq i32 %x, 0
; CHECK: br label %loop
loop:
br label %test
test:
br i1 %cond, label %if, label %else
if:
br label %then
else:
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i8 [ 0, %if ], [ 1, %else ]
then:
%phi = phi i8 [ 0, %if ], [ 1, %else ]
%cmp = icmp eq i32 %x, 0
br i1 %cmp, label %end, label %loop
end:
ret i8 %phi
}
; The phi is on one branch of a diamond while simultaneously at the end of a
; triangle. Check that we duplicate the triangle and not the diamond.
; CHECK-LABEL: @triangle_diamond
define void @triangle_diamond(i32* %ptr, i32 %x, i32 %y) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp ne i32 %x, 0
; CHECK-DAG: %cmp2 = icmp ne i32 %y, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i32 [ 0, %[[IF_LICM]] ], [ 127, %entry ]
; CHECK: br label %loop
loop:
%cmp1 = icmp ne i32 %x, 0
br i1 %cmp1, label %if, label %then
if:
%cmp2 = icmp ne i32 %y, 0
br i1 %cmp2, label %if.then, label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i32 [ 0, %if ], [ 127, %loop ]
then:
%phi = phi i32 [ 0, %if ], [ 127, %loop ]
store i32 %phi, i32* %ptr
br label %end
if.then:
br label %end
end:
br label %loop
}
; As the previous, but the end of the diamond is the head of the loop.
; CHECK-LABEL: @triangle_diamond_backedge
define void @triangle_diamond_backedge(i32* %ptr, i32 %x, i32 %y) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp ne i32 %x, 0
; CHECK-DAG: %cmp2 = icmp ne i32 %y, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i32 [ 0, %[[IF_LICM]] ], [ 127, %entry ]
; CHECK: br label %loop
loop:
%cmp1 = icmp ne i32 %x, 0
br i1 %cmp1, label %if, label %then
if:
%cmp2 = icmp ne i32 %y, 0
br i1 %cmp2, label %backedge, label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i32 [ 0, %if ], [ 127, %loop ]
then:
%phi = phi i32 [ 0, %if ], [ 127, %loop ]
store i32 %phi, i32* %ptr
br label %loop
backedge:
br label %loop
}
; TODO: The inner diamonds can be hoisted, but not currently the outer diamond
; CHECK-LABEL: @diamonds_inside_diamond
define void @diamonds_inside_diamond(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
; CHECK-DAG: %cmp3 = icmp slt i32 %x, -10
; CHECK-ENABLED: br i1 %cmp3, label %[[ELSE_IF_LICM:.*]], label %[[ELSE_ELSE_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[ELSE_IF_LICM]]:
; CHECK-ENABLED: br label %[[ELSE_THEN_LICM:.*]]
; CHECK-ENABLED: [[ELSE_ELSE_LICM]]:
; CHECK-ENABLED: br label %[[ELSE_THEN_LICM]]
; CHECK-ENABLED: [[ELSE_THEN_LICM]]:
; CHECK-ENABLED: %phi2 = phi i32 [ 2, %[[ELSE_IF_LICM]] ], [ 3, %[[ELSE_ELSE_LICM]] ]
; CHECK: %cmp2 = icmp sgt i32 %x, 10
; CHECK-ENABLED: br i1 %cmp2, label %[[IF_IF_LICM:.*]], label %[[IF_ELSE_LICM:.*]]
; CHECK-ENABLED: [[IF_IF_LICM]]:
; CHECK-ENABLED: br label %[[IF_THEN_LICM:.*]]
; CHECK-ENABLED: [[IF_ELSE_LICM]]:
; CHECK-ENABLED: br label %[[IF_THEN_LICM]]
; CHECK-ENABLED: [[IF_THEN_LICM]]:
; CHECK-ENABLED: %phi1 = phi i32 [ 0, %[[IF_IF_LICM]] ], [ 1, %[[IF_ELSE_LICM]] ]
; CHECK: br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %else
if:
%cmp2 = icmp sgt i32 %x, 10
br i1 %cmp2, label %if.if, label %if.else
if.if:
br label %if.then
if.else:
br label %if.then
; CHECK-LABEL: if.then:
; CHECK-DISABLED: %phi1 = phi i32 [ 0, %if.if ], [ 1, %if.else ]
if.then:
%phi1 = phi i32 [ 0, %if.if ], [ 1, %if.else ]
br label %then
else:
%cmp3 = icmp slt i32 %x, -10
br i1 %cmp3, label %else.if, label %else.else
else.if:
br label %else.then
else.else:
br label %else.then
; CHECK-LABEL: else.then:
; CHECK-DISABLED: %phi2 = phi i32 [ 2, %else.if ], [ 3, %else.else ]
else.then:
%phi2 = phi i32 [ 2, %else.if ], [ 3, %else.else ]
br label %then
; CHECK-LABEL: then:
; CHECK: %phi3 = phi i32 [ %phi1, %if.then ], [ %phi2, %else.then ]
; CHECK: %cmp4 = icmp ne i32 %phi3, 0
then:
%phi3 = phi i32 [ %phi1, %if.then ], [ %phi2, %else.then ]
store i32 %phi3, i32* %p
%cmp4 = icmp ne i32 %phi3, 0
br i1 %cmp4, label %loop, label %end
end:
ret void
}
; We can hoist blocks that contain an edge that exits the loop by ignoring that
; edge in the hoisted block.
; CHECK-LABEL: @triangle_phi_loopexit
define void @triangle_phi_loopexit(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %add = add i32 %x, 1
; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
; CHECK-DAG: %cmp2 = icmp sgt i32 10, %add
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi = phi i32 [ %add, %[[IF_LICM]] ], [ %x, %entry ]
; CHECK: br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %then
if:
%add = add i32 %x, 1
%cmp2 = icmp sgt i32 10, %add
br i1 %cmp2, label %then, label %end
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %x, %loop ]
then:
%phi = phi i32 [ %add, %if ], [ %x, %loop ]
store i32 %phi, i32* %p
%cmp3 = icmp ne i32 %phi, 0
br i1 %cmp3, label %loop, label %end
end:
ret void
}
; CHECK-LABEL: @diamond_phi_oneloopexit
define void @diamond_phi_oneloopexit(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %add = add i32 %x, 1
; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
; CHECK-DAG: %cmp2 = icmp sgt i32 10, %add
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
; CHECK-ENABLED: [[ELSE_LICM]]:
; CHECK-DAG: %sub = sub i32 %x, 1
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]
; CHECK-ENABLED: %phi = phi i32 [ %add, %[[IF_LICM]] ], [ %sub, %[[ELSE_LICM]] ]
; CHECK-ENABLED: %cmp3 = icmp ne i32 %phi, 0
; CHECK: br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %else
if:
%add = add i32 %x, 1
%cmp2 = icmp sgt i32 10, %add
br i1 %cmp2, label %then, label %end
else:
%sub = sub i32 %x, 1
br label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %sub, %else ]
then:
%phi = phi i32 [ %add, %if ], [ %sub, %else ]
store i32 %phi, i32* %p
%cmp3 = icmp ne i32 %phi, 0
br i1 %cmp3, label %loop, label %end
end:
ret void
}
; CHECK-LABEL: @diamond_phi_twoloopexit
define void @diamond_phi_twoloopexit(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %sub = sub i32 %x, 1
; CHECK-DAG: %add = add i32 %x, 1
; CHECK-DAG: %cmp1 = icmp sgt i32 %x, 0
; CHECK-DAG: %cmp2 = icmp sgt i32 10, %add
; CHECK-DAG: %cmp3 = icmp sgt i32 10, %sub
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM:.*]]
; CHECK-ENABLED: [[ELSE_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]
; CHECK-ENABLED: %phi = phi i32 [ %add, %[[IF_LICM]] ], [ %sub, %[[ELSE_LICM]] ]
; CHECK-ENABLED: %cmp4 = icmp ne i32 %phi, 0
; CHECK: br label %loop
loop:
%cmp1 = icmp sgt i32 %x, 0
br i1 %cmp1, label %if, label %else
if:
%add = add i32 %x, 1
%cmp2 = icmp sgt i32 10, %add
br i1 %cmp2, label %then, label %end
else:
%sub = sub i32 %x, 1
%cmp3 = icmp sgt i32 10, %sub
br i1 %cmp3, label %then, label %end
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi = phi i32 [ %add, %if ], [ %sub, %else ]
; CHECK-DISABLED: %cmp4 = icmp ne i32 %phi, 0
then:
%phi = phi i32 [ %add, %if ], [ %sub, %else ]
store i32 %phi, i32* %p
%cmp4 = icmp ne i32 %phi, 0
br i1 %cmp4, label %loop, label %end
end:
ret void
}
; The store cannot be hoisted, so add and shr cannot be hoisted into a
; conditional block.
; CHECK-LABEL: @conditional_use
define void @conditional_use(i32 %x, i32* %p) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cond = icmp ugt i32 %x, 0
; CHECK-DAG: %add = add i32 %x, 5
; CHECK-DAG: %shr = ashr i32 %add, 1
; CHECK: br label %loop
entry:
br label %loop
loop:
%cond = icmp ugt i32 %x, 0
br i1 %cond, label %if, label %else
; CHECK-LABEL: if:
; CHECK: store i32 %shr, i32* %p, align 4
if:
%add = add i32 %x, 5
%shr = ashr i32 %add, 1
store i32 %shr, i32* %p, align 4
br label %then
else:
br label %then
then:
br label %loop
}
; A diamond with two triangles on the left and one on the right. This test is
; to check that we have a unique loop preheader when we hoist the store (and so
; don't fail an assertion).
; CHECK-LABEL: @triangles_in_diamond
define void @triangles_in_diamond(i32* %ptr) {
; CHECK-LABEL: entry:
; CHECK: store i32 0, i32* %ptr, align 4
; CHECK: br label %loop
entry:
br label %loop
loop:
br i1 undef, label %left_triangle_1, label %right_triangle
left_triangle_1:
br i1 undef, label %left_triangle_1_if, label %left_triangle_2
left_triangle_1_if:
br label %left_triangle_2
left_triangle_2:
br i1 undef, label %left_triangle_2_if, label %left_triangle_2_then
left_triangle_2_if:
br label %left_triangle_2_then
left_triangle_2_then:
br label %loop.end
right_triangle:
br i1 undef, label %right_triangle.if, label %right_triangle.then
right_triangle.if:
br label %right_triangle.then
right_triangle.then:
br label %loop.end
loop.end:
store i32 0, i32* %ptr, align 4
br label %loop
}
; %cmp dominates its used after being hoisted, but not after %brmerge is rehoisted
; CHECK-LABEL: @rehoist
define void @rehoist(i8* %this, i32 %x) {
; CHECK-LABEL: entry:
; CHECK-DAG: %sub = add nsw i32 %x, -1
; CHECK-DAG: %fptr = bitcast i8* %this to void (i8*)*
; CHECK-DAG: %cmp = icmp eq i32 0, %sub
; CHECK-DAG: %brmerge = or i1 %cmp, true
entry:
%sub = add nsw i32 %x, -1
br label %loop
loop:
br i1 undef, label %if1, label %else1
if1:
%fptr = bitcast i8* %this to void (i8*)*
call void %fptr(i8* %this)
br label %then1
else1:
br label %then1
then1:
%cmp = icmp eq i32 0, %sub
br i1 %cmp, label %end, label %else2
else2:
%brmerge = or i1 %cmp, true
br i1 %brmerge, label %if3, label %end
if3:
br label %end
end:
br label %loop
}
; A test case that uses empty blocks in a way that can cause control flow
; hoisting to get confused.
; CHECK-LABEL: @empty_blocks_multiple_conditional_branches
define void @empty_blocks_multiple_conditional_branches(float %arg, float* %ptr) {
; CHECK-LABEL: entry
; CHECK-DAG: %div1 = fmul float %arg, 4.000000e+00
; CHECK-DAG: %div2 = fmul float %arg, 2.000000e+00
entry:
br label %loop
; The exact path to the phi isn't checked here, because it depends on whether
; cond2 or cond3 is hoisted first
; CHECK-ENABLED: %phi = phi float [ 0.000000e+00, %{{.*}} ], [ %div1, %{{.*}} ]
; CHECK: br label %loop
loop:
br i1 undef, label %backedge2, label %cond1
cond1:
br i1 undef, label %cond1.if, label %cond1.else
cond1.else:
br label %cond3
cond1.if:
br label %cond1.if.next
cond1.if.next:
br label %cond2
cond2:
%div1 = fmul float %arg, 4.000000e+00
br i1 undef, label %cond2.if, label %cond2.then
cond2.if:
br label %cond2.then
; CHECK-LABEL: cond2.then:
; CHECK-DISABLED: %phi = phi float [ 0.000000e+00, %cond2 ], [ %div1, %cond2.if ]
cond2.then:
%phi = phi float [ 0.000000e+00, %cond2 ], [ %div1, %cond2.if ]
store float %phi, float* %ptr
br label %backedge2
cond3:
br i1 undef, label %cond3.then, label %cond3.if
cond3.if:
%div2 = fmul float %arg, 2.000000e+00
store float %div2, float* %ptr
br label %cond3.then
cond3.then:
br label %loop
backedge2:
br label %loop
}
; We can't do much here, so mainly just check that we don't crash.
; CHECK-LABEL: @many_path_phi
define void @many_path_phi(i32* %ptr1, i32* %ptr2) {
; CHECK-LABEL: entry:
; CHECK-DAG: %gep3 = getelementptr inbounds i32, i32* %ptr2, i32 2
; CHECK-DAG: %gep2 = getelementptr inbounds i32, i32* %ptr2, i32 2
; CHECK: br label %loop
entry:
br label %loop
loop:
%phi1 = phi i32 [ 0, %entry ], [ %phi2, %end ]
%cmp1 = icmp ugt i32 %phi1, 3
br i1 %cmp1, label %cond2, label %cond1
cond1:
br i1 undef, label %end, label %cond1.else
cond1.else:
%gep2 = getelementptr inbounds i32, i32* %ptr2, i32 2
%val2 = load i32, i32* %gep2, align 4
%cmp2 = icmp eq i32 %val2, 13
br i1 %cmp2, label %cond1.end, label %end
cond1.end:
br label %end
cond2:
br i1 undef, label %end, label %cond2.else
cond2.else:
%gep3 = getelementptr inbounds i32, i32* %ptr2, i32 2
%val3 = load i32, i32* %gep3, align 4
%cmp3 = icmp eq i32 %val3, 13
br i1 %cmp3, label %cond2.end, label %end
cond2.end:
br label %end
end:
%phi2 = phi i32 [ 1, %cond1 ], [ 2, %cond1.else ], [ 3, %cond1.end ], [ 4, %cond2 ], [ 5, %cond2.else ], [ 6, %cond2.end ]
br label %loop
}
; Check that we correctly handle the hoisting of %gep when theres a critical
; edge that branches to the preheader.
; CHECK-LABEL: @crit_edge
define void @crit_edge(i32* %ptr, i32 %idx, i1 %cond1, i1 %cond2) {
; CHECK-LABEL: entry:
; CHECK: %gep = getelementptr inbounds i32, i32* %ptr, i32 %idx
; CHECK: br label %preheader
entry:
br label %preheader
preheader:
br label %loop
loop:
br i1 %cond1, label %then, label %if
if:
%gep = getelementptr inbounds i32, i32* %ptr, i32 %idx
%val = load i32, i32* %gep
br label %then
then:
%phi = phi i32 [ %val, %if ], [ 0, %loop ]
store i32 %phi, i32* %ptr
br i1 %cond2, label %loop, label %crit_edge
crit_edge:
br label %preheader
}
; Check that the conditional sub is correctly hoisted from the inner loop to the
; preheader of the outer loop.
; CHECK-LABEL: @hoist_from_innermost_loop
define void @hoist_from_innermost_loop(i32 %nx, i32* %ptr) {
; CHECK-LABEL: entry:
; CHECK-DAG: %sub = sub nsw i32 0, %nx
; CHECK: br label %outer_loop
entry:
br label %outer_loop
outer_loop:
br label %middle_loop
middle_loop:
br label %inner_loop
inner_loop:
br i1 undef, label %inner_loop_end, label %if
if:
%sub = sub nsw i32 0, %nx
store i32 %sub, i32* %ptr, align 4
br label %inner_loop_end
inner_loop_end:
br i1 undef, label %inner_loop, label %middle_loop_end
middle_loop_end:
br i1 undef, label %middle_loop, label %outer_loop_end
outer_loop_end:
br label %outer_loop
}
; We have a diamond starting from %if, but %if.if is also reachable from %loop,
; so %gep should not be conditionally hoisted.
; CHECK-LABEL: @diamond_with_extra_in_edge
define void @diamond_with_extra_in_edge(i32* %ptr1, i32* %ptr2, i32 %arg) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp2 = icmp ne i32 0, %arg
; CHECK-DAG: %gep = getelementptr i32, i32* %ptr1, i32 4
; CHECK: br label %loop
entry:
br label %loop
loop:
%phi1 = phi i32 [ 0, %entry ], [ %phi2, %then ]
%cmp1 = icmp ugt i32 16, %phi1
br i1 %cmp1, label %if, label %if.if
if:
%cmp2 = icmp ne i32 0, %arg
br i1 %cmp2, label %if.if, label %if.else
if.if:
%gep = getelementptr i32, i32* %ptr1, i32 4
%val = load i32, i32* %gep, align 4
br label %then
if.else:
br label %then
then:
%phi2 = phi i32 [ %val, %if.if ], [ %phi1, %if.else ]
store i32 %phi2, i32* %ptr2, align 4
br label %loop
}
; %loop/%if/%then form a triangle, but %loop/%if/%then/%end also form a diamond.
; The triangle should be picked for conditional hoisting.
; CHECK-LABEL: @both_triangle_and_diamond
define void @both_triangle_and_diamond(i32* %ptr1, i32* %ptr2, i32 %arg) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp ne i32 0, %arg
; CHECK-DAG: %gep = getelementptr i32, i32* %ptr1, i32 4
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_LICM:.*]], label %[[THEN_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF_LICM]]:
; CHECK-ENABLED: br label %[[THEN_LICM]]
; CHECK-ENABLED: [[THEN_LICM]]:
; CHECK-ENABLED: %phi2 = phi i32 [ 0, %[[IF_LICM]] ], [ 1, %entry ]
; CHECK: br label %loop
loop:
%phi1 = phi i32 [ 0, %entry ], [ %phi3, %end ]
%cmp1 = icmp ne i32 0, %arg
br i1 %cmp1, label %if, label %then
if:
%gep = getelementptr i32, i32* %ptr1, i32 4
%val = load i32, i32* %gep, align 4
%cmp2 = icmp ugt i32 16, %phi1
br i1 %cmp2, label %end, label %then
; CHECK-LABEL: then:
; CHECK-DISABLED: %phi2 = phi i32 [ 0, %if ], [ 1, %loop ]
then:
%phi2 = phi i32 [ 0, %if ], [ 1, %loop ]
br label %end
end:
%phi3 = phi i32 [ %phi2, %then ], [ %val, %if ]
store i32 %phi3, i32* %ptr2, align 4
br label %loop
}
; We shouldn't duplicate the branch at the end of %loop and should instead hoist
; %val to %entry.
; CHECK-LABEL: @same_destination_branch
define i32 @same_destination_branch(i32 %arg1, i32 %arg2) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp ne i32 %arg2, 0
; CHECK-DAG: %val = add i32 %arg1, 1
; CHECK: br label %loop
entry:
br label %loop
; CHECK-LABEL: loop:
; CHECK: %phi = phi i32 [ 0, %entry ], [ %add, %then ]
loop:
%phi = phi i32 [ 0, %entry ], [ %add, %then ]
%add = add i32 %phi, 1
%cmp1 = icmp ne i32 %arg2, 0
br i1 %cmp1, label %if, label %if
if:
%val = add i32 %arg1, 1
br label %then
then:
%cmp2 = icmp ne i32 %val, %phi
br i1 %cmp2, label %loop, label %end
end:
ret i32 %val
}
; Diamond-like control flow but the left/right blocks actually have the same
; destinations.
; TODO: We could potentially hoist all of phi2-4, but currently only hoist phi2.
; CHECK-LABEL: @diamond_like_same_destinations
define i32 @diamond_like_same_destinations(i32 %arg1, i32 %arg2) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp ne i32 %arg1, 0
; CHECK-DAG: %cmp2 = icmp ugt i32 %arg2, 1
; CHECK-DAG: %cmp3 = icmp ugt i32 %arg2, 2
; CHECK-ENABLED: br i1 %cmp1, label %[[LEFT1_LICM:.*]], label %[[RIGHT1_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[LEFT1_LICM]]:
; CHECK-ENABLED: br label %[[LEFT2_LICM:.*]]
; CHECK-ENABLED: [[RIGHT1_LICM]]:
; CHECK-ENABLED: br label %[[LEFT2_LICM]]
; CHECK-ENABLED: [[LEFT2_LICM]]:
; CHECK-ENABLED: %phi2 = phi i32 [ 0, %[[LEFT1_LICM]] ], [ 1, %[[RIGHT1_LICM]] ]
; CHECK: br label %loop
loop:
%phi1 = phi i32 [ 0, %entry ], [ %add, %loopend ]
%add = add i32 %phi1, 1
%cmp1 = icmp ne i32 %arg1, 0
br i1 %cmp1, label %left1, label %right1
left1:
%cmp2 = icmp ugt i32 %arg2, 1
br i1 %cmp2, label %left2, label %right2
right1:
%cmp3 = icmp ugt i32 %arg2, 2
br i1 %cmp3, label %left2, label %right2
; CHECK-LABEL: left2:
; CHECK-DISABLED: %phi2 = phi i32 [ 0, %left1 ], [ 1, %right1 ]
left2:
%phi2 = phi i32 [ 0, %left1 ], [ 1, %right1 ]
br label %loopend
; CHECK-LABEL: right2:
; CHECK: %phi3 = phi i32 [ 2, %left1 ], [ 3, %right1 ]
right2:
%phi3 = phi i32 [ 2, %left1 ], [ 3, %right1 ]
br label %loopend
; CHECK-LABEL: loopend:
; CHECK: %phi4 = phi i32 [ %phi2, %left2 ], [ %phi3, %right2 ]
loopend:
%phi4 = phi i32 [ %phi2, %left2 ], [ %phi3, %right2 ]
%cmp4 = icmp ne i32 %phi1, 32
br i1 %cmp4, label %loop, label %end
end:
ret i32 %phi4
}
; A phi with multiple incoming values for the same block due to a branch with
; two destinations that are actually the same. We can't hoist this.
; TODO: This could be hoisted by erasing one of the incoming values.
; CHECK-LABEL: @phi_multiple_values_same_block
define i32 @phi_multiple_values_same_block(i32 %arg) {
; CHECK-LABEL: entry:
; CHECK: %cmp = icmp sgt i32 %arg, 4
; CHECK-NOT: phi
; CHECK: br label %loop
entry:
br label %loop
loop:
%cmp = icmp sgt i32 %arg, 4
br i1 %cmp, label %if, label %then
if:
br i1 undef, label %then, label %then
then:
%phi = phi i32 [ %arg, %loop ], [ 1, %if ], [ 1, %if ]
br i1 undef, label %exit, label %loop
exit:
ret i32 %phi
}
; %phi is conditionally used in %d, and the store that %d is used in cannot be
; hoisted. This means that we have to rehoist %d, but have to make sure to
; rehoist it after %phi.
; CHECK-LABEL: @phi_conditional_use
define i64 @phi_conditional_use(i32 %f, i32* %g) {
; CHECK-LABEL: entry:
; CHECK: %cmp1 = icmp eq i32 %f, 1
; CHECK: %cmp2 = icmp eq i32 %f, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_END_LICM:.*]], label %[[IF_THEN_LICM:.*]]
entry:
%cmp1 = icmp eq i32 %f, 1
%cmp2 = icmp eq i32 %f, 0
br label %loop
; CHECK-ENABLED: [[IF_THEN_LICM]]:
; CHECK-ENABLED: br label %[[IF_END_LICM]]
; CHECK-ENABLED: [[IF_END_LICM]]:
; CHECK-ENABLED: %phi = phi i64 [ 0, %entry ], [ 1, %[[IF_THEN_LICM]] ]
; CHECK-ENABLED: %d = getelementptr inbounds i32, i32* %g, i64 %phi
; CHECK-ENABLED: i1 %cmp2, label %[[LOOP_BACKEDGE_LICM:.*]], label %[[IF_THEN2_LICM:.*]]
; CHECK-ENABLED: [[IF_THEN2_LICM]]:
; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
; CHECK: br label %loop
loop:
br i1 %cmp1, label %if.end, label %if.then
if.then:
br label %if.end
; CHECK-LABEL: if.end:
; CHECK-DISABLED: %phi = phi i64 [ 0, %loop ], [ 1, %if.then ]
if.end:
%phi = phi i64 [ 0, %loop ], [ 1, %if.then ]
br i1 %cmp2, label %loop.backedge, label %if.then2
; CHECK-LABEL: if.then2:
; CHECK-DISABLED: %d = getelementptr inbounds i32, i32* %g, i64 %phi
if.then2:
%d = getelementptr inbounds i32, i32* %g, i64 %phi
store i32 1, i32* %d, align 4
br label %loop.backedge
loop.backedge:
br label %loop
}
; As above, but we have two such phis
; CHECK-LABEL: @phi_conditional_use_twice
define i64 @phi_conditional_use_twice(i32 %f, i32* %g) {
; CHECK-LABEL: entry:
; CHECK: %cmp1 = icmp eq i32 %f, 1
; CHECK: %cmp2 = icmp eq i32 %f, 0
; CHECK-ENABLED: br i1 %cmp1, label %[[IF_END_LICM:.*]], label %[[IF_THEN_LICM:.*]]
entry:
%cmp1 = icmp eq i32 %f, 1
%cmp2 = icmp eq i32 %f, 0
%cmp3 = icmp sgt i32 %f, 0
br label %loop
; CHECK-ENABLED: [[IF_THEN_LICM]]:
; CHECK-ENABLED: br label %[[IF_END_LICM]]
; CHECK-ENABLED: [[IF_END_LICM]]:
; CHECK-ENABLED: %phi1 = phi i64 [ 0, %entry ], [ 1, %[[IF_THEN_LICM]] ]
; CHECK-ENABLED: %d = getelementptr inbounds i32, i32* %g, i64 %phi1
; CHECK-ENABLED: i1 %cmp2, label %[[IF_END2_LICM:.*]], label %[[IF_THEN2_LICM:.*]]
; CHECK-ENABLED: [[IF_THEN2_LICM]]:
; CHECK-ENABLED: br label %[[IF_END2_LICM]]
; CHECK-ENABLED: [[IF_END2_LICM]]:
; CHECK-ENABLED: %phi2 = phi i64 [ 2, %[[IF_END_LICM]] ], [ 3, %[[IF_THEN2_LICM]] ]
; CHECK-ENABLED: %e = getelementptr inbounds i32, i32* %g, i64 %phi2
; CHECK-ENABLED: i1 %cmp3, label %[[LOOP_BACKEDGE_LICM:.*]], label %[[IF_THEN3_LICM:.*]]
; CHECK-ENABLED: [[IF_THEN3_LICM]]:
; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
; CHECK: br label %loop
loop:
br i1 %cmp1, label %if.end, label %if.then
if.then:
br label %if.end
; CHECK-LABEL: if.end:
; CHECK-DISABLED: %phi1 = phi i64 [ 0, %loop ], [ 1, %if.then ]
if.end:
%phi1 = phi i64 [ 0, %loop ], [ 1, %if.then ]
br i1 %cmp2, label %if.end2, label %if.then2
; CHECK-LABEL: if.then2:
; CHECK-DISABLED: %d = getelementptr inbounds i32, i32* %g, i64 %phi1
if.then2:
%d = getelementptr inbounds i32, i32* %g, i64 %phi1
store i32 1, i32* %d, align 4
br label %if.end2
; CHECK-LABEL: if.end2:
; CHECK-DISABLED: %phi2 = phi i64 [ 2, %if.end ], [ 3, %if.then2 ]
if.end2:
%phi2 = phi i64 [ 2, %if.end ], [ 3, %if.then2 ]
br i1 %cmp3, label %loop.backedge, label %if.then3
; CHECK-LABEL: if.then3:
; CHECK-DISABLED: %e = getelementptr inbounds i32, i32* %g, i64 %phi2
if.then3:
%e = getelementptr inbounds i32, i32* %g, i64 %phi2
store i32 1, i32* %e, align 4
br label %loop.backedge
loop.backedge:
br label %loop
}
; The order that we hoist instructions from the loop is different to the textual
; order in the function. Check that we can rehoist this correctly.
; CHECK-LABEL: @rehoist_wrong_order_1
define void @rehoist_wrong_order_1(i32* %ptr) {
; CHECK-LABEL: entry
; CHECK-DAG: %gep2 = getelementptr inbounds i32, i32* %ptr, i64 2
; CHECK-DAG: %gep3 = getelementptr inbounds i32, i32* %ptr, i64 3
; CHECK-DAG: %gep1 = getelementptr inbounds i32, i32* %ptr, i64 1
; CHECK-ENABLED: br i1 undef, label %[[IF1_LICM:.*]], label %[[ELSE1_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF1_LICM]]:
; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM:.*]]
; CHECK-ENABLED: [[ELSE1_LICM]]:
; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
; CHECK-ENABLED: br i1 undef, label %[[IF3_LICM:.*]], label %[[END_LICM:.*]]
; CHECK-ENABLED: [[IF3_LICM]]:
; CHECK-ENABLED: br label %[[END_LICM]]
; CHECK-ENABLED: [[END_LICM]]:
; CHECK: br label %loop
loop:
br i1 undef, label %if1, label %else1
if1:
%gep1 = getelementptr inbounds i32, i32* %ptr, i64 1
store i32 0, i32* %gep1, align 4
br label %loop.backedge
else1:
%gep2 = getelementptr inbounds i32, i32* %ptr, i64 2
store i32 0, i32* %gep2, align 4
br i1 undef, label %if2, label %loop.backedge
if2:
br i1 undef, label %if3, label %end
if3:
%gep3 = getelementptr inbounds i32, i32* %ptr, i64 3
store i32 0, i32* %gep3, align 4
br label %end
end:
br label %loop.backedge
loop.backedge:
br label %loop
}
; CHECK-LABEL: @rehoist_wrong_order_2
define void @rehoist_wrong_order_2(i32* %ptr) {
; CHECK-LABEL: entry
; CHECK-DAG: %gep2 = getelementptr inbounds i32, i32* %ptr, i64 2
; CHECK-DAG: %gep3 = getelementptr inbounds i32, i32* %gep2, i64 3
; CHECK-DAG: %gep1 = getelementptr inbounds i32, i32* %ptr, i64 1
; CHECK-ENABLED: br i1 undef, label %[[IF1_LICM:.*]], label %[[ELSE1_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF1_LICM]]:
; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM:.*]]
; CHECK-ENABLED: [[ELSE1_LICM]]:
; CHECK-ENABLED: br label %[[LOOP_BACKEDGE_LICM]]
; CHECK-ENABLED: [[LOOP_BACKEDGE_LICM]]:
; CHECK-ENABLED: br i1 undef, label %[[IF3_LICM:.*]], label %[[END_LICM:.*]]
; CHECK-ENABLED: [[IF3_LICM]]:
; CHECK-ENABLED: br label %[[END_LICM]]
; CHECK-ENABLED: [[END_LICM]]:
; CHECK: br label %loop
loop:
br i1 undef, label %if1, label %else1
if1:
%gep1 = getelementptr inbounds i32, i32* %ptr, i64 1
store i32 0, i32* %gep1, align 4
br label %loop.backedge
else1:
%gep2 = getelementptr inbounds i32, i32* %ptr, i64 2
store i32 0, i32* %gep2, align 4
br i1 undef, label %if2, label %loop.backedge
if2:
br i1 undef, label %if3, label %end
if3:
%gep3 = getelementptr inbounds i32, i32* %gep2, i64 3
store i32 0, i32* %gep3, align 4
br label %end
end:
br label %loop.backedge
loop.backedge:
br label %loop
}
; CHECK-LABEL: @rehoist_wrong_order_3
define void @rehoist_wrong_order_3(i32* %ptr) {
; CHECK-LABEL: entry
; CHECK-DAG: %gep2 = getelementptr inbounds i32, i32* %ptr, i64 2
; CHECK-DAG: %gep1 = getelementptr inbounds i32, i32* %ptr, i64 1
; CHECK-ENABLED: br i1 undef, label %[[IF1_LICM:.*]], label %[[ELSE1_LICM:.*]]
entry:
br label %loop
; CHECK-ENABLED: [[IF1_LICM]]:
; CHECK-ENABLED: br label %[[IF2_LICM:.*]]
; CHECK-ENABLED: [[ELSE1_LICM]]:
; CHECK-ENABLED: br label %[[IF2_LICM]]
; CHECK-ENABLED: [[IF2_LICM]]:
; CHECK-ENABLED: %phi = phi i32* [ %gep1, %[[IF1_LICM]] ], [ %gep2, %[[ELSE1_LICM]] ]
; CHECK-ENABLED: %gep3 = getelementptr inbounds i32, i32* %phi, i64 3
; CHECK-ENABLED: br i1 undef, label %[[IF3_LICM:.*]], label %[[END_LICM:.*]]
; CHECK-ENABLED: [[IF3_LICM]]:
; CHECK-ENABLED: br label %[[END_LICM]]
; CHECK-ENABLED: [[END_LICM]]:
; CHECK: br label %loop
loop:
br i1 undef, label %if1, label %else1
if1:
%gep1 = getelementptr inbounds i32, i32* %ptr, i64 1
store i32 0, i32* %gep1, align 4
br label %if2
else1:
%gep2 = getelementptr inbounds i32, i32* %ptr, i64 2
store i32 0, i32* %gep2, align 4
br i1 undef, label %if2, label %loop.backedge
if2:
%phi = phi i32* [ %gep1, %if1 ], [ %gep2, %else1 ]
br i1 undef, label %if3, label %end
if3:
%gep3 = getelementptr inbounds i32, i32* %phi, i64 3
store i32 0, i32* %gep3, align 4
br label %end
end:
br label %loop.backedge
loop.backedge:
br label %loop
}