| ; RUN: opt -passes=constraint-elimination -constraint-elimination-dump-reproducers -pass-remarks=constraint-elimination %s 2>&1 | FileCheck %s | 
 |  | 
 | target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" | 
 |  | 
 | declare void @use(i1) | 
 |  | 
 | declare void @llvm.assume(i1) | 
 |  | 
 | define i1 @test_no_known_facts(ptr %dst) { | 
 | ; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_no_known_facts' | 
 | ; CHECK-LABEL: define i1 @"{{.+}}test_no_known_factsrepro"(ptr %dst) | 
 | ; CHECK-NEXT:  entry: | 
 | ; CHECK-NEXT:    %dst.0 = getelementptr inbounds ptr, ptr %dst, i64 0 | 
 | ; CHECK-NEXT:    %upper = getelementptr inbounds ptr, ptr %dst, i64 2 | 
 | ; CHECK-NEXT:    %c = icmp ult ptr %dst.0, %upper | 
 | ; CHECK-NEXT:    ret i1 %c | 
 | ; CHECK-NEXT:  } | 
 | ; | 
 | entry: | 
 |   %dst.0 = getelementptr inbounds ptr, ptr %dst, i64 0 | 
 |   %upper = getelementptr inbounds ptr, ptr %dst, i64 2 | 
 |   %c = icmp ult i32* %dst.0, %upper | 
 |   ret i1 %c | 
 | } | 
 |  | 
 | define void @test_one_known_fact_true_branch(i8 %start, i8 %high) { | 
 | ; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_one_known_fact_true_branch' | 
 |  | 
 | ; CHECK-LABEL: define i1 @"{{.*}}test_one_known_fact_true_branchrepro"(i8 %high, i8 %start) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %add.ptr.i = add nuw i8 %start, 3 | 
 | ; CHECK-NEXT:   %0 = icmp ult i8 %add.ptr.i, %high | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %t.0 = icmp ult i8 %start, %high | 
 | ; CHECK-NEXT:   ret i1 %t.0 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %add.ptr.i = add nuw i8 %start, 3 | 
 |   %c.1 = icmp ult i8 %add.ptr.i, %high | 
 |   br i1 %c.1, label %if.then, label %if.end | 
 |  | 
 | if.then: | 
 |   %t.0 = icmp ult i8 %start, %high | 
 |   call void @use(i1 %t.0) | 
 |   ret void | 
 |  | 
 | if.end: | 
 |   ret void | 
 | } | 
 |  | 
 | define void @test_one_known_fact_false_branch(i8 %start, i8 %high) { | 
 | ; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_one_known_fact_false_branch' | 
 | ; | 
 | ; CHECK-LABEL:define i1 @"{{.*}}test_one_known_fact_false_branchrepro"(i8 %high, i8 %start) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %add.ptr.i = add nuw i8 %start, 3 | 
 | ; CHECK-NEXT:   %0 = icmp ult i8 %add.ptr.i, %high | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %t.0 = icmp ult i8 %start, %high | 
 | ; CHECK-NEXT:   ret i1 %t.0 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %add.ptr.i = add nuw i8 %start, 3 | 
 |   %c.1 = icmp uge i8 %add.ptr.i, %high | 
 |   br i1 %c.1, label %if.then, label %if.end | 
 |  | 
 | if.then: | 
 |   ret void | 
 |  | 
 | if.end: | 
 |   %t.0 = icmp ult i8 %start, %high | 
 |   call void @use(i1 %t.0) | 
 |   ret void | 
 | } | 
 |  | 
 | define void @test_multiple_known_facts_branches_1(i8 %a, i8 %b) { | 
 | ; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_multiple_known_facts_branches_1' | 
 |  | 
 | ; CHECK-LABEL: define i1 @"{{.*}}test_multiple_known_facts_branches_1repro"(i8 %a, i8 %b) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %0 = icmp ugt i8 %a, 10 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %1 = icmp ugt i8 %b, 10 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %1) | 
 | ; CHECK-NEXT:   %add = add nuw i8 %a, %b | 
 | ; CHECK-NEXT:   %t.0 = icmp ugt i8 %add, 20 | 
 | ; CHECK-NEXT:   ret i1 %t.0 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %c.1 = icmp ugt i8 %a, 10 | 
 |   br i1 %c.1, label %then.1, label %else.1 | 
 |  | 
 | then.1: | 
 |   %c.2 = icmp ugt i8 %b, 10 | 
 |   br i1 %c.2, label %then.2, label %else.1 | 
 |  | 
 | then.2: | 
 |   %add = add nuw i8 %a, %b | 
 |   %t.0 = icmp ugt i8 %add, 20 | 
 |   call void @use(i1 %t.0) | 
 |   ret void | 
 |  | 
 | else.1: | 
 |   ret void | 
 | } | 
 |  | 
 | define void @test_multiple_known_facts_branches_2(i8 %a, i8 %b) { | 
 | ; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_multiple_known_facts_branches_2' | 
 | ; | 
 | ; CHECK-LABEL: define i1 @"{{.*}}test_multiple_known_facts_branches_2repro"(i8 %a, i8 %b) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %0 = icmp ugt i8 %a, 10 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %1 = icmp ugt i8 %b, 10 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %1) | 
 | ; CHECK-NEXT:   %add = add nuw i8 %a, %b | 
 | ; CHECK-NEXT:   %t.0 = icmp ugt i8 %add, 20 | 
 | ; CHECK-NEXT:   ret i1 %t.0 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %c.1 = icmp ugt i8 %a, 10 | 
 |   br i1 %c.1, label %then.1, label %exit | 
 |  | 
 | then.1: | 
 |   %c.2 = icmp ule i8 %b, 10 | 
 |   br i1 %c.2, label %exit, label %else.2 | 
 |  | 
 | else.2: | 
 |   %add = add nuw i8 %a, %b | 
 |   %t.0 = icmp ugt i8 %add, 20 | 
 |   call void @use(i1 %t.0) | 
 |   ret void | 
 |  | 
 | exit: | 
 |   ret void | 
 | } | 
 |  | 
 | define void @test_assumes(i8 %a, i8 %b) { | 
 | ; CHECK-LABEL: define i1 @"{{.*}}test_assumesrepro.2"(i8 %a, i8 %b) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %0 = icmp ugt i8 %a, 10 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %1 = icmp ugt i8 %b, 10 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %1) | 
 | ; CHECK-NEXT:   %add = add nuw i8 %a, %b | 
 | ; CHECK-NEXT:   %t.0 = icmp ult i8 %add, 20 | 
 | ; CHECK-NEXT:   ret i1 %t.0 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %c.1 = icmp ugt i8 %a, 10 | 
 |   call void @llvm.assume(i1 %c.1) | 
 |   %c.2 = icmp ugt i8 %b, 10 | 
 |   call void @llvm.assume(i1 %c.2) | 
 |   %add = add nuw i8 %a, %b | 
 |   %t.0 = icmp ult i8 %add, 20 | 
 |   call void @use(i1 %t.0) | 
 |   ret void | 
 | } | 
 |  | 
 | declare void @noundef(ptr noundef) | 
 |  | 
 | ; Currently this fails decomposition. No reproducer should be generated. | 
 | define i1 @test_inbounds_precondition(ptr %src, i32 %n, i32 %idx) { | 
 | ; CHECK-NOT: test_inbounds_precondition | 
 | entry: | 
 |   %upper = getelementptr inbounds i32, ptr %src, i64 5 | 
 |   %src.idx.4 = getelementptr i32, ptr %src, i64 4 | 
 |   %cmp.upper.4 = icmp ule ptr %src.idx.4, %upper | 
 |   br i1 %cmp.upper.4, label %then, label %else | 
 |  | 
 | then: | 
 |   ret i1 true | 
 |  | 
 | else: | 
 |   ret i1 false | 
 | } | 
 |  | 
 | define i32 @test_branch(i32 %a) { | 
 | ; CHECK-LABEL: define i1 @"{{.+}}test_branchrepro"(i32 %a) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %0 = icmp ult i32 %a, 4 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %c.2 = icmp ugt i32 0, 0 | 
 | ; CHECK-NEXT:   ret i1 %c.2 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %c.1 = icmp ult i32 %a, 4 | 
 |   br i1 %c.1, label %then, label %exit | 
 |  | 
 | then: | 
 |   %c.2 = icmp ugt i32 0, 0 | 
 |   call void @use(i1 %c.2) | 
 |   br label %exit | 
 |  | 
 | exit: | 
 |   ret i32 0 | 
 | } | 
 |  | 
 | define i32 @test_invoke(i32 %a) personality ptr null { | 
 | ; CHECK-LABEL: define i1 @"{{.+}}test_invokerepro"(i32 %l, i32 %a) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:  %0 = icmp slt i32 %a, %l | 
 | ; CHECK-NEXT:  call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:  %c.2 = icmp eq i32 0, 0 | 
 | ; CHECK-NEXT:  ret i1 %c.2 | 
 | ; CHECK-NEXT:} | 
 | ; | 
 | entry: | 
 |   %call = invoke ptr null(i64 0) | 
 |           to label %cont unwind label %lpad | 
 |  | 
 | cont: | 
 |   %l = load i32, ptr %call, align 4 | 
 |   %c.1 = icmp slt i32 %a, %l | 
 |   br i1 %c.1, label %then, label %exit | 
 |  | 
 | lpad: | 
 |   %lp = landingpad { ptr, i32 } | 
 |           catch ptr null | 
 |           catch ptr null | 
 |   ret i32 0 | 
 |  | 
 | then: | 
 |   %c.2 = icmp eq i32 0, 0 | 
 |   call void @use(i1 %c.2) | 
 |   br label %exit | 
 |  | 
 | exit: | 
 |   ret i32 0 | 
 | } | 
 |  | 
 | define <2 x i1> @vector_cmp(<2 x ptr> %vec) { | 
 | ; CHECK-LABEL: define <2 x i1> @"{{.+}}vector_cmprepro"(<2 x ptr> %vec) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %gep.1 = getelementptr inbounds i32, <2 x ptr> %vec, i64 1 | 
 | ; CHECK-NEXT:   %t.1 = icmp ult <2 x ptr> %vec, %gep.1 | 
 | ; CHECK-NEXT:   ret <2 x i1> %t.1 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 |   %gep.1 = getelementptr inbounds i32, <2 x ptr> %vec, i64 1 | 
 |   %t.1 = icmp ult <2 x ptr> %vec, %gep.1 | 
 |   ret <2 x i1> %t.1 | 
 | } | 
 |  | 
 | define i1 @shared_operand() { | 
 | ; CHECK-LABEL: define i1 @"{{.+}}shared_operandrepro"() { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %sub = sub i8 0, 0 | 
 | ; CHECK-NEXT:   %sub.2 = sub nuw i8 %sub, 0 | 
 | ; CHECK-NEXT:   %c.5 = icmp ult i8 %sub.2, %sub | 
 | ; CHECK-NEXT:   ret i1 %c.5 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %sub = sub i8 0, 0 | 
 |   %sub.2 = sub nuw i8 %sub, 0 | 
 |   %c.5 = icmp ult i8 %sub.2, %sub | 
 |   ret i1 %c.5 | 
 | } | 
 |  | 
 | @glob = external global i32 | 
 |  | 
 | define i1 @load_global() { | 
 | ; CHECK-LABEL: define i1 @"{{.*}}load_globalrepro"(i32 %l) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:  %c = icmp ugt i32 %l, %l | 
 | ; CHECK-NEXT:  ret i1 %c | 
 | ; CHECK-NEXT:} | 
 | ; | 
 | entry: | 
 |   %l = load i32, ptr @glob, align 8 | 
 |   %c = icmp ugt i32 %l, %l | 
 |   ret i1 %c | 
 | } | 
 |  | 
 | define i1 @test_ptr_null_constant(ptr %a) { | 
 | ; CHECK-LABEL: define i1 @"{{.+}}test_ptr_null_constantrepro"(ptr %a) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %0 = icmp eq ptr %a, null | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %c.2 = icmp eq ptr %a, null | 
 | ; CHECK-NEXT:   ret i1 %c.2 | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %c.1 = icmp eq ptr %a, null | 
 |   br i1 %c.1, label %then, label %else | 
 |  | 
 | then: | 
 |   %c.2 = icmp eq ptr %a, null | 
 |   ret i1 %c.2 | 
 |  | 
 | else: | 
 |   ret i1 false | 
 | } | 
 |  | 
 | define i1 @test_both_signed_and_unsigned_conds_needed_in_reproducer(ptr %src, ptr %lower, ptr %upper, i16 %N) { | 
 | ; CHECK-LABEL: define i1 @"{{.+}}test_both_signed_and_unsigned_conds_needed_in_reproducerrepro"(i16 %N, ptr %src) { | 
 | ; CHECK-NEXT: entry: | 
 | ; CHECK-NEXT:   %0 = icmp sge i16 %N, 0 | 
 | ; CHECK-NEXT:   call void @llvm.assume(i1 %0) | 
 | ; CHECK-NEXT:   %src.end = getelementptr inbounds i8, ptr %src, i16 %N | 
 | ; CHECK-NEXT:   %cmp.src.start = icmp ule ptr %src, %src.end | 
 | ; CHECK-NEXT:   ret i1 %cmp.src.start | 
 | ; CHECK-NEXT: } | 
 | ; | 
 | entry: | 
 |   %N.pos = icmp sge i16 %N, 0 | 
 |   br i1 %N.pos, label %then, label %else | 
 |  | 
 | then: | 
 |   %src.end = getelementptr inbounds i8, ptr %src, i16 %N | 
 |   %cmp.src.start = icmp ule ptr %src, %src.end | 
 |   ret i1 %cmp.src.start | 
 |  | 
 | else: | 
 |   ret i1 false | 
 | } |