1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals 2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC 4; 5; Test for multiple potential values 6; 7; potential-test 1 8; bool iszero(int c) { return c == 0; } 9; bool potential_test1(bool c) { return iszero(c ? 1 : -1); } 10 11define internal i1 @iszero1(i32 %c) { 12; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 13; CGSCC-LABEL: define {{[^@]+}}@iszero1 14; CGSCC-SAME: () #[[ATTR0:[0-9]+]] { 15; CGSCC-NEXT: ret i1 false 16; 17 %cmp = icmp eq i32 %c, 0 18 ret i1 %cmp 19} 20 21define i1 @potential_test1(i1 %c) { 22; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 23; TUNIT-LABEL: define {{[^@]+}}@potential_test1 24; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] { 25; TUNIT-NEXT: ret i1 false 26; 27; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 28; CGSCC-LABEL: define {{[^@]+}}@potential_test1 29; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR1:[0-9]+]] { 30; CGSCC-NEXT: [[RET:%.*]] = call noundef i1 @iszero1() #[[ATTR2:[0-9]+]] 31; CGSCC-NEXT: ret i1 [[RET]] 32; 33 %arg = select i1 %c, i32 -1, i32 1 34 %ret = call i1 @iszero1(i32 %arg) 35 ret i1 %ret 36} 37 38 39; potential-test 2 40; 41; potential values of argument of iszero are {1,-1} 42; potential value of returned value of iszero is 0 43; 44; int call_with_two_values(int x) { return iszero(x) + iszero(-x); } 45; int potential_test2(int x) { return call_with_two_values(1) + call_with_two_values(-1); } 46 47define internal i32 @iszero2(i32 %c) { 48; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 49; CGSCC-LABEL: define {{[^@]+}}@iszero2 50; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 51; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0 52; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[CMP]] to i32 53; CGSCC-NEXT: ret i32 [[RET]] 54; 55 %cmp = icmp eq i32 %c, 0 56 %ret = zext i1 %cmp to i32 57 ret i32 %ret 58} 59 60define internal i32 @call_with_two_values(i32 %c) { 61; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 62; CGSCC-LABEL: define {{[^@]+}}@call_with_two_values 63; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] { 64; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @iszero2(i32 noundef [[C]]) #[[ATTR2]] 65; CGSCC-NEXT: [[MINUSC:%.*]] = sub i32 0, [[C]] 66; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @iszero2(i32 noundef [[MINUSC]]) #[[ATTR2]] 67; CGSCC-NEXT: [[RET:%.*]] = add i32 [[CSRET1]], [[CSRET2]] 68; CGSCC-NEXT: ret i32 [[RET]] 69; 70 %csret1 = call i32 @iszero2(i32 %c) 71 %minusc = sub i32 0, %c 72 %csret2 = call i32 @iszero2(i32 %minusc) 73 %ret = add i32 %csret1, %csret2 74 ret i32 %ret 75} 76 77define i32 @potential_test2(i1 %c) { 78; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 79; TUNIT-LABEL: define {{[^@]+}}@potential_test2 80; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] { 81; TUNIT-NEXT: ret i32 0 82; 83; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 84; CGSCC-LABEL: define {{[^@]+}}@potential_test2 85; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR1]] { 86; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @call_with_two_values(i32 noundef 1) #[[ATTR2]] 87; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @call_with_two_values(i32 noundef -1) #[[ATTR2]] 88; CGSCC-NEXT: [[RET:%.*]] = add i32 [[CSRET1]], [[CSRET2]] 89; CGSCC-NEXT: ret i32 [[RET]] 90; 91 %csret1 = call i32 @call_with_two_values(i32 1) 92 %csret2 = call i32 @call_with_two_values(i32 -1) 93 %ret = add i32 %csret1, %csret2 94 ret i32 %ret 95} 96 97 98; potential-test 3 99; 100; potential values of returned value of f are {0,1} 101; potential values of argument of g are {0,1} 102; potential value of returned value of g is 1 103; then returned value of g can be simplified 104; 105; int zero_or_one(int c) { return c < 2; } 106; int potential_test3() { return zero_or_one(iszero(0))+zero_or_one(iszero(1)); } 107 108define internal i32 @iszero3(i32 %c) { 109; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 110; CGSCC-LABEL: define {{[^@]+}}@iszero3 111; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] { 112; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0 113; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[CMP]] to i32 114; CGSCC-NEXT: ret i32 [[RET]] 115; 116 %cmp = icmp eq i32 %c, 0 117 %ret = zext i1 %cmp to i32 118 ret i32 %ret 119} 120 121define internal i32 @less_than_two(i32 %c) { 122; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 123; CGSCC-LABEL: define {{[^@]+}}@less_than_two 124; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] { 125; CGSCC-NEXT: [[CMP:%.*]] = icmp slt i32 [[C]], 2 126; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[CMP]] to i32 127; CGSCC-NEXT: ret i32 [[RET]] 128; 129 %cmp = icmp slt i32 %c, 2 130 %ret = zext i1 %cmp to i32 131 ret i32 %ret 132} 133 134define i32 @potential_test3() { 135; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 136; TUNIT-LABEL: define {{[^@]+}}@potential_test3 137; TUNIT-SAME: () #[[ATTR0]] { 138; TUNIT-NEXT: ret i32 2 139; 140; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 141; CGSCC-LABEL: define {{[^@]+}}@potential_test3 142; CGSCC-SAME: () #[[ATTR1]] { 143; CGSCC-NEXT: [[CMP1:%.*]] = call i32 @iszero3(i32 noundef 0) #[[ATTR2]] 144; CGSCC-NEXT: [[TRUE1:%.*]] = call i32 @less_than_two(i32 noundef [[CMP1]]) #[[ATTR2]] 145; CGSCC-NEXT: [[CMP2:%.*]] = call i32 @iszero3(i32 noundef 1) #[[ATTR2]] 146; CGSCC-NEXT: [[TRUE2:%.*]] = call i32 @less_than_two(i32 noundef [[CMP2]]) #[[ATTR2]] 147; CGSCC-NEXT: [[RET:%.*]] = add i32 [[TRUE1]], [[TRUE2]] 148; CGSCC-NEXT: ret i32 [[RET]] 149; 150 %cmp1 = call i32 @iszero3(i32 0) 151 %true1 = call i32 @less_than_two(i32 %cmp1) 152 %cmp2 = call i32 @iszero3(i32 1) 153 %true2 = call i32 @less_than_two(i32 %cmp2) 154 %ret = add i32 %true1, %true2 155 ret i32 %ret 156} 157 158 159; potential-test 4,5 160; 161; simplified 162; int potential_test4(int c) { return return1or3(c) == 2; } 163; int potential_test5(int c) { return return1or3(c) == return2or4(c); } 164; 165; not simplified 166; int potential_test6(int c) { return return1or3(c) == 3; } 167; int potential_test7(int c) { return return1or3(c) == return3or4(c); } 168 169define i32 @potential_test4(i32 %c) { 170; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 171; TUNIT-LABEL: define {{[^@]+}}@potential_test4 172; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 173; TUNIT-NEXT: ret i32 0 174; 175; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 176; CGSCC-LABEL: define {{[^@]+}}@potential_test4 177; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] { 178; CGSCC-NEXT: [[CSRET:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]] 179; CGSCC-NEXT: [[FALSE:%.*]] = icmp eq i32 [[CSRET]], 2 180; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[FALSE]] to i32 181; CGSCC-NEXT: ret i32 [[RET]] 182; 183 %csret = call i32 @return1or3(i32 %c) 184 %false = icmp eq i32 %csret, 2 185 %ret = zext i1 %false to i32 186 ret i32 %ret 187} 188 189define i32 @potential_test5(i32 %c) { 190; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 191; TUNIT-LABEL: define {{[^@]+}}@potential_test5 192; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 193; TUNIT-NEXT: ret i32 0 194; 195; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 196; CGSCC-LABEL: define {{[^@]+}}@potential_test5 197; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] { 198; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]] 199; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @return2or4(i32 [[C]]) #[[ATTR2]] 200; CGSCC-NEXT: [[FALSE:%.*]] = icmp eq i32 [[CSRET1]], [[CSRET2]] 201; CGSCC-NEXT: [[RET:%.*]] = zext i1 [[FALSE]] to i32 202; CGSCC-NEXT: ret i32 [[RET]] 203; 204 %csret1 = call i32 @return1or3(i32 %c) 205 %csret2 = call i32 @return2or4(i32 %c) 206 %false = icmp eq i32 %csret1, %csret2 207 %ret = zext i1 %false to i32 208 ret i32 %ret 209} 210 211define i1 @potential_test6(i32 %c) { 212; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 213; TUNIT-LABEL: define {{[^@]+}}@potential_test6 214; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 215; TUNIT-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR1:[0-9]+]] 216; TUNIT-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], 3 217; TUNIT-NEXT: ret i1 [[RET]] 218; 219; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 220; CGSCC-LABEL: define {{[^@]+}}@potential_test6 221; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] { 222; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]] 223; CGSCC-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], 3 224; CGSCC-NEXT: ret i1 [[RET]] 225; 226 %csret1 = call i32 @return1or3(i32 %c) 227 %ret = icmp eq i32 %csret1, 3 228 ret i1 %ret 229} 230 231define i1 @potential_test7(i32 %c) { 232; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 233; TUNIT-LABEL: define {{[^@]+}}@potential_test7 234; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 235; TUNIT-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR1]] 236; TUNIT-NEXT: [[CSRET2:%.*]] = call i32 @return3or4(i32 [[C]]) #[[ATTR1]] 237; TUNIT-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], [[CSRET2]] 238; TUNIT-NEXT: ret i1 [[RET]] 239; 240; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 241; CGSCC-LABEL: define {{[^@]+}}@potential_test7 242; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR1]] { 243; CGSCC-NEXT: [[CSRET1:%.*]] = call i32 @return1or3(i32 [[C]]) #[[ATTR2]] 244; CGSCC-NEXT: [[CSRET2:%.*]] = call i32 @return3or4(i32 [[C]]) #[[ATTR2]] 245; CGSCC-NEXT: [[RET:%.*]] = icmp eq i32 [[CSRET1]], [[CSRET2]] 246; CGSCC-NEXT: ret i1 [[RET]] 247; 248 %csret1 = call i32 @return1or3(i32 %c) 249 %csret2 = call i32 @return3or4(i32 %c) 250 %ret = icmp eq i32 %csret1, %csret2 251 ret i1 %ret 252} 253 254define internal i32 @return1or3(i32 %c) { 255; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 256; CHECK-LABEL: define {{[^@]+}}@return1or3 257; CHECK-SAME: (i32 [[C:%.*]]) #[[ATTR0:[0-9]+]] { 258; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0 259; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 1, i32 3 260; CHECK-NEXT: ret i32 [[RET]] 261; 262 %cmp = icmp eq i32 %c, 0 263 %ret = select i1 %cmp, i32 1, i32 3 264 ret i32 %ret 265} 266 267define internal i32 @return2or4(i32 %c) { 268; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 269; CGSCC-LABEL: define {{[^@]+}}@return2or4 270; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 271; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0 272; CGSCC-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 2, i32 4 273; CGSCC-NEXT: ret i32 [[RET]] 274; 275 %cmp = icmp eq i32 %c, 0 276 %ret = select i1 %cmp, i32 2, i32 4 277 ret i32 %ret 278} 279 280define internal i32 @return3or4(i32 %c) { 281; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 282; CHECK-LABEL: define {{[^@]+}}@return3or4 283; CHECK-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 284; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 0 285; CHECK-NEXT: [[RET:%.*]] = select i1 [[CMP]], i32 3, i32 4 286; CHECK-NEXT: ret i32 [[RET]] 287; 288 %cmp = icmp eq i32 %c, 0 289 %ret = select i1 %cmp, i32 3, i32 4 290 ret i32 %ret 291} 292 293; potential-test 8 294; 295; propagate argument to callsite argument 296 297define internal i1 @cmp_with_four(i32 %c) { 298; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 299; CGSCC-LABEL: define {{[^@]+}}@cmp_with_four 300; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 301; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[C]], 4 302; CGSCC-NEXT: ret i1 [[CMP]] 303; 304 %cmp = icmp eq i32 %c, 4 305 ret i1 %cmp 306} 307 308define internal i1 @wrapper(i32 %c) { 309; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 310; CGSCC-LABEL: define {{[^@]+}}@wrapper 311; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] { 312; CGSCC-NEXT: [[RET:%.*]] = call i1 @cmp_with_four(i32 noundef [[C]]) #[[ATTR2]] 313; CGSCC-NEXT: ret i1 [[RET]] 314; 315 %ret = call i1 @cmp_with_four(i32 %c) 316 ret i1 %ret 317} 318 319define i1 @potential_test8() { 320; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 321; TUNIT-LABEL: define {{[^@]+}}@potential_test8 322; TUNIT-SAME: () #[[ATTR0]] { 323; TUNIT-NEXT: ret i1 false 324; 325; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 326; CGSCC-LABEL: define {{[^@]+}}@potential_test8 327; CGSCC-SAME: () #[[ATTR1]] { 328; CGSCC-NEXT: [[RES1:%.*]] = call i1 @wrapper(i32 noundef 1) #[[ATTR2]] 329; CGSCC-NEXT: [[RES3:%.*]] = call i1 @wrapper(i32 noundef 3) #[[ATTR2]] 330; CGSCC-NEXT: [[RES5:%.*]] = call i1 @wrapper(i32 noundef 5) #[[ATTR2]] 331; CGSCC-NEXT: [[RES13:%.*]] = or i1 [[RES1]], [[RES3]] 332; CGSCC-NEXT: [[RES135:%.*]] = or i1 [[RES13]], [[RES5]] 333; CGSCC-NEXT: ret i1 [[RES135]] 334; 335 %res1 = call i1 @wrapper(i32 1) 336 %res3 = call i1 @wrapper(i32 3) 337 %res5 = call i1 @wrapper(i32 5) 338 %res13 = or i1 %res1, %res3 339 %res135 = or i1 %res13, %res5 340 ret i1 %res135 341} 342 343define i1 @potential_test9() { 344; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 345; CHECK-LABEL: define {{[^@]+}}@potential_test9 346; CHECK-SAME: () #[[ATTR0]] { 347; CHECK-NEXT: entry: 348; CHECK-NEXT: br label [[COND:%.*]] 349; CHECK: cond: 350; CHECK-NEXT: [[I_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_1:%.*]], [[INC:%.*]] ] 351; CHECK-NEXT: [[C_0:%.*]] = phi i32 [ 1, [[ENTRY]] ], [ [[C_1:%.*]], [[INC]] ] 352; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I_0]], 10 353; CHECK-NEXT: br i1 [[CMP]], label [[BODY:%.*]], label [[END:%.*]] 354; CHECK: body: 355; CHECK-NEXT: [[C_1]] = mul i32 [[C_0]], -1 356; CHECK-NEXT: br label [[INC]] 357; CHECK: inc: 358; CHECK-NEXT: [[I_1]] = add i32 [[I_0]], 1 359; CHECK-NEXT: br label [[COND]] 360; CHECK: end: 361; CHECK-NEXT: ret i1 false 362; 363entry: 364 br label %cond 365cond: 366 %i.0 = phi i32 [0, %entry], [%i.1, %inc] 367 %c.0 = phi i32 [1, %entry], [%c.1, %inc] 368 %cmp = icmp slt i32 %i.0, 10 369 br i1 %cmp, label %body, label %end 370body: 371 %c.1 = mul i32 %c.0, -1 372 br label %inc 373inc: 374 %i.1 = add i32 %i.0, 1 375 br label %cond 376end: 377 %ret = icmp eq i32 %c.0, 0 378 ret i1 %ret 379} 380 381; Test 10 382; potential returned values of @may_return_undef is {1, -1} 383; and returned value of @potential_test10 can be simplified to 0(false) 384 385define internal i32 @may_return_undef(i32 %c) { 386; CGSCC: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 387; CGSCC-LABEL: define {{[^@]+}}@may_return_undef 388; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR0]] { 389; CGSCC-NEXT: switch i32 [[C]], label [[OTHERWISE:%.*]] [ 390; CGSCC-NEXT: i32 1, label [[A:%.*]] 391; CGSCC-NEXT: i32 -1, label [[B:%.*]] 392; CGSCC-NEXT: ] 393; CGSCC: a: 394; CGSCC-NEXT: ret i32 1 395; CGSCC: b: 396; CGSCC-NEXT: ret i32 -1 397; CGSCC: otherwise: 398; CGSCC-NEXT: ret i32 undef 399; 400 switch i32 %c, label %otherwise [i32 1, label %a 401 i32 -1, label %b] 402a: 403 ret i32 1 404b: 405 ret i32 -1 406otherwise: 407 ret i32 undef 408} 409 410define i1 @potential_test10(i32 %c) { 411; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 412; TUNIT-LABEL: define {{[^@]+}}@potential_test10 413; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 414; TUNIT-NEXT: ret i1 false 415; 416; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 417; CGSCC-LABEL: define {{[^@]+}}@potential_test10 418; CGSCC-SAME: (i32 noundef [[C:%.*]]) #[[ATTR1]] { 419; CGSCC-NEXT: [[RET:%.*]] = call i32 @may_return_undef(i32 noundef [[C]]) #[[ATTR2]] 420; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[RET]], 0 421; CGSCC-NEXT: ret i1 [[CMP]] 422; 423 %ret = call i32 @may_return_undef(i32 %c) 424 %cmp = icmp eq i32 %ret, 0 425 ret i1 %cmp 426} 427 428define i32 @optimize_undef_1(i1 %c) { 429; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 430; CHECK-LABEL: define {{[^@]+}}@optimize_undef_1 431; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] { 432; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 433; CHECK: t: 434; CHECK-NEXT: ret i32 0 435; CHECK: f: 436; CHECK-NEXT: [[UNDEF:%.*]] = add i32 undef, 1 437; CHECK-NEXT: ret i32 [[UNDEF]] 438; 439 br i1 %c, label %t, label %f 440t: 441 ret i32 0 442f: 443 %undef = add i32 undef, 1 444 ret i32 %undef 445} 446 447define i32 @optimize_undef_2(i1 %c) { 448; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 449; CHECK-LABEL: define {{[^@]+}}@optimize_undef_2 450; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] { 451; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 452; CHECK: t: 453; CHECK-NEXT: ret i32 0 454; CHECK: f: 455; CHECK-NEXT: [[UNDEF:%.*]] = sub i32 undef, 1 456; CHECK-NEXT: ret i32 [[UNDEF]] 457; 458 br i1 %c, label %t, label %f 459t: 460 ret i32 0 461f: 462 %undef = sub i32 undef, 1 463 ret i32 %undef 464} 465 466define i32 @optimize_undef_3(i1 %c) { 467; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 468; CHECK-LABEL: define {{[^@]+}}@optimize_undef_3 469; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] { 470; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 471; CHECK: t: 472; CHECK-NEXT: ret i32 0 473; CHECK: f: 474; CHECK-NEXT: ret i32 0 475; 476 br i1 %c, label %t, label %f 477t: 478 ret i32 0 479f: 480 %undef = icmp eq i32 undef, 0 481 %undef2 = zext i1 %undef to i32 482 ret i32 %undef2 483} 484 485 486; FIXME: returned value can be simplified to 0 487define i32 @potential_test11(i1 %c) { 488; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 489; TUNIT-LABEL: define {{[^@]+}}@potential_test11 490; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] { 491; TUNIT-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 noundef [[C]]) #[[ATTR1]] 492; TUNIT-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 noundef [[C]]) #[[ATTR1]] 493; TUNIT-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]] 494; TUNIT-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], 0 495; TUNIT-NEXT: ret i32 [[ACC2]] 496; 497; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 498; CGSCC-LABEL: define {{[^@]+}}@potential_test11 499; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] { 500; CGSCC-NEXT: [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 noundef [[C]]) #[[ATTR2]] 501; CGSCC-NEXT: [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 noundef [[C]]) #[[ATTR2]] 502; CGSCC-NEXT: [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 noundef [[C]]) #[[ATTR2]] 503; CGSCC-NEXT: [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]] 504; CGSCC-NEXT: [[ACC2:%.*]] = add i32 [[ACC1]], [[ZERO3]] 505; CGSCC-NEXT: ret i32 [[ACC2]] 506; 507 %zero1 = call i32 @optimize_undef_1(i1 %c) 508 %zero2 = call i32 @optimize_undef_2(i1 %c) 509 %zero3 = call i32 @optimize_undef_3(i1 %c) 510 %acc1 = add i32 %zero1, %zero2 511 %acc2 = add i32 %acc1, %zero3 512 ret i32 %acc2 513} 514 515define i32 @optimize_poison_1(i1 %c) { 516; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 517; CHECK-LABEL: define {{[^@]+}}@optimize_poison_1 518; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR0]] { 519; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 520; CHECK: t: 521; CHECK-NEXT: ret i32 0 522; CHECK: f: 523; CHECK-NEXT: ret i32 0 524; 525 br i1 %c, label %t, label %f 526t: 527 ret i32 0 528f: 529 %poison = sub nuw i32 0, 1 530 ret i32 %poison 531} 532 533; returned value can be simplified to 0 534define i32 @potential_test12(i1 %c) { 535; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 536; TUNIT-LABEL: define {{[^@]+}}@potential_test12 537; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR0]] { 538; TUNIT-NEXT: ret i32 0 539; 540; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 541; CGSCC-LABEL: define {{[^@]+}}@potential_test12 542; CGSCC-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] { 543; CGSCC-NEXT: [[ZERO:%.*]] = call noundef i32 @optimize_poison_1(i1 noundef [[C]]) #[[ATTR2]] 544; CGSCC-NEXT: ret i32 [[ZERO]] 545; 546 %zero = call i32 @optimize_poison_1(i1 %c) 547 ret i32 %zero 548} 549 550; Test 13 551; Do not simplify %ret in the callee to `%c`. 552; The potential value of %c is {0, 1} (undef is merged). 553; However, we should not simplify `and i32 %c, 3` to `%c` 554 555define internal i32 @potential_test13_callee(i32 %c) { 556; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 557; CHECK-LABEL: define {{[^@]+}}@potential_test13_callee 558; CHECK-SAME: (i32 [[C:%.*]]) #[[ATTR0]] { 559; CHECK-NEXT: [[RET:%.*]] = and i32 [[C]], 3 560; CHECK-NEXT: ret i32 [[RET]] 561; 562 %ret = and i32 %c, 3 563 ret i32 %ret 564} 565 566define i32 @potential_test13_caller1() { 567; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 568; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller1 569; TUNIT-SAME: () #[[ATTR0]] { 570; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 0) #[[ATTR1]] 571; TUNIT-NEXT: ret i32 [[RET]] 572; 573; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 574; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller1 575; CGSCC-SAME: () #[[ATTR1]] { 576; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 noundef 0) #[[ATTR2]] 577; CGSCC-NEXT: ret i32 [[RET]] 578; 579 %ret = call i32 @potential_test13_callee(i32 0) 580 ret i32 %ret 581} 582 583define i32 @potential_test13_caller2() { 584; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 585; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller2 586; TUNIT-SAME: () #[[ATTR0]] { 587; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 noundef 1) #[[ATTR1]] 588; TUNIT-NEXT: ret i32 [[RET]] 589; 590; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 591; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller2 592; CGSCC-SAME: () #[[ATTR1]] { 593; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 noundef 1) #[[ATTR2]] 594; CGSCC-NEXT: ret i32 [[RET]] 595; 596 %ret = call i32 @potential_test13_callee(i32 1) 597 ret i32 %ret 598} 599 600define i32 @potential_test13_caller3() { 601; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 602; TUNIT-LABEL: define {{[^@]+}}@potential_test13_caller3 603; TUNIT-SAME: () #[[ATTR0]] { 604; TUNIT-NEXT: [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) #[[ATTR1]] 605; TUNIT-NEXT: ret i32 [[RET]] 606; 607; CGSCC: Function Attrs: mustprogress nofree nosync nounwind willreturn memory(none) 608; CGSCC-LABEL: define {{[^@]+}}@potential_test13_caller3 609; CGSCC-SAME: () #[[ATTR1]] { 610; CGSCC-NEXT: [[RET:%.*]] = call noundef i32 @potential_test13_callee(i32 undef) #[[ATTR2]] 611; CGSCC-NEXT: ret i32 [[RET]] 612; 613 %ret = call i32 @potential_test13_callee(i32 undef) 614 ret i32 %ret 615} 616 617define i1 @potential_test14(i1 %c0, i1 %c1, i1 %c2, i1 %c3) { 618; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 619; CHECK-LABEL: define {{[^@]+}}@potential_test14 620; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) #[[ATTR0]] { 621; CHECK-NEXT: [[X0:%.*]] = select i1 [[C0]], i32 0, i32 1 622; CHECK-NEXT: [[X1:%.*]] = select i1 [[C1]], i32 [[X0]], i32 undef 623; CHECK-NEXT: [[Y2:%.*]] = select i1 [[C2]], i32 0, i32 7 624; CHECK-NEXT: [[Z3:%.*]] = select i1 [[C3]], i32 [[X1]], i32 [[Y2]] 625; CHECK-NEXT: [[RET:%.*]] = icmp slt i32 [[Z3]], 7 626; CHECK-NEXT: ret i1 [[RET]] 627; 628 %x0 = select i1 %c0, i32 0, i32 1 629 %x1 = select i1 %c1, i32 %x0, i32 undef 630 %y2 = select i1 %c2, i32 0, i32 7 631 %z3 = select i1 %c3, i32 %x1, i32 %y2 632 %ret = icmp slt i32 %z3, 7 633 ret i1 %ret 634} 635 636define i1 @potential_test15(i1 %c0, i1 %c1) { 637; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 638; CHECK-LABEL: define {{[^@]+}}@potential_test15 639; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]]) #[[ATTR0]] { 640; CHECK-NEXT: ret i1 false 641; 642 %x0 = select i1 %c0, i32 0, i32 1 643 %x1 = select i1 %c1, i32 %x0, i32 undef 644 %ret = icmp eq i32 %x1, 7 645 ret i1 %ret 646} 647 648define i1 @potential_test16(i1 %c0, i1 %c1) { 649; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) 650; CHECK-LABEL: define {{[^@]+}}@potential_test16 651; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]]) #[[ATTR0]] { 652; CHECK-NEXT: ret i1 false 653; 654 %x0 = select i1 %c0, i32 0, i32 undef 655 %x1 = select i1 %c1, i32 %x0, i32 1 656 %ret = icmp eq i32 %x1, 7 657 ret i1 %ret 658} 659 660;. 661; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 662; TUNIT: attributes #[[ATTR1]] = { nofree nosync nounwind willreturn memory(none) } 663;. 664; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 665; CGSCC: attributes #[[ATTR1]] = { mustprogress nofree nosync nounwind willreturn memory(none) } 666; CGSCC: attributes #[[ATTR2]] = { nofree nosync willreturn } 667;. 668