40 changes: 40 additions & 0 deletions llvm/test/Transforms/LoopFusion/no_sink_hoist_unknown_function.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
; RUN: opt -S -loop-simplify -loop-fusion -debug-only=loop-fusion < %s 2>&1 | FileCheck %s
; REQUIRES: asserts
; CHECK: may have side-effects
; CHECK: Could not hoist/sink all instructions

declare void @unknown_func()

define void @sink_preheader(i32 %N) {
; CHECK:pre1:
; CHECK-NEXT: br label %body1
pre1:
br label %body1

; CHECK:body1:
; CHECK-NOT: %stay =
body1: ; preds = %pre1, %body1
%i = phi i32 [%i_next, %body1], [0, %pre1]
%i_next = add i32 1, %i
%cond = icmp ne i32 %i, %N
br i1 %cond, label %body1, label %pre2

; CHECK:pre2:
; CHECK-NEXT: call void @unknown_func()
pre2:
call void @unknown_func()
br label %body2

; CHECK: body2:
; CHECK-NOT: %stay =
body2: ; preds = %pre2, %body2
%i2 = phi i32 [%i_next2, %body2], [0, %pre2]
%i_next2 = add i32 1, %i2
%cond2 = icmp ne i32 %i2, %N
br i1 %cond2, label %body2, label %exit

; CHECK: exit:
; CHECK-NOT: %stay =
exit:
ret void
}
9 changes: 5 additions & 4 deletions llvm/test/Transforms/LoopFusion/simple.ll
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,9 @@ for.second.exit:
}

; Test that `%add` cannot be moved to basic block entry, as it uses %i, which
; defined after basic block entry. And the two loops for.first and for.second
; are not fused.
; defined after basic block entry. It also cannot be moved to for.second.exit
; since it is used in for.second. Check also that the two loops for.first and
; for.second are not fused.

define i64 @unsafe_preheader(i32* %A, i64 %x) {
; CHECK-LABEL: @unsafe_preheader(
Expand All @@ -505,7 +506,7 @@ define i64 @unsafe_preheader(i32* %A, i64 %x) {
; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[X:%.*]], [[I]]
; CHECK-NEXT: br label [[FOR_SECOND:%.*]]
; CHECK: for.second:
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, [[FOR_FIRST_EXIT]] ], [ [[INC_J:%.*]], [[FOR_SECOND]] ]
; CHECK-NEXT: [[J:%.*]] = phi i64 [ [[ADD]], [[FOR_FIRST_EXIT]] ], [ [[INC_J:%.*]], [[FOR_SECOND]] ]
; CHECK-NEXT: [[AJ:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[J]]
; CHECK-NEXT: store i32 2, i32* [[AJ]], align 4
; CHECK-NEXT: [[INC_J]] = add nsw i64 [[J]], 1
Expand All @@ -530,7 +531,7 @@ for.first.exit:
br label %for.second

for.second:
%j = phi i64 [ 0, %for.first.exit ], [ %inc.j, %for.second ]
%j = phi i64 [ %add, %for.first.exit ], [ %inc.j, %for.second ]
%Aj = getelementptr inbounds i32, i32* %A, i64 %j
store i32 2, i32* %Aj, align 4
%inc.j = add nsw i64 %j, 1
Expand Down
46 changes: 46 additions & 0 deletions llvm/test/Transforms/LoopFusion/sink_preheader.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
; RUN: opt -S -loop-fusion < %s | FileCheck %s

define void @sink_preheader(i32 %N) {
; CHECK-LABEL: @sink_preheader(
; CHECK-NEXT: pre1:
; CHECK-NEXT: br label [[BODY1:%.*]]
; CHECK: body1:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[BODY1]] ], [ 0, [[PRE1:%.*]] ]
; CHECK-NEXT: [[I2:%.*]] = phi i32 [ [[I_NEXT2:%.*]], [[BODY1]] ], [ 0, [[PRE1]] ]
; CHECK-NEXT: [[I_NEXT]] = add i32 1, [[I]]
; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[I]], [[N:%.*]]
; CHECK-NEXT: [[BARRIER:%.*]] = add i32 1, [[N]]
; CHECK-NEXT: [[I_NEXT2]] = add i32 1, [[I2]]
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i32 [[I2]], [[N]]
; CHECK-NEXT: br i1 [[COND2]], label [[BODY1]], label [[EXIT:%.*]]
; CHECK: exit:
; CHECK-NEXT: [[SINKME:%.*]] = add i32 1, [[BARRIER]]
; CHECK-NEXT: [[SINKME2:%.*]] = add i32 1, [[BARRIER]]
; CHECK-NEXT: [[SINKME3:%.*]] = add i32 1, [[SINKME2]]
; CHECK-NEXT: ret void
;
pre1:
br label %body1

body1: ; preds = %pre1, %body1
%i = phi i32 [%i_next, %body1], [0, %pre1]
%i_next = add i32 1, %i
%cond = icmp ne i32 %i, %N
%barrier = add i32 1, %N
br i1 %cond, label %body1, label %pre2

pre2:
%sinkme = add i32 1, %barrier
%sinkme2 = add i32 1, %barrier
%sinkme3 = add i32 1, %sinkme2
br label %body2

body2: ; preds = %pre2, %body2
%i2 = phi i32 [%i_next2, %body2], [0, %pre2]
%i_next2 = add i32 1, %i2
%cond2 = icmp ne i32 %i2, %N
br i1 %cond2, label %body2, label %exit

exit:
ret void
}