diff --git a/llvm/test/Transforms/LICM/hoist-mustexec.ll b/llvm/test/Transforms/LICM/hoist-mustexec.ll index cd7c28c5e617..1248542584a8 100644 --- a/llvm/test/Transforms/LICM/hoist-mustexec.ll +++ b/llvm/test/Transforms/LICM/hoist-mustexec.ll @@ -280,3 +280,152 @@ fail: call void @f() ret i32 -1 } + +declare void @may_throw() inaccessiblememonly + +; Test that we can sink a mustexecute load from loop header even in presence of +; throwing instructions after it. +define void @test_hoist_from_header_01(i32* %p, i32 %n) { + +; CHECK-LABEL: @test_hoist_from_header_01( +; CHECK: entry: +; CHECK-NEXT: %load = load i32, i32* %p +; CHECK-NOT: load i32 + +entry: + br label %loop + +loop: + %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] + %dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ] + %load = load i32, i32* %p + call void @may_throw() + %cond = icmp slt i32 %iv, %n + br i1 %cond, label %if.true, label %if.false + +if.true: + %a = add i32 %iv, %iv + br label %backedge + +if.false: + %b = mul i32 %iv, %iv + br label %backedge + +backedge: + %merge = phi i32 [ %a, %if.true ], [ %b, %if.false ] + %iv.next = add i32 %iv, %merge + %loop.cond = icmp ult i32 %iv.next, %load + br i1 %loop.cond, label %loop, label %exit + +exit: + ret void +} + +define void @test_hoist_from_header_02(i32* %p, i32 %n) { + +; CHECK-LABEL: @test_hoist_from_header_02( +; CHECK: entry: +; CHECK-NEXT: %load = load i32, i32* %p +; CHECK-NOT: load i32 + +entry: + br label %loop + +loop: + %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] + %dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ] + %load = load i32, i32* %p + %cond = icmp slt i32 %iv, %n + br i1 %cond, label %if.true, label %if.false + +if.true: + call void @may_throw() + %a = add i32 %iv, %iv + br label %backedge + +if.false: + %b = mul i32 %iv, %iv + br label %backedge + +backedge: + %merge = phi i32 [ %a, %if.true ], [ %b, %if.false ] + %iv.next = add i32 %iv, %merge + %loop.cond = icmp ult i32 %iv.next, %load + br i1 %loop.cond, label %loop, label %exit + +exit: + ret void +} + +define void @test_hoist_from_header_03(i32* %p, i32 %n) { + +; CHECK-LABEL: @test_hoist_from_header_03( +; CHECK: entry: +; CHECK-NEXT: %load = load i32, i32* %p +; CHECK-NOT: load i32 + +entry: + br label %loop + +loop: + %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] + %dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ] + %load = load i32, i32* %p + %cond = icmp slt i32 %iv, %n + br i1 %cond, label %if.true, label %if.false + +if.true: + %a = add i32 %iv, %iv + br label %backedge + +if.false: + %b = mul i32 %iv, %iv + br label %backedge + +backedge: + %merge = phi i32 [ %a, %if.true ], [ %b, %if.false ] + call void @may_throw() + %iv.next = add i32 %iv, %merge + %loop.cond = icmp ult i32 %iv.next, %load + br i1 %loop.cond, label %loop, label %exit + +exit: + ret void +} + +; Check that a throwing instruction prohibits hoisting across it. +define void @test_hoist_from_header_04(i32* %p, i32 %n) { + +; CHECK-LABEL: @test_hoist_from_header_04( +; CHECK: entry: +; CHECK: loop: +; CHECK: %load = load i32, i32* %p + +entry: + br label %loop + +loop: + %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] + %dummy = phi i32 [ 0, %entry ], [ %merge, %backedge ] + call void @may_throw() + %load = load i32, i32* %p + %cond = icmp slt i32 %iv, %n + br i1 %cond, label %if.true, label %if.false + +if.true: + %a = add i32 %iv, %iv + br label %backedge + +if.false: + %b = mul i32 %iv, %iv + br label %backedge + +backedge: + %merge = phi i32 [ %a, %if.true ], [ %b, %if.false ] + %iv.next = add i32 %iv, %merge + %loop.cond = icmp ult i32 %iv.next, %load + br i1 %loop.cond, label %loop, label %exit + +exit: + ret void +}