diff --git a/llvm/test/Transforms/LICM/call-hoisting.ll b/llvm/test/Transforms/LICM/call-hoisting.ll index 170f4ac535bec..b210678bc6274 100644 --- a/llvm/test/Transforms/LICM/call-hoisting.ll +++ b/llvm/test/Transforms/LICM/call-hoisting.ll @@ -23,6 +23,38 @@ exit: ret void } +declare i32 @spec(i32* %p) readonly argmemonly nounwind speculatable + +; FIXME: We should strip the nonnull callsite attribute on spec call's argument since it is +; may not be valid when hoisted to preheader. +define void @test_strip_attribute(i32* noalias %loc, i32* noalias %sink, i32* %q) { +; CHECK-LABEL: test_strip_attribute +; CHECK-LABEL: entry +; CHECK-NEXT: %ret = call i32 @load(i32* %loc) +; CHECK-NEXT: %nullchk = icmp eq i32* %q, null +; CHECK-NEXT: %ret2 = call i32 @spec(i32* nonnull %q) +entry: + br label %loop + +loop: + %iv = phi i32 [0, %entry], [%iv.next, %isnull ] + %ret = call i32 @load(i32* %loc) + %nullchk = icmp eq i32* %q, null + br i1 %nullchk, label %isnull, label %nonnullbb + +nonnullbb: + %ret2 = call i32 @spec(i32* nonnull %q) + br label %isnull + +isnull: + store volatile i32 %ret, i32* %sink + %iv.next = add i32 %iv, 1 + %cmp = icmp slt i32 %iv, 200 + br i1 %cmp, label %loop, label %exit + +exit: + ret void +} declare void @store(i32 %val, i32* %p) argmemonly writeonly nounwind diff --git a/llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest.ll b/llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest.ll index 7f0ea2f35a6d1..5f4226e0cbefd 100644 --- a/llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest.ll +++ b/llvm/test/Transforms/SimplifyCFG/fold-branch-to-common-dest.ll @@ -6,6 +6,7 @@ declare void @sideeffect1() declare void @sideeffect2() declare void @use8(i8) declare i1 @gen1() +declare i32 @speculate_call(i32 *) #0 ; Basic cases, blocks have nothing other than the comparison itself. @@ -117,6 +118,30 @@ final_right: ret void } +; FIXME: When we fold the dispatch block into pred, the call is moved to pred +; and the attribute nonnull is no longer valid on paramater. We should drop it. +define void @one_pred_with_spec_call(i8 %v0, i8 %v1, i32* %p) { +; CHECK-LABEL: one_pred_with_spec_call +; CHECK-LABEL: pred: +; CHECK: %c0 = icmp ne i32* %p, null +; CHECK: %x = call i32 @speculate_call(i32* nonnull %p) +pred: + %c0 = icmp ne i32* %p, null + br i1 %c0, label %dispatch, label %final_right + +dispatch: + %x = call i32 @speculate_call(i32* nonnull %p) + %c1 = icmp eq i8 %v1, 0 + br i1 %c1, label %final_left, label %final_right + +final_left: + ret void + +final_right: + call void @sideeffect0() + ret void +} + define void @two_preds_with_extra_op(i8 %v0, i8 %v1, i8 %v2, i8 %v3) { ; CHECK-LABEL: @two_preds_with_extra_op( ; CHECK-NEXT: entry: @@ -962,3 +987,5 @@ land.rhs: for.end: ret void } + +attributes #0 = { nounwind argmemonly speculatable } diff --git a/llvm/test/Transforms/SimplifyCFG/speculate-call.ll b/llvm/test/Transforms/SimplifyCFG/speculate-call.ll index 11a88fa80308f..fe8041718f586 100644 --- a/llvm/test/Transforms/SimplifyCFG/speculate-call.ll +++ b/llvm/test/Transforms/SimplifyCFG/speculate-call.ll @@ -19,5 +19,30 @@ end: define i32 @func() #0 { ret i32 1 } + +; FIXME: We should correctly drop the attribute since it may no longer be valid +; in the context the call is moved to. +define i32 @strip_attr(i32 * %p) { +; CHECK-LABEL: strip_attr +; CHECK-LABEL: entry: +; CHECK: %nullchk = icmp ne i32* %p, null +; CHECK: %val = call i32 @func_deref(i32* nonnull %p) +; CHECK: select +entry: + %nullchk = icmp ne i32* %p, null + br i1 %nullchk, label %if, label %end + +if: + %val = call i32 @func_deref(i32* nonnull %p) #1 + br label %end + +end: + %ret = phi i32 [%val, %if], [0, %entry] + ret i32 %ret +} + +declare i32 @func_deref(i32*) #1 + attributes #0 = { nounwind readnone speculatable } +attributes #1 = { nounwind argmemonly speculatable }