; RUN: opt -S -passes=licm < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
; RUN: opt -S -passes=licm -licm-control-flow-hoisting=1 < %s | FileCheck %s -check-prefixes=CHECK,CHECK-ENABLED
; RUN: opt -S -passes=licm -licm-control-flow-hoisting=0 < %s | FileCheck %s -check-prefixes=CHECK,CHECK-DISABLED
; RUN: opt -passes='require<opt-remark-emit>,loop-mssa(licm)' -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, ptr %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, ptr %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, ptr %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, ptr %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]], ptr %p
end:
ret void
}
; CHECK-LABEL: @diamond_phi
define void @diamond_phi(i32 %x, ptr %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, ptr %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, ptr %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]], ptr %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, ptr %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, ptr %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, ptr %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, ptr %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, ptr %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, ptr %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(ptr %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, ptr %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(ptr %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, ptr %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, ptr %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, ptr %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.
define void @triangle_phi_loopexit(i32 %x, ptr %p) {
; CHECK-DISABLED-LABEL: @triangle_phi_loopexit(
; CHECK-DISABLED-NEXT: entry:
; CHECK-DISABLED-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 1
; CHECK-DISABLED-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], 0
; CHECK-DISABLED-NEXT: [[CMP2:%.*]] = icmp sgt i32 10, [[ADD]]
; CHECK-DISABLED-NEXT: br label [[LOOP:%.*]]
; CHECK-DISABLED: loop:
; CHECK-DISABLED-NEXT: br i1 [[CMP1]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK-DISABLED: if:
; CHECK-DISABLED-NEXT: br i1 [[CMP2]], label [[THEN]], label [[END:%.*]]
; CHECK-DISABLED: then:
; CHECK-DISABLED-NEXT: [[PHI:%.*]] = phi i32 [ [[ADD]], [[IF]] ], [ [[X]], [[LOOP]] ]
; CHECK-DISABLED-NEXT: store i32 [[PHI]], ptr [[P:%.*]], align 4
; CHECK-DISABLED-NEXT: [[CMP3:%.*]] = icmp ne i32 [[PHI]], 0
; CHECK-DISABLED-NEXT: br i1 [[CMP3]], label [[LOOP]], label [[END]]
; CHECK-DISABLED: end:
; CHECK-DISABLED-NEXT: ret void
;
; CHECK-ENABLED-LABEL: @triangle_phi_loopexit(
; CHECK-ENABLED-NEXT: entry:
; CHECK-ENABLED-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 1
; CHECK-ENABLED-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], 0
; CHECK-ENABLED-NEXT: [[CMP2:%.*]] = icmp sgt i32 10, [[ADD]]
; CHECK-ENABLED-NEXT: br i1 [[CMP1]], label [[IF_LICM:%.*]], label [[THEN_LICM:%.*]]
; CHECK-ENABLED: if.licm:
; CHECK-ENABLED-NEXT: br label [[THEN_LICM]]
; CHECK-ENABLED: then.licm:
; CHECK-ENABLED-NEXT: [[PHI:%.*]] = phi i32 [ [[ADD]], [[IF_LICM]] ], [ [[X]], [[ENTRY:%.*]] ]
; CHECK-ENABLED-NEXT: [[CMP3:%.*]] = icmp ne i32 [[PHI]], 0
; CHECK-ENABLED-NEXT: br label [[LOOP:%.*]]
; CHECK-ENABLED: loop:
; CHECK-ENABLED-NEXT: br i1 [[CMP1]], label [[IF:%.*]], label [[THEN:%.*]]
; CHECK-ENABLED: if:
; CHECK-ENABLED-NEXT: br i1 [[CMP2]], label [[THEN]], label [[END:%.*]]
; CHECK-ENABLED: then:
; CHECK-ENABLED-NEXT: store i32 [[PHI]], ptr [[P:%.*]], align 4
; CHECK-ENABLED-NEXT: br i1 [[CMP3]], label [[LOOP]], label [[END]]
; CHECK-ENABLED: end:
; CHECK-ENABLED-NEXT: ret void
;
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 10, %add
br i1 %cmp2, label %then, label %end
then:
%phi = phi i32 [ %add, %if ], [ %x, %loop ]
store i32 %phi, ptr %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, ptr %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, ptr %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, ptr %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, ptr %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, ptr %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, ptr %p, align 4
if:
%add = add i32 %x, 5
%shr = ashr i32 %add, 1
store i32 %shr, ptr %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(ptr %ptr) {
; CHECK-LABEL: entry:
; CHECK: store i32 0, ptr %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, ptr %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(ptr %this, i32 %x) {
; CHECK-LABEL: entry:
; CHECK-DAG: %sub = add nsw i32 %x, -1
; 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:
call void %this(ptr %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, ptr %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, ptr %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, ptr %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(ptr %ptr1, ptr %ptr2) {
; CHECK-LABEL: entry:
; CHECK-DAG: %gep3 = getelementptr inbounds i32, ptr %ptr2, i32 2
; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %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, ptr %ptr2, i32 2
%val2 = load i32, ptr %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, ptr %ptr2, i32 2
%val3 = load i32, ptr %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(ptr %ptr, i32 %idx, i1 %cond1, i1 %cond2) {
; CHECK-LABEL: entry:
; CHECK: %gep = getelementptr inbounds i32, ptr %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, ptr %ptr, i32 %idx
%val = load i32, ptr %gep
br label %then
then:
%phi = phi i32 [ %val, %if ], [ 0, %loop ]
store i32 %phi, ptr %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, ptr %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, ptr %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(ptr %ptr1, ptr %ptr2, i32 %arg) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp2 = icmp ne i32 0, %arg
; CHECK-DAG: %gep = getelementptr i32, ptr %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, ptr %ptr1, i32 4
%val = load i32, ptr %gep, align 4
br label %then
if.else:
br label %then
then:
%phi2 = phi i32 [ %val, %if.if ], [ %phi1, %if.else ]
store i32 %phi2, ptr %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(ptr %ptr1, ptr %ptr2, i32 %arg) {
; CHECK-LABEL: entry:
; CHECK-DAG: %cmp1 = icmp ne i32 0, %arg
; CHECK-DAG: %gep = getelementptr i32, ptr %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, ptr %ptr1, i32 4
%val = load i32, ptr %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, ptr %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, ptr %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, ptr %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, ptr %g, i64 %phi
if.then2:
%d = getelementptr inbounds i32, ptr %g, i64 %phi
store i32 1, ptr %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, ptr %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, ptr %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, ptr %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, ptr %g, i64 %phi1
if.then2:
%d = getelementptr inbounds i32, ptr %g, i64 %phi1
store i32 1, ptr %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, ptr %g, i64 %phi2
if.then3:
%e = getelementptr inbounds i32, ptr %g, i64 %phi2
store i32 1, ptr %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(ptr %ptr) {
; CHECK-LABEL: entry
; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
; CHECK-DAG: %gep3 = getelementptr inbounds i32, ptr %ptr, i64 3
; CHECK-DAG: %gep1 = getelementptr inbounds i32, ptr %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, ptr %ptr, i64 1
store i32 0, ptr %gep1, align 4
br label %loop.backedge
else1:
%gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
store i32 0, ptr %gep2, align 4
br i1 undef, label %if2, label %loop.backedge
if2:
br i1 undef, label %if3, label %end
if3:
%gep3 = getelementptr inbounds i32, ptr %ptr, i64 3
store i32 0, ptr %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(ptr %ptr) {
; CHECK-LABEL: entry
; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
; CHECK-DAG: %gep3 = getelementptr inbounds i32, ptr %gep2, i64 3
; CHECK-DAG: %gep1 = getelementptr inbounds i32, ptr %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, ptr %ptr, i64 1
store i32 0, ptr %gep1, align 4
br label %loop.backedge
else1:
%gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
store i32 0, ptr %gep2, align 4
br i1 undef, label %if2, label %loop.backedge
if2:
br i1 undef, label %if3, label %end
if3:
%gep3 = getelementptr inbounds i32, ptr %gep2, i64 3
store i32 0, ptr %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(ptr %ptr) {
; CHECK-LABEL: entry
; CHECK-DAG: %gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
; CHECK-DAG: %gep1 = getelementptr inbounds i32, ptr %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 ptr [ %gep1, %[[IF1_LICM]] ], [ %gep2, %[[ELSE1_LICM]] ]
; CHECK-ENABLED: %gep3 = getelementptr inbounds i32, ptr %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, ptr %ptr, i64 1
store i32 0, ptr %gep1, align 4
br label %if2
else1:
%gep2 = getelementptr inbounds i32, ptr %ptr, i64 2
store i32 0, ptr %gep2, align 4
br i1 undef, label %if2, label %loop.backedge
if2:
%phi = phi ptr [ %gep1, %if1 ], [ %gep2, %else1 ]
br i1 undef, label %if3, label %end
if3:
%gep3 = getelementptr inbounds i32, ptr %phi, i64 3
store i32 0, ptr %gep3, align 4
br label %end
end:
br label %loop.backedge
loop.backedge:
br label %loop
}