diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -1151,7 +1151,9 @@ [], "llvm.clear_cache">; // Intrinsic to detect whether its argument is a constant. -def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem, IntrWillReturn], "llvm.is.constant">; +def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], + [IntrNoMem, IntrWillReturn, IntrConvergent], + "llvm.is.constant">; // Intrinsic to mask out bits of a pointer. def int_ptrmask: Intrinsic<[llvm_anyptr_ty], [llvm_anyptr_ty, llvm_anyint_ty], diff --git a/llvm/test/Transforms/JumpThreading/is_constant.ll b/llvm/test/Transforms/JumpThreading/is_constant.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/JumpThreading/is_constant.ll @@ -0,0 +1,40 @@ +; RUN: opt -jump-threading -S -verify < %s | FileCheck %s + +; This is reduced from the Linux net/ipv4/tcp.c file built with ASAN. We +; don't want jump threading to split up a basic block which has a PHI node with +; at least one constant incoming value, whose value is used by an is.constant +; intrinsic with non-local uses. It could lead to later passes no DCE'ing +; invalid paths. + +; CHECK-LABEL: define void @test1( +; CHECK-LABEL: bb_cond: +; CHECK-NOT: %sext = phi i64 [ %var, %entry ] +; CHECK-NEXT: %sext = phi i64 [ 24, %bb_constant ], [ %var, %entry ] +; CHECK-NEXT: %cond2 = icmp +; CHECK-NEXT: call i1 @llvm.is.constant.i64( + +define void @test1(i32 %a, i64 %var) { +entry: + %cond1 = icmp ugt i32 %a, 24 + br i1 %cond1, label %bb_constant, label %bb_cond + +bb_constant: + br label %bb_cond + +bb_cond: + %sext = phi i64 [ 24, %bb_constant ], [ %var, %entry ] + %cond2 = icmp ugt i64 %sext, 24 + %is_constant = call i1 @llvm.is.constant.i64(i64 %sext) + br i1 %cond2, label %bb_then, label %bb_else + +bb_then: + unreachable + +bb_else: + unreachable +} + +; Function Attrs: nounwind readnone willreturn +declare i1 @llvm.is.constant.i64(i64) #0 + +attributes #0 = { convergent nounwind readnone willreturn }