1; RUN: opt -functionattrs -S < %s | FileCheck %s --check-prefix=FNATTR 2; 3; Test cases specifically designed for the "returned" argument attribute. 4; We use FIXME's to indicate problems and missing attributes. 5; 6 7; TEST SCC test returning an integer value argument 8; 9; 10; FNATTR: define i32 @sink_r0(i32 returned %r) 11; FNATTR: define i32 @scc_r1(i32 %a, i32 %r, i32 %b) 12; FNATTR: define i32 @scc_r2(i32 %a, i32 %b, i32 %r) 13; FNATTR: define i32 @scc_rX(i32 %a, i32 %b, i32 %r) 14; 15; 16; int scc_r1(int a, int b, int r); 17; int scc_r2(int a, int b, int r); 18; 19; __attribute__((noinline)) int sink_r0(int r) { 20; return r; 21; } 22; 23; __attribute__((noinline)) int scc_r1(int a, int r, int b) { 24; return scc_r2(r, a, sink_r0(r)); 25; } 26; 27; __attribute__((noinline)) int scc_r2(int a, int b, int r) { 28; if (a > b) 29; return scc_r2(b, a, sink_r0(r)); 30; if (a < b) 31; return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r2(a, b, r)), scc_r1(a, b, r)); 32; return a == b ? r : scc_r2(a, b, r); 33; } 34; __attribute__((noinline)) int scc_rX(int a, int b, int r) { 35; if (a > b) 36; return scc_r2(b, a, sink_r0(r)); 37; if (a < b) // V Diff to scc_r2 38; return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r1(a, b, r)), scc_r1(a, b, r)); 39; return a == b ? r : scc_r2(a, b, r); 40; } 41target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 42 43define i32 @sink_r0(i32 %r) #0 { 44entry: 45 ret i32 %r 46} 47 48define i32 @scc_r1(i32 %a, i32 %r, i32 %b) #0 { 49entry: 50 %call = call i32 @sink_r0(i32 %r) 51 %call1 = call i32 @scc_r2(i32 %r, i32 %a, i32 %call) 52 ret i32 %call1 53} 54 55define i32 @scc_r2(i32 %a, i32 %b, i32 %r) #0 { 56entry: 57 %cmp = icmp sgt i32 %a, %b 58 br i1 %cmp, label %if.then, label %if.end 59 60if.then: ; preds = %entry 61 %call = call i32 @sink_r0(i32 %r) 62 %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call) 63 br label %return 64 65if.end: ; preds = %entry 66 %cmp2 = icmp slt i32 %a, %b 67 br i1 %cmp2, label %if.then3, label %if.end12 68 69if.then3: ; preds = %if.end 70 %call4 = call i32 @sink_r0(i32 %b) 71 %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 72 %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r) 73 %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r) 74 %call8 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r) 75 %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8) 76 %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 77 %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10) 78 br label %return 79 80if.end12: ; preds = %if.end 81 %cmp13 = icmp eq i32 %a, %b 82 br i1 %cmp13, label %cond.true, label %cond.false 83 84cond.true: ; preds = %if.end12 85 br label %cond.end 86 87cond.false: ; preds = %if.end12 88 %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r) 89 br label %cond.end 90 91cond.end: ; preds = %cond.false, %cond.true 92 %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ] 93 br label %return 94 95return: ; preds = %cond.end, %if.then3, %if.then 96 %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ] 97 ret i32 %retval.0 98} 99 100define i32 @scc_rX(i32 %a, i32 %b, i32 %r) #0 { 101entry: 102 %cmp = icmp sgt i32 %a, %b 103 br i1 %cmp, label %if.then, label %if.end 104 105if.then: ; preds = %entry 106 %call = call i32 @sink_r0(i32 %r) 107 %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call) 108 br label %return 109 110if.end: ; preds = %entry 111 %cmp2 = icmp slt i32 %a, %b 112 br i1 %cmp2, label %if.then3, label %if.end12 113 114if.then3: ; preds = %if.end 115 %call4 = call i32 @sink_r0(i32 %b) 116 %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 117 %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r) 118 %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r) 119 %call8 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 120 %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8) 121 %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 122 %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10) 123 br label %return 124 125if.end12: ; preds = %if.end 126 %cmp13 = icmp eq i32 %a, %b 127 br i1 %cmp13, label %cond.true, label %cond.false 128 129cond.true: ; preds = %if.end12 130 br label %cond.end 131 132cond.false: ; preds = %if.end12 133 %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r) 134 br label %cond.end 135 136cond.end: ; preds = %cond.false, %cond.true 137 %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ] 138 br label %return 139 140return: ; preds = %cond.end, %if.then3, %if.then 141 %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ] 142 ret i32 %retval.0 143} 144 145 146; TEST SCC test returning a pointer value argument 147; 148; FNATTR: define double* @ptr_sink_r0(double* readnone returned %r) 149; FNATTR: define double* @ptr_scc_r1(double* %a, double* readnone %r, double* nocapture readnone %b) 150; FNATTR: define double* @ptr_scc_r2(double* readnone %a, double* readnone %b, double* readnone %r) 151; 152; 153; double* ptr_scc_r1(double* a, double* b, double* r); 154; double* ptr_scc_r2(double* a, double* b, double* r); 155; 156; __attribute__((noinline)) double* ptr_sink_r0(double* r) { 157; return r; 158; } 159; 160; __attribute__((noinline)) double* ptr_scc_r1(double* a, double* r, double* b) { 161; return ptr_scc_r2(r, a, ptr_sink_r0(r)); 162; } 163; 164; __attribute__((noinline)) double* ptr_scc_r2(double* a, double* b, double* r) { 165; if (a > b) 166; return ptr_scc_r2(b, a, ptr_sink_r0(r)); 167; if (a < b) 168; return ptr_scc_r1(ptr_sink_r0(b), ptr_scc_r2(ptr_scc_r1(a, b, r), ptr_scc_r1(a, ptr_scc_r2(r, r, r), r), ptr_scc_r2(a, b, r)), ptr_scc_r1(a, b, r)); 169; return a == b ? r : ptr_scc_r2(a, b, r); 170; } 171define double* @ptr_sink_r0(double* %r) #0 { 172entry: 173 ret double* %r 174} 175 176define double* @ptr_scc_r1(double* %a, double* %r, double* %b) #0 { 177entry: 178 %call = call double* @ptr_sink_r0(double* %r) 179 %call1 = call double* @ptr_scc_r2(double* %r, double* %a, double* %call) 180 ret double* %call1 181} 182 183define double* @ptr_scc_r2(double* %a, double* %b, double* %r) #0 { 184entry: 185 %cmp = icmp ugt double* %a, %b 186 br i1 %cmp, label %if.then, label %if.end 187 188if.then: ; preds = %entry 189 %call = call double* @ptr_sink_r0(double* %r) 190 %call1 = call double* @ptr_scc_r2(double* %b, double* %a, double* %call) 191 br label %return 192 193if.end: ; preds = %entry 194 %cmp2 = icmp ult double* %a, %b 195 br i1 %cmp2, label %if.then3, label %if.end12 196 197if.then3: ; preds = %if.end 198 %call4 = call double* @ptr_sink_r0(double* %b) 199 %call5 = call double* @ptr_scc_r1(double* %a, double* %b, double* %r) 200 %call6 = call double* @ptr_scc_r2(double* %r, double* %r, double* %r) 201 %call7 = call double* @ptr_scc_r1(double* %a, double* %call6, double* %r) 202 %call8 = call double* @ptr_scc_r2(double* %a, double* %b, double* %r) 203 %call9 = call double* @ptr_scc_r2(double* %call5, double* %call7, double* %call8) 204 %call10 = call double* @ptr_scc_r1(double* %a, double* %b, double* %r) 205 %call11 = call double* @ptr_scc_r1(double* %call4, double* %call9, double* %call10) 206 br label %return 207 208if.end12: ; preds = %if.end 209 %cmp13 = icmp eq double* %a, %b 210 br i1 %cmp13, label %cond.true, label %cond.false 211 212cond.true: ; preds = %if.end12 213 br label %cond.end 214 215cond.false: ; preds = %if.end12 216 %call14 = call double* @ptr_scc_r2(double* %a, double* %b, double* %r) 217 br label %cond.end 218 219cond.end: ; preds = %cond.false, %cond.true 220 %cond = phi double* [ %r, %cond.true ], [ %call14, %cond.false ] 221 br label %return 222 223return: ; preds = %cond.end, %if.then3, %if.then 224 %retval.0 = phi double* [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ] 225 ret double* %retval.0 226} 227 228 229; TEST a no-return singleton SCC 230; 231; int* rt0(int *a) { 232; return *a ? a : rt0(a); 233; } 234; 235; FNATTR: define i32* @rt0(i32* readonly %a) 236define i32* @rt0(i32* %a) #0 { 237entry: 238 %v = load i32, i32* %a, align 4 239 %tobool = icmp ne i32 %v, 0 240 %call = call i32* @rt0(i32* %a) 241 %sel = select i1 %tobool, i32* %a, i32* %call 242 ret i32* %sel 243} 244 245; TEST a no-return singleton SCC 246; 247; int* rt1(int *a) { 248; return *a ? undef : rt1(a); 249; } 250; 251; FNATTR: define noalias i32* @rt1(i32* nocapture readonly %a) 252define i32* @rt1(i32* %a) #0 { 253entry: 254 %v = load i32, i32* %a, align 4 255 %tobool = icmp ne i32 %v, 0 256 %call = call i32* @rt1(i32* %a) 257 %sel = select i1 %tobool, i32* undef, i32* %call 258 ret i32* %sel 259} 260 261; TEST another SCC test 262; 263; FNATTR: define i32* @rt2_helper(i32* %a) 264; FNATTR: define i32* @rt2(i32* readnone %a, i32* readnone %b) 265define i32* @rt2_helper(i32* %a) #0 { 266entry: 267 %call = call i32* @rt2(i32* %a, i32* %a) 268 ret i32* %call 269} 270 271define i32* @rt2(i32* %a, i32 *%b) #0 { 272entry: 273 %cmp = icmp eq i32* %a, null 274 br i1 %cmp, label %if.then, label %if.end 275 276if.then: 277 %call = call i32* @rt2_helper(i32* %a) 278 br label %if.end 279 280if.end: 281 %sel = phi i32* [ %b, %entry], [%call, %if.then] 282 ret i32* %sel 283} 284 285; TEST another SCC test 286; 287; FNATTR: define i32* @rt3_helper(i32* %a, i32* %b) 288; FNATTR: define i32* @rt3(i32* readnone %a, i32* readnone %b) 289define i32* @rt3_helper(i32* %a, i32* %b) #0 { 290entry: 291 %call = call i32* @rt3(i32* %a, i32* %b) 292 ret i32* %call 293} 294 295define i32* @rt3(i32* %a, i32 *%b) #0 { 296entry: 297 %cmp = icmp eq i32* %a, null 298 br i1 %cmp, label %if.then, label %if.end 299 300if.then: 301 %call = call i32* @rt3_helper(i32* %a, i32* %b) 302 br label %if.end 303 304if.end: 305 %sel = phi i32* [ %b, %entry], [%call, %if.then] 306 ret i32* %sel 307} 308 309; TEST address taken function with call to an external functions 310; 311; void unknown_fn(void *); 312; 313; int* calls_unknown_fn(int *r) { 314; unknown_fn(&calls_unknown_fn); 315; return r; 316; } 317; 318; 319; FNATTR: define i32* @calls_unknown_fn(i32* readnone returned %r) 320declare void @unknown_fn(i32* (i32*)*) #0 321 322define i32* @calls_unknown_fn(i32* %r) #0 { 323 tail call void @unknown_fn(i32* (i32*)* nonnull @calls_unknown_fn) 324 ret i32* %r 325} 326 327 328; TEST return call to a function that might be redifined at link time 329; 330; int *maybe_redefined_fn2(int *r) { 331; return r; 332; } 333; 334; int *calls_maybe_redefined_fn2(int *r) { 335; return maybe_redefined_fn2(r); 336; } 337; 338; Verify the maybe-redefined function is not annotated: 339; 340; 341; FNATTR: define i32* @calls_maybe_redefined_fn2(i32* %r) 342define linkonce_odr i32* @maybe_redefined_fn2(i32* %r) #0 { 343entry: 344 ret i32* %r 345} 346 347define i32* @calls_maybe_redefined_fn2(i32* %r) #0 { 348entry: 349 %call = call i32* @maybe_redefined_fn2(i32* %r) 350 ret i32* %call 351} 352 353 354; TEST returned argument goes through select and phi 355; 356; double select_and_phi(double b) { 357; double x = b; 358; if (b > 0) 359; x = b; 360; return b == 0? b : x; 361; } 362; 363; 364; FNATTR: define double @select_and_phi(double %b) 365define double @select_and_phi(double %b) #0 { 366entry: 367 %cmp = fcmp ogt double %b, 0.000000e+00 368 br i1 %cmp, label %if.then, label %if.end 369 370if.then: ; preds = %entry 371 br label %if.end 372 373if.end: ; preds = %if.then, %entry 374 %phi = phi double [ %b, %if.then ], [ %b, %entry ] 375 %cmp1 = fcmp oeq double %b, 0.000000e+00 376 %sel = select i1 %cmp1, double %b, double %phi 377 ret double %sel 378} 379 380 381; TEST returned argument goes through recursion, select, and phi 382; 383; double recursion_select_and_phi(int a, double b) { 384; double x = b; 385; if (a-- > 0) 386; x = recursion_select_and_phi(a, b); 387; return b == 0? b : x; 388; } 389; 390; 391; FNATTR: define double @recursion_select_and_phi(i32 %a, double %b) 392; 393define double @recursion_select_and_phi(i32 %a, double %b) #0 { 394entry: 395 %dec = add nsw i32 %a, -1 396 %cmp = icmp sgt i32 %a, 0 397 br i1 %cmp, label %if.then, label %if.end 398 399if.then: ; preds = %entry 400 %call = call double @recursion_select_and_phi(i32 %dec, double %b) 401 br label %if.end 402 403if.end: ; preds = %if.then, %entry 404 %phi = phi double [ %call, %if.then ], [ %b, %entry ] 405 %cmp1 = fcmp oeq double %b, 0.000000e+00 406 %sel = select i1 %cmp1, double %b, double %phi 407 ret double %sel 408} 409 410 411; TEST returned argument goes through bitcasts 412; 413; double* bitcast(int* b) { 414; return (double*)b; 415; } 416; 417; 418; FNATTR: define double* @bitcast(i32* readnone %b) 419; 420define double* @bitcast(i32* %b) #0 { 421entry: 422 %bc0 = bitcast i32* %b to double* 423 ret double* %bc0 424} 425 426 427; TEST returned argument goes through select and phi interleaved with bitcasts 428; 429; double* bitcasts_select_and_phi(int* b) { 430; double* x = b; 431; if (b == 0) 432; x = b; 433; return b != 0 ? b : x; 434; } 435; 436; 437; FNATTR: define double* @bitcasts_select_and_phi(i32* readnone %b) 438; 439define double* @bitcasts_select_and_phi(i32* %b) #0 { 440entry: 441 %bc0 = bitcast i32* %b to double* 442 %cmp = icmp eq double* %bc0, null 443 br i1 %cmp, label %if.then, label %if.end 444 445if.then: ; preds = %entry 446 %bc1 = bitcast i32* %b to double* 447 br label %if.end 448 449if.end: ; preds = %if.then, %entry 450 %phi = phi double* [ %bc1, %if.then ], [ %bc0, %entry ] 451 %bc2 = bitcast double* %phi to i8* 452 %bc3 = bitcast i32* %b to i8* 453 %cmp2 = icmp ne double* %bc0, null 454 %sel = select i1 %cmp2, i8* %bc2, i8* %bc3 455 %bc4 = bitcast i8* %sel to double* 456 ret double* %bc4 457} 458 459 460; TEST return argument or argument or undef 461; 462; double* ret_arg_arg_undef(int* b) { 463; if (b == 0) 464; return (double*)b; 465; if (b == 0) 466; return (double*)b; 467; /* return undef */ 468; } 469; 470; 471; FNATTR: define double* @ret_arg_arg_undef(i32* readnone %b) 472; 473define double* @ret_arg_arg_undef(i32* %b) #0 { 474entry: 475 %bc0 = bitcast i32* %b to double* 476 %cmp = icmp eq double* %bc0, null 477 br i1 %cmp, label %ret_arg0, label %if.end 478 479ret_arg0: 480 %bc1 = bitcast i32* %b to double* 481 ret double* %bc1 482 483if.end: 484 br i1 %cmp, label %ret_arg1, label %ret_undef 485 486ret_arg1: 487 ret double* %bc0 488 489ret_undef: 490 ret double *undef 491} 492 493 494; TEST return undef or argument or argument 495; 496; double* ret_undef_arg_arg(int* b) { 497; if (b == 0) 498; return (double*)b; 499; if (b == 0) 500; return (double*)b; 501; /* return undef */ 502; } 503; 504; 505; FNATTR: define double* @ret_undef_arg_arg(i32* readnone %b) 506; 507define double* @ret_undef_arg_arg(i32* %b) #0 { 508entry: 509 %bc0 = bitcast i32* %b to double* 510 %cmp = icmp eq double* %bc0, null 511 br i1 %cmp, label %ret_undef, label %if.end 512 513ret_undef: 514 ret double *undef 515 516if.end: 517 br i1 %cmp, label %ret_arg0, label %ret_arg1 518 519ret_arg0: 520 ret double* %bc0 521 522ret_arg1: 523 %bc1 = bitcast i32* %b to double* 524 ret double* %bc1 525} 526 527 528; TEST return undef or argument or undef 529; 530; double* ret_undef_arg_undef(int* b) { 531; if (b == 0) 532; /* return undef */ 533; if (b == 0) 534; return (double*)b; 535; /* return undef */ 536; } 537; 538; 539; FNATTR: define double* @ret_undef_arg_undef(i32* readnone %b) 540define double* @ret_undef_arg_undef(i32* %b) #0 { 541entry: 542 %bc0 = bitcast i32* %b to double* 543 %cmp = icmp eq double* %bc0, null 544 br i1 %cmp, label %ret_undef0, label %if.end 545 546ret_undef0: 547 ret double *undef 548 549if.end: 550 br i1 %cmp, label %ret_arg, label %ret_undef1 551 552ret_arg: 553 ret double* %bc0 554 555ret_undef1: 556 ret double *undef 557} 558 559; TEST return argument or unknown call result 560; 561; int* ret_arg_or_unknown(int* b) { 562; if (b == 0) 563; return b; 564; return unknown(); 565; } 566; 567; Verify we do not assume b is returned 568; 569; FNATTR: define i32* @ret_arg_or_unknown(i32* %b) 570; FNATTR: define i32* @ret_arg_or_unknown_through_phi(i32* %b) 571declare i32* @unknown(i32*) 572 573define i32* @ret_arg_or_unknown(i32* %b) #0 { 574entry: 575 %cmp = icmp eq i32* %b, null 576 br i1 %cmp, label %ret_arg, label %ret_unknown 577 578ret_arg: 579 ret i32* %b 580 581ret_unknown: 582 %call = call i32* @unknown(i32* %b) 583 ret i32* %call 584} 585 586define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 { 587entry: 588 %cmp = icmp eq i32* %b, null 589 br i1 %cmp, label %ret_arg, label %ret_unknown 590 591ret_arg: 592 br label %r 593 594ret_unknown: 595 %call = call i32* @unknown(i32* %b) 596 br label %r 597 598r: 599 %phi = phi i32* [ %b, %ret_arg ], [ %call, %ret_unknown ] 600 ret i32* %phi 601} 602 603; TEST inconsistent IR in dead code. 604; 605; FNATTR: define i32 @deadblockcall1(i32 %A) 606; FNATTR: define i32 @deadblockcall2(i32 %A) 607; FNATTR: define i32 @deadblockphi1(i32 %A) 608; FNATTR: define i32 @deadblockphi2(i32 %A) 609define i32 @deadblockcall1(i32 %A) #0 { 610entry: 611 ret i32 %A 612unreachableblock: 613 %B = call i32 @deadblockcall1(i32 %B) 614 ret i32 %B 615} 616 617declare i32 @deadblockcall_helper(i32 returned %A); 618 619define i32 @deadblockcall2(i32 %A) #0 { 620entry: 621 ret i32 %A 622unreachableblock1: 623 %B = call i32 @deadblockcall_helper(i32 %B) 624 ret i32 %B 625unreachableblock2: 626 %C = call i32 @deadblockcall1(i32 %C) 627 ret i32 %C 628} 629 630define i32 @deadblockphi1(i32 %A) #0 { 631entry: 632 br label %r 633unreachableblock1: 634 %B = call i32 @deadblockcall_helper(i32 %B) 635 ret i32 %B 636unreachableblock2: 637 %C = call i32 @deadblockcall1(i32 %C) 638 br label %r 639r: 640 %PHI = phi i32 [%A, %entry], [%C, %unreachableblock2] 641 ret i32 %PHI 642} 643 644define i32 @deadblockphi2(i32 %A) #0 { 645entry: 646 br label %r 647unreachableblock1: 648 %B = call i32 @deadblockcall_helper(i32 %B) 649 br label %unreachableblock3 650unreachableblock2: 651 %C = call i32 @deadblockcall1(i32 %C) 652 br label %unreachableblock3 653unreachableblock3: 654 %PHI1 = phi i32 [%B, %unreachableblock1], [%C, %unreachableblock2] 655 br label %r 656r: 657 %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3] 658 ret i32 %PHI2 659} 660 661declare void @noreturn() noreturn; 662 663define i32 @deadblockphi3(i32 %A, i1 %c) #0 { 664entry: 665 br i1 %c, label %r, label %unreachablecall 666unreachablecall: 667 call void @noreturn(); 668 %B = call i32 @deadblockcall_helper(i32 0) 669 br label %unreachableblock3 670unreachableblock2: 671 %C = call i32 @deadblockcall1(i32 %C) 672 br label %unreachableblock3 673unreachableblock3: 674 %PHI1 = phi i32 [%B, %unreachablecall], [%C, %unreachableblock2] 675 br label %r 676r: 677 %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3] 678 ret i32 %PHI2 679} 680 681attributes #0 = { noinline nounwind uwtable } 682