; 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-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, 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 }