mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
1542bebc55
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
1521 lines
38 KiB
LLVM
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
|
|
}
|