1; RUN: opt -passes=constraint-elimination -constraint-elimination-dump-reproducers -pass-remarks=constraint-elimination %s 2>&1 | FileCheck %s 2 3target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 4 5declare void @use(i1) 6 7declare void @llvm.assume(i1) 8 9define i1 @test_no_known_facts(ptr %dst) { 10; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_no_known_facts' 11; CHECK-LABEL: define i1 @"{{.+}}test_no_known_factsrepro"(ptr %dst) 12; CHECK-NEXT: entry: 13; CHECK-NEXT: %dst.0 = getelementptr inbounds ptr, ptr %dst, i64 0 14; CHECK-NEXT: %upper = getelementptr inbounds ptr, ptr %dst, i64 2 15; CHECK-NEXT: %c = icmp ult ptr %dst.0, %upper 16; CHECK-NEXT: ret i1 %c 17; CHECK-NEXT: } 18; 19entry: 20 %dst.0 = getelementptr inbounds ptr, ptr %dst, i64 0 21 %upper = getelementptr inbounds ptr, ptr %dst, i64 2 22 %c = icmp ult ptr %dst.0, %upper 23 ret i1 %c 24} 25 26define void @test_one_known_fact_true_branch(i8 %start, i8 %high) { 27; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_one_known_fact_true_branch' 28 29; CHECK-LABEL: define i1 @"{{.*}}test_one_known_fact_true_branchrepro"(i8 %high, i8 %start) { 30; CHECK-NEXT: entry: 31; CHECK-NEXT: %add.ptr.i = add nuw i8 %start, 3 32; CHECK-NEXT: %0 = icmp ult i8 %add.ptr.i, %high 33; CHECK-NEXT: call void @llvm.assume(i1 %0) 34; CHECK-NEXT: %t.0 = icmp ult i8 %start, %high 35; CHECK-NEXT: ret i1 %t.0 36; CHECK-NEXT: } 37; 38entry: 39 %add.ptr.i = add nuw i8 %start, 3 40 %c.1 = icmp ult i8 %add.ptr.i, %high 41 br i1 %c.1, label %if.then, label %if.end 42 43if.then: 44 %t.0 = icmp ult i8 %start, %high 45 call void @use(i1 %t.0) 46 ret void 47 48if.end: 49 ret void 50} 51 52define void @test_one_known_fact_false_branch(i8 %start, i8 %high) { 53; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_one_known_fact_false_branch' 54; 55; CHECK-LABEL:define i1 @"{{.*}}test_one_known_fact_false_branchrepro"(i8 %high, i8 %start) { 56; CHECK-NEXT: entry: 57; CHECK-NEXT: %add.ptr.i = add nuw i8 %start, 3 58; CHECK-NEXT: %0 = icmp ult i8 %add.ptr.i, %high 59; CHECK-NEXT: call void @llvm.assume(i1 %0) 60; CHECK-NEXT: %t.0 = icmp ult i8 %start, %high 61; CHECK-NEXT: ret i1 %t.0 62; CHECK-NEXT: } 63; 64entry: 65 %add.ptr.i = add nuw i8 %start, 3 66 %c.1 = icmp uge i8 %add.ptr.i, %high 67 br i1 %c.1, label %if.then, label %if.end 68 69if.then: 70 ret void 71 72if.end: 73 %t.0 = icmp ult i8 %start, %high 74 call void @use(i1 %t.0) 75 ret void 76} 77 78define void @test_multiple_known_facts_branches_1(i8 %a, i8 %b) { 79; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_multiple_known_facts_branches_1' 80 81; CHECK-LABEL: define i1 @"{{.*}}test_multiple_known_facts_branches_1repro"(i8 %a, i8 %b) { 82; CHECK-NEXT: entry: 83; CHECK-NEXT: %0 = icmp ugt i8 %a, 10 84; CHECK-NEXT: call void @llvm.assume(i1 %0) 85; CHECK-NEXT: %1 = icmp ugt i8 %b, 10 86; CHECK-NEXT: call void @llvm.assume(i1 %1) 87; CHECK-NEXT: %add = add nuw i8 %a, %b 88; CHECK-NEXT: %t.0 = icmp ugt i8 %add, 20 89; CHECK-NEXT: ret i1 %t.0 90; CHECK-NEXT: } 91; 92entry: 93 %c.1 = icmp ugt i8 %a, 10 94 br i1 %c.1, label %then.1, label %else.1 95 96then.1: 97 %c.2 = icmp ugt i8 %b, 10 98 br i1 %c.2, label %then.2, label %else.1 99 100then.2: 101 %add = add nuw i8 %a, %b 102 %t.0 = icmp ugt i8 %add, 20 103 call void @use(i1 %t.0) 104 ret void 105 106else.1: 107 ret void 108} 109 110define void @test_multiple_known_facts_branches_2(i8 %a, i8 %b) { 111; CHECK: remark: <unknown>:0:0: module; ModuleID = 'test_multiple_known_facts_branches_2' 112; 113; CHECK-LABEL: define i1 @"{{.*}}test_multiple_known_facts_branches_2repro"(i8 %a, i8 %b) { 114; CHECK-NEXT: entry: 115; CHECK-NEXT: %0 = icmp ugt i8 %a, 10 116; CHECK-NEXT: call void @llvm.assume(i1 %0) 117; CHECK-NEXT: %1 = icmp ugt i8 %b, 10 118; CHECK-NEXT: call void @llvm.assume(i1 %1) 119; CHECK-NEXT: %add = add nuw i8 %a, %b 120; CHECK-NEXT: %t.0 = icmp ugt i8 %add, 20 121; CHECK-NEXT: ret i1 %t.0 122; CHECK-NEXT: } 123; 124entry: 125 %c.1 = icmp ugt i8 %a, 10 126 br i1 %c.1, label %then.1, label %exit 127 128then.1: 129 %c.2 = icmp ule i8 %b, 10 130 br i1 %c.2, label %exit, label %else.2 131 132else.2: 133 %add = add nuw i8 %a, %b 134 %t.0 = icmp ugt i8 %add, 20 135 call void @use(i1 %t.0) 136 ret void 137 138exit: 139 ret void 140} 141 142define void @test_assumes(i8 %a, i8 %b) { 143; CHECK-LABEL: define i1 @"{{.*}}test_assumesrepro.2"(i8 %a, i8 %b) { 144; CHECK-NEXT: entry: 145; CHECK-NEXT: %0 = icmp ugt i8 %a, 10 146; CHECK-NEXT: call void @llvm.assume(i1 %0) 147; CHECK-NEXT: %1 = icmp ugt i8 %b, 10 148; CHECK-NEXT: call void @llvm.assume(i1 %1) 149; CHECK-NEXT: %add = add nuw i8 %a, %b 150; CHECK-NEXT: %t.0 = icmp ult i8 %add, 20 151; CHECK-NEXT: ret i1 %t.0 152; CHECK-NEXT: } 153; 154entry: 155 %c.1 = icmp ugt i8 %a, 10 156 call void @llvm.assume(i1 %c.1) 157 %c.2 = icmp ugt i8 %b, 10 158 call void @llvm.assume(i1 %c.2) 159 %add = add nuw i8 %a, %b 160 %t.0 = icmp ult i8 %add, 20 161 call void @use(i1 %t.0) 162 ret void 163} 164 165declare void @noundef(ptr noundef) 166 167; Currently this fails decomposition. No reproducer should be generated. 168define i1 @test_inbounds_precondition(ptr %src, i32 %n, i32 %idx) { 169; CHECK-NOT: test_inbounds_precondition 170entry: 171 %upper = getelementptr inbounds i32, ptr %src, i64 5 172 %src.idx.4 = getelementptr i32, ptr %src, i64 4 173 %cmp.upper.4 = icmp ule ptr %src.idx.4, %upper 174 br i1 %cmp.upper.4, label %then, label %else 175 176then: 177 ret i1 true 178 179else: 180 ret i1 false 181} 182 183define i32 @test_branch(i32 %a) { 184; CHECK-LABEL: define i1 @"{{.+}}test_branchrepro"(i32 %a) { 185; CHECK-NEXT: entry: 186; CHECK-NEXT: %0 = icmp ult i32 %a, 4 187; CHECK-NEXT: call void @llvm.assume(i1 %0) 188; CHECK-NEXT: %c.2 = icmp ugt i32 0, 0 189; CHECK-NEXT: ret i1 %c.2 190; CHECK-NEXT: } 191; 192entry: 193 %c.1 = icmp ult i32 %a, 4 194 br i1 %c.1, label %then, label %exit 195 196then: 197 %c.2 = icmp ugt i32 0, 0 198 call void @use(i1 %c.2) 199 br label %exit 200 201exit: 202 ret i32 0 203} 204 205define i32 @test_invoke(i32 %a) personality ptr null { 206; CHECK-LABEL: define i1 @"{{.+}}test_invokerepro"(i32 %l, i32 %a) { 207; CHECK-NEXT: entry: 208; CHECK-NEXT: %0 = icmp slt i32 %a, %l 209; CHECK-NEXT: call void @llvm.assume(i1 %0) 210; CHECK-NEXT: %c.2 = icmp eq i32 0, 0 211; CHECK-NEXT: ret i1 %c.2 212; CHECK-NEXT:} 213; 214entry: 215 %call = invoke ptr null(i64 0) 216 to label %cont unwind label %lpad 217 218cont: 219 %l = load i32, ptr %call, align 4 220 %c.1 = icmp slt i32 %a, %l 221 br i1 %c.1, label %then, label %exit 222 223lpad: 224 %lp = landingpad { ptr, i32 } 225 catch ptr null 226 catch ptr null 227 ret i32 0 228 229then: 230 %c.2 = icmp eq i32 0, 0 231 call void @use(i1 %c.2) 232 br label %exit 233 234exit: 235 ret i32 0 236} 237 238define <2 x i1> @vector_cmp(<2 x ptr> %vec) { 239; CHECK-LABEL: define <2 x i1> @"{{.+}}vector_cmprepro"(<2 x ptr> %vec) { 240; CHECK-NEXT: entry: 241; CHECK-NEXT: %gep.1 = getelementptr inbounds i32, <2 x ptr> %vec, i64 1 242; CHECK-NEXT: %t.1 = icmp ult <2 x ptr> %vec, %gep.1 243; CHECK-NEXT: ret <2 x i1> %t.1 244; CHECK-NEXT: } 245; 246 %gep.1 = getelementptr inbounds i32, <2 x ptr> %vec, i64 1 247 %t.1 = icmp ult <2 x ptr> %vec, %gep.1 248 ret <2 x i1> %t.1 249} 250 251define i1 @shared_operand() { 252; CHECK-LABEL: define i1 @"{{.+}}shared_operandrepro"() { 253; CHECK-NEXT: entry: 254; CHECK-NEXT: %sub = sub i8 0, 0 255; CHECK-NEXT: %sub.2 = sub nuw i8 %sub, 0 256; CHECK-NEXT: %c.5 = icmp ult i8 %sub.2, %sub 257; CHECK-NEXT: ret i1 %c.5 258; CHECK-NEXT: } 259; 260entry: 261 %sub = sub i8 0, 0 262 %sub.2 = sub nuw i8 %sub, 0 263 %c.5 = icmp ult i8 %sub.2, %sub 264 ret i1 %c.5 265} 266 267@glob = external global i32 268 269define i1 @load_global() { 270; CHECK-LABEL: define i1 @"{{.*}}load_globalrepro"(i32 %l) { 271; CHECK-NEXT: entry: 272; CHECK-NEXT: %c = icmp ugt i32 %l, %l 273; CHECK-NEXT: ret i1 %c 274; CHECK-NEXT:} 275; 276entry: 277 %l = load i32, ptr @glob, align 8 278 %c = icmp ugt i32 %l, %l 279 ret i1 %c 280} 281 282define i1 @test_ptr_null_constant(ptr %a) { 283; CHECK-LABEL: define i1 @"{{.+}}test_ptr_null_constantrepro"(ptr %a) { 284; CHECK-NEXT: entry: 285; CHECK-NEXT: %0 = icmp eq ptr %a, null 286; CHECK-NEXT: call void @llvm.assume(i1 %0) 287; CHECK-NEXT: %c.2 = icmp eq ptr %a, null 288; CHECK-NEXT: ret i1 %c.2 289; CHECK-NEXT: } 290; 291entry: 292 %c.1 = icmp eq ptr %a, null 293 br i1 %c.1, label %then, label %else 294 295then: 296 %c.2 = icmp eq ptr %a, null 297 ret i1 %c.2 298 299else: 300 ret i1 false 301} 302 303define i1 @test_both_signed_and_unsigned_conds_needed_in_reproducer(ptr %src, ptr %lower, ptr %upper, i16 %N) { 304; CHECK-LABEL: define i1 @"{{.+}}test_both_signed_and_unsigned_conds_needed_in_reproducerrepro"(i16 %N, ptr %src) { 305; CHECK-NEXT: entry: 306; CHECK-NEXT: %0 = icmp sge i16 %N, 0 307; CHECK-NEXT: call void @llvm.assume(i1 %0) 308; CHECK-NEXT: %src.end = getelementptr inbounds i8, ptr %src, i16 %N 309; CHECK-NEXT: %cmp.src.start = icmp ule ptr %src, %src.end 310; CHECK-NEXT: ret i1 %cmp.src.start 311; CHECK-NEXT: } 312; 313entry: 314 %N.pos = icmp sge i16 %N, 0 315 br i1 %N.pos, label %then, label %else 316 317then: 318 %src.end = getelementptr inbounds i8, ptr %src, i16 %N 319 %cmp.src.start = icmp ule ptr %src, %src.end 320 ret i1 %cmp.src.start 321 322else: 323 ret i1 false 324} 325