1; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \ 2; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE --check-prefix=ENABLE-V4T 3; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv5-macho \ 4; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE --check-prefix=ENABLE-V5T 5; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \ 6; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE --check-prefix=DISABLE-V4T 7; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv5-macho \ 8; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE --check-prefix=DISABLE-V5T 9; 10; Note: Lots of tests use inline asm instead of regular calls. 11; This allows to have a better control on what the allocation will do. 12; Otherwise, we may have spill right in the entry block, defeating 13; shrink-wrapping. Moreover, some of the inline asm statements (nop) 14; are here to ensure that the related paths do not end up as critical 15; edges. 16; Also disable the late if-converter as it makes harder to reason on 17; the diffs. 18 19; Initial motivating example: Simple diamond with a call just on one side. 20; CHECK-LABEL: foo: 21; 22; Compare the arguments and jump to exit. 23; No prologue needed. 24; ENABLE: cmp r0, r1 25; ENABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]] 26; 27; Prologue code. 28; CHECK: push {r7, lr} 29; CHECK: sub sp, #8 30; 31; Compare the arguments and jump to exit. 32; After the prologue is set. 33; DISABLE: cmp r0, r1 34; DISABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]] 35; 36; Store %a in the alloca. 37; CHECK: str r0, [sp, #4] 38; Set the alloca address in the second argument. 39; Set the first argument to zero. 40; CHECK: movs r0, #0 41; CHECK-NEXT: add r1, sp, #4 42; CHECK-NEXT: bl 43; 44; With shrink-wrapping, epilogue is just after the call. 45; ENABLE-NEXT: add sp, #8 46; ENABLE-V5T-NEXT: pop {r7, pc} 47; ENABLE-V4T-NEXT: pop {r7} 48; ENABLE-V4T-NEXT: pop {r1} 49; ENABLE-V4T-NEXT: mov lr, r1 50; 51; CHECK: [[EXIT_LABEL]]: 52; 53; Without shrink-wrapping, epilogue is in the exit block. 54; Epilogue code. (What we pop does not matter.) 55; DISABLE: add sp, #8 56; DISABLE-V5T-NEXT: pop {r7, pc} 57; DISABLE-V4T-NEXT: pop {r7} 58; DISABLE-V4T-NEXT: pop {r1} 59; DISABLE-V4T-NEXT: bx r1 60; 61; ENABLE-NEXT: bx lr 62define i32 @foo(i32 %a, i32 %b) { 63 %tmp = alloca i32, align 4 64 %tmp2 = icmp slt i32 %a, %b 65 br i1 %tmp2, label %true, label %false 66 67true: 68 store i32 %a, i32* %tmp, align 4 69 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) 70 br label %false 71 72false: 73 %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ] 74 ret i32 %tmp.0 75} 76 77 78; Same, but the final BB is non-trivial, so we don't duplicate the return inst. 79; CHECK-LABEL: bar: 80; 81; With shrink-wrapping, epilogue is just after the call. 82; CHECK: bl 83; ENABLE-NEXT: add sp, #8 84; ENABLE-NEXT: pop {r7} 85; ENABLE-NEXT: pop {r0} 86; ENABLE-NEXT: mov lr, r0 87; 88; CHECK: movs r0, #42 89; 90; Without shrink-wrapping, epilogue is in the exit block. 91; Epilogue code. (What we pop does not matter.) 92; DISABLE: add sp, #8 93; DISABLE-V5T-NEXT: pop {r7, pc} 94; DISABLE-V4T-NEXT: pop {r7} 95; DISABLE-V4T-NEXT: pop {r1} 96; DISABLE-V4T-NEXT: bx r1 97; 98; ENABLE-NEXT: bx lr 99define i32 @bar(i32 %a, i32 %b) { 100 %tmp = alloca i32, align 4 101 %tmp2 = icmp slt i32 %a, %b 102 br i1 %tmp2, label %true, label %false 103 104true: 105 store i32 %a, i32* %tmp, align 4 106 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) 107 br label %false 108 109false: 110 ret i32 42 111} 112 113; Function Attrs: optsize 114declare i32 @doSomething(i32, i32*) 115 116 117; Check that we do not perform the restore inside the loop whereas the save 118; is outside. 119; CHECK-LABEL: freqSaveAndRestoreOutsideLoop: 120; 121; Shrink-wrapping allows to skip the prologue in the else case. 122; ENABLE: cmp r0, #0 123; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 124; 125; Prologue code. 126; Make sure we save the CSR used in the inline asm: r4. 127; CHECK: push {r4, lr} 128; 129; DISABLE: cmp r0, #0 130; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 131; 132; SUM is in r0 because it is coalesced with the second 133; argument on the else path. 134; CHECK: movs [[SUM:r0]], #0 135; CHECK-NEXT: movs [[IV:r[0-9]+]], #10 136; 137; Next BB. 138; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body 139; CHECK: movs [[TMP:r[0-9]+]], #1 140; CHECK: adds [[SUM]], [[TMP]], [[SUM]] 141; CHECK-NEXT: subs [[IV]], [[IV]], #1 142; CHECK-NEXT: cmp [[IV]], #0 143; CHECK-NEXT: bne [[LOOP]] 144; 145; Next BB. 146; SUM << 3. 147; CHECK: lsls [[SUM]], [[SUM]], #3 148; 149; Duplicated epilogue. 150; DISABLE-V5T: pop {r4, pc} 151; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]] 152; 153; CHECK: [[ELSE_LABEL]]: @ %if.else 154; Shift second argument by one and store into returned register. 155; CHECK: lsls r0, r1, #1 156; DISABLE-V5T-NEXT: pop {r4, pc} 157; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end 158; DISABLE-V4T-NEXT: pop {r4} 159; DISABLE-V4T-NEXT: pop {r1} 160; DISABLE-V4T-NEXT: bx r1 161; 162; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end 163; ENABLE-NEXT: bx lr 164define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) { 165entry: 166 %tobool = icmp eq i32 %cond, 0 167 br i1 %tobool, label %if.else, label %for.preheader 168 169for.preheader: 170 tail call void asm "nop", ""() 171 br label %for.body 172 173for.body: ; preds = %entry, %for.body 174 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ] 175 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ] 176 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"() 177 %add = add nsw i32 %call, %sum.04 178 %inc = add nuw nsw i32 %i.05, 1 179 %exitcond = icmp eq i32 %inc, 10 180 br i1 %exitcond, label %for.end, label %for.body 181 182for.end: ; preds = %for.body 183 %shl = shl i32 %add, 3 184 br label %if.end 185 186if.else: ; preds = %entry 187 %mul = shl nsw i32 %N, 1 188 br label %if.end 189 190if.end: ; preds = %if.else, %for.end 191 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ] 192 ret i32 %sum.1 193} 194 195declare i32 @something(...) 196 197; Check that we do not perform the shrink-wrapping inside the loop even 198; though that would be legal. The cost model must prevent that. 199; CHECK-LABEL: freqSaveAndRestoreOutsideLoop2: 200; Prologue code. 201; Make sure we save the CSR used in the inline asm: r4. 202; CHECK: push {r4 203; This is the nop. 204; CHECK: mov r8, r8 205; CHECK: movs [[SUM:r0]], #0 206; CHECK-NEXT: movs [[IV:r[0-9]+]], #10 207; Next BB. 208; CHECK: [[LOOP_LABEL:LBB[0-9_]+]]: @ %for.body 209; CHECK: movs [[TMP:r[0-9]+]], #1 210; CHECK: adds [[SUM]], [[TMP]], [[SUM]] 211; CHECK-NEXT: subs [[IV]], [[IV]], #1 212; CHECK-NEXT: cmp [[IV]], #0 213; CHECK-NEXT: bne [[LOOP_LABEL]] 214; Next BB. 215; CHECK: @ %for.exit 216; This is the nop. 217; CHECK: mov r8, r8 218; CHECK: pop {r4 219define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) { 220entry: 221 br label %for.preheader 222 223for.preheader: 224 tail call void asm "nop", ""() 225 br label %for.body 226 227for.body: ; preds = %for.body, %entry 228 %i.04 = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ] 229 %sum.03 = phi i32 [ 0, %for.preheader ], [ %add, %for.body ] 230 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"() 231 %add = add nsw i32 %call, %sum.03 232 %inc = add nuw nsw i32 %i.04, 1 233 %exitcond = icmp eq i32 %inc, 10 234 br i1 %exitcond, label %for.exit, label %for.body 235 236for.exit: 237 tail call void asm "nop", ""() 238 br label %for.end 239 240for.end: ; preds = %for.body 241 ret i32 %add 242} 243 244; Check with a more complex case that we do not have save within the loop and 245; restore outside. 246; CHECK-LABEL: loopInfoSaveOutsideLoop: 247; 248; ENABLE: cmp r0, #0 249; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 250; 251; Prologue code. 252; Make sure we save the CSR used in the inline asm: r4. 253; CHECK: push {r4, lr} 254; 255; DISABLE: cmp r0, #0 256; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 257; 258; SUM is in r0 because it is coalesced with the second 259; argument on the else path. 260; CHECK: movs [[SUM:r0]], #0 261; CHECK-NEXT: movs [[IV:r[0-9]+]], #10 262; 263; Next BB. 264; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body 265; CHECK: movs [[TMP:r[0-9]+]], #1 266; CHECK: adds [[SUM]], [[TMP]], [[SUM]] 267; CHECK-NEXT: subs [[IV]], [[IV]], #1 268; CHECK-NEXT: cmp [[IV]], #0 269; CHECK-NEXT: bne [[LOOP]] 270; 271; Next BB. 272; SUM << 3. 273; CHECK: lsls [[SUM]], [[SUM]], #3 274; ENABLE-V5T-NEXT: pop {r4, pc} 275; ENABLE-V4T-NEXT: pop {r4} 276; ENABLE-V4T-NEXT: pop {r1} 277; ENABLE-V4T-NEXT: bx r1 278; 279; Duplicated epilogue. 280; DISABLE-V5T: pop {r4, pc} 281; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]] 282; 283; CHECK: [[ELSE_LABEL]]: @ %if.else 284; Shift second argument by one and store into returned register. 285; CHECK: lsls r0, r1, #1 286; DISABLE-V5T-NEXT: pop {r4, pc} 287; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end 288; DISABLE-V4T-NEXT: pop {r4} 289; DISABLE-V4T-NEXT: pop {r1} 290; DISABLE-V4T-NEXT: bx r1 291; 292; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end 293; ENABLE-NEXT: bx lr 294define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) { 295entry: 296 %tobool = icmp eq i32 %cond, 0 297 br i1 %tobool, label %if.else, label %for.preheader 298 299for.preheader: 300 tail call void asm "nop", ""() 301 br label %for.body 302 303for.body: ; preds = %entry, %for.body 304 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ] 305 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ] 306 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"() 307 %add = add nsw i32 %call, %sum.04 308 %inc = add nuw nsw i32 %i.05, 1 309 %exitcond = icmp eq i32 %inc, 10 310 br i1 %exitcond, label %for.end, label %for.body 311 312for.end: ; preds = %for.body 313 tail call void asm "nop", "~{r4}"() 314 %shl = shl i32 %add, 3 315 br label %if.end 316 317if.else: ; preds = %entry 318 %mul = shl nsw i32 %N, 1 319 br label %if.end 320 321if.end: ; preds = %if.else, %for.end 322 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ] 323 ret i32 %sum.1 324} 325 326declare void @somethingElse(...) 327 328; Check with a more complex case that we do not have restore within the loop and 329; save outside. 330; CHECK-LABEL: loopInfoRestoreOutsideLoop: 331; 332; ENABLE: cmp r0, #0 333; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 334; 335; Prologue code. 336; Make sure we save the CSR used in the inline asm: r4. 337; CHECK: push {r4, lr} 338; 339; DISABLE-NEXT: cmp r0, #0 340; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 341; 342; SUM is in r0 because it is coalesced with the second 343; argument on the else path. 344; CHECK: movs [[SUM:r0]], #0 345; CHECK-NEXT: movs [[IV:r[0-9]+]], #10 346; 347; Next BB. 348; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body 349; CHECK: movs [[TMP:r[0-9]+]], #1 350; CHECK: adds [[SUM]], [[TMP]], [[SUM]] 351; CHECK-NEXT: subs [[IV]], [[IV]], #1 352; CHECK-NEXT: cmp [[IV]], #0 353; CHECK-NEXT: bne [[LOOP]] 354; 355; Next BB. 356; SUM << 3. 357; CHECK: lsls [[SUM]], [[SUM]], #3 358; ENABLE-V5T-NEXT: pop {r4, pc} 359; ENABLE-V4T-NEXT: pop {r4} 360; ENABLE-V4T-NEXT: pop {r1} 361; ENABLE-V4T-NEXT: bx r1 362; 363; Duplicated epilogue. 364; DISABLE-V5T: pop {r4, pc} 365; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]] 366; 367; CHECK: [[ELSE_LABEL]]: @ %if.else 368; Shift second argument by one and store into returned register. 369; CHECK: lsls r0, r1, #1 370; DISABLE-V5T-NEXT: pop {r4, pc} 371; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end 372; DISABLE-V4T-NEXT: pop {r4} 373; DISABLE-V4T-NEXT: pop {r1} 374; DISABLE-V4T-NEXT: bx r1 375; 376; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end 377; ENABLE-NEXT: bx lr 378define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 { 379entry: 380 %tobool = icmp eq i32 %cond, 0 381 br i1 %tobool, label %if.else, label %if.then 382 383if.then: ; preds = %entry 384 tail call void asm "nop", "~{r4}"() 385 br label %for.body 386 387for.body: ; preds = %for.body, %if.then 388 %i.05 = phi i32 [ 0, %if.then ], [ %inc, %for.body ] 389 %sum.04 = phi i32 [ 0, %if.then ], [ %add, %for.body ] 390 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"() 391 %add = add nsw i32 %call, %sum.04 392 %inc = add nuw nsw i32 %i.05, 1 393 %exitcond = icmp eq i32 %inc, 10 394 br i1 %exitcond, label %for.end, label %for.body 395 396for.end: ; preds = %for.body 397 %shl = shl i32 %add, 3 398 br label %if.end 399 400if.else: ; preds = %entry 401 %mul = shl nsw i32 %N, 1 402 br label %if.end 403 404if.end: ; preds = %if.else, %for.end 405 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ] 406 ret i32 %sum.1 407} 408 409; Check that we handle function with no frame information correctly. 410; CHECK-LABEL: emptyFrame: 411; CHECK: @ %entry 412; CHECK-NEXT: movs r0, #0 413; CHECK-NEXT: bx lr 414define i32 @emptyFrame() { 415entry: 416 ret i32 0 417} 418 419; Check that we handle inline asm correctly. 420; CHECK-LABEL: inlineAsm: 421; 422; ENABLE: cmp r0, #0 423; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 424; 425; Prologue code. 426; Make sure we save the CSR used in the inline asm: r4. 427; CHECK: push {r4, lr} 428; 429; DISABLE: cmp r0, #0 430; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 431; 432; CHECK: movs [[IV:r[0-9]+]], #10 433; 434; Next BB. 435; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body 436; CHECK: movs r4, #1 437; CHECK: subs [[IV]], [[IV]], #1 438; CHECK-NEXT: cmp [[IV]], #0 439; CHECK-NEXT: bne [[LOOP]] 440; 441; Next BB. 442; CHECK: movs r0, #0 443; ENABLE-V5T-NEXT: pop {r4, pc} 444; ENABLE-V4T-NEXT: pop {r4} 445; ENABLE-V4T-NEXT: pop {r1} 446; ENABLE-V4T-NEXT: bx r1 447; 448; Duplicated epilogue. 449; DISABLE-V5T-NEXT: pop {r4, pc} 450; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]] 451; 452; CHECK: [[ELSE_LABEL]]: @ %if.else 453; Shift second argument by one and store into returned register. 454; CHECK: lsls r0, r1, #1 455; DISABLE-V5T-NEXT: pop {r4, pc} 456; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end 457; DISABLE-V4T-NEXT: pop {r4} 458; DISABLE-V4T-NEXT: pop {r1} 459; DISABLE-V4T-NEXT: bx r1 460; 461; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end 462; ENABLE-NEXT: bx lr 463define i32 @inlineAsm(i32 %cond, i32 %N) { 464entry: 465 %tobool = icmp eq i32 %cond, 0 466 br i1 %tobool, label %if.else, label %for.preheader 467 468for.preheader: 469 tail call void asm "nop", ""() 470 br label %for.body 471 472for.body: ; preds = %entry, %for.body 473 %i.03 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ] 474 tail call void asm sideeffect "movs r4, #1", "~{r4}"() 475 %inc = add nuw nsw i32 %i.03, 1 476 %exitcond = icmp eq i32 %inc, 10 477 br i1 %exitcond, label %for.exit, label %for.body 478 479for.exit: 480 tail call void asm "nop", ""() 481 br label %if.end 482 483if.else: ; preds = %entry 484 %mul = shl nsw i32 %N, 1 485 br label %if.end 486 487if.end: ; preds = %for.body, %if.else 488 %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ] 489 ret i32 %sum.0 490} 491 492; Check that we handle calls to variadic functions correctly. 493; CHECK-LABEL: callVariadicFunc: 494; 495; ENABLE: cmp r0, #0 496; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 497; 498; Prologue code. 499; CHECK: push {[[TMP:r[0-9]+]], lr} 500; CHECK: sub sp, #16 501; 502; DISABLE: cmp r0, #0 503; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]] 504; 505; Setup of the varags. 506; CHECK: mov [[TMP_SP:r[0-9]+]], sp 507; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]]] 508; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #4] 509; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #8] 510; Thumb has quite a strange way for moving stuff 511; in around. Oh well, match the current sequence. 512; CHECK: push {r1} 513; CHECK-NEXT: pop {r0} 514; CHECK: push {r1} 515; CHECK-NEXT: pop {r2} 516; CHECK: push {r1} 517; CHECK-NEXT: pop {r3} 518; CHECK-NEXT: bl 519; CHECK-NEXT: lsls r0, r0, #3 520; 521; ENABLE-NEXT: add sp, #16 522; ENABLE-V5T-NEXT: pop {[[TMP]], pc} 523; ENABLE-V4T-NEXT: pop {[[TMP]]} 524; ENABLE-V4T-NEXT: pop {r1} 525; ENABLE-V4T-NEXT: bx r1 526; 527; Duplicated epilogue. 528; DISABLE-V5T-NEXT: add sp, #16 529; DISABLE-V5T-NEXT: pop {[[TMP]], pc} 530; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]] 531; 532; CHECK: [[ELSE_LABEL]]: @ %if.else 533; Shift second argument by one and store into returned register. 534; CHECK: lsls r0, r1, #1 535; 536; Epilogue code. 537; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end 538; ENABLE-NEXT: bx lr 539; 540; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end 541; DISABLE-NEXT: add sp, #16 542; DISABLE-V5T-NEXT: pop {[[TMP]], pc} 543; DISABLE-V4T-NEXT: pop {[[TMP]]} 544; DISABLE-V4T-NEXT: pop {r1} 545; DISABLE-V4T-NEXT: bx r1 546define i32 @callVariadicFunc(i32 %cond, i32 %N) { 547entry: 548 %tobool = icmp eq i32 %cond, 0 549 br i1 %tobool, label %if.else, label %if.then 550 551if.then: ; preds = %entry 552 %call = tail call i32 (i32, ...) @someVariadicFunc(i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N) 553 %shl = shl i32 %call, 3 554 br label %if.end 555 556if.else: ; preds = %entry 557 %mul = shl nsw i32 %N, 1 558 br label %if.end 559 560if.end: ; preds = %if.else, %if.then 561 %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ] 562 ret i32 %sum.0 563} 564 565declare i32 @someVariadicFunc(i32, ...) 566 567; Make sure we do not insert unreachable code after noreturn function. 568; Although this is not incorrect to insert such code, it is useless 569; and it hurts the binary size. 570; 571; CHECK-LABEL: noreturn: 572; DISABLE: push 573; 574; CHECK: movs [[TMP:r[0-9]+]], #255 575; CHECK-NEXT: tst r0, [[TMP]] 576; CHECK-NEXT: bne [[ABORT:LBB[0-9_]+]] 577; 578; CHECK: movs r0, #42 579; 580; ENABLE-NEXT: bx lr 581; 582; DISABLE-NEXT: pop 583;; 584; CHECK: [[ABORT]]: @ %if.abort 585; 586; ENABLE: push 587; 588; CHECK: bl 589; ENABLE-NOT: pop 590define i32 @noreturn(i8 signext %bad_thing) { 591entry: 592 %tobool = icmp eq i8 %bad_thing, 0 593 br i1 %tobool, label %if.end, label %if.abort 594 595if.abort: 596 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"() 597 tail call void @abort() #0 598 unreachable 599 600if.end: 601 ret i32 42 602} 603 604declare void @abort() #0 605 606define i32 @b_to_bx(i32 %value) { 607; CHECK-LABEL: b_to_bx: 608; DISABLE: push {r7, lr} 609; CHECK: cmp r1, #49 610; CHECK-NEXT: bgt [[ELSE_LABEL:LBB[0-9_]+]] 611; ENABLE: push {r7, lr} 612 613; CHECK: bl 614; DISABLE-V5-NEXT: pop {r7, pc} 615; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]] 616 617; ENABLE-V5-NEXT: pop {r7, pc} 618; ENABLE-V4-NEXT: pop {r7} 619; ENABLE-V4-NEXT: pop {r1} 620; ENABLE-V4-NEXT: bx r1 621 622; CHECK: [[ELSE_LABEL]]: @ %if.else 623; CHECK-NEXT: lsls r0, r1, #1 624; DISABLE-V5-NEXT: pop {r7, pc} 625; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end 626; DISABLE-V4T-NEXT: pop {r7} 627; DISABLE-V4T-NEXT: pop {r1} 628; DISABLE-V4T-NEXT: bx r1 629 630; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end 631; ENABLE-NEXT: bx lr 632 633entry: 634 %cmp = icmp slt i32 %value, 50 635 br i1 %cmp, label %if.then, label %if.else 636 637if.then: 638 %div = sdiv i32 5000, %value 639 br label %if.end 640 641if.else: 642 %mul = shl nsw i32 %value, 1 643 br label %if.end 644 645if.end: 646 %value.addr.0 = phi i32 [ %div, %if.then ], [ %mul, %if.else ] 647 ret i32 %value.addr.0 648} 649 650define i1 @beq_to_bx(i32* %y, i32 %head) { 651; CHECK-LABEL: beq_to_bx: 652; DISABLE: push {r4, lr} 653; CHECK: cmp r2, #0 654; CHECK-NEXT: beq [[EXIT_LABEL:LBB[0-9_]+]] 655; ENABLE: push {r4, lr} 656 657; CHECK: tst r3, r4 658; ENABLE-NEXT: pop {r4} 659; ENABLE-NEXT: pop {r3} 660; ENABLE-NEXT: mov lr, r3 661; CHECK-NEXT: beq [[EXIT_LABEL]] 662 663; CHECK: str r1, [r2] 664; CHECK-NEXT: movs r0, #0 665; CHECK-NEXT: [[EXIT_LABEL]]: @ %cleanup 666; ENABLE-NEXT: bx lr 667; DISABLE-V5-NEXT: pop {r4, pc} 668; DISABLE-V4T-NEXT: pop {r4} 669; DISABLE-V4T-NEXT: pop {r1} 670; DISABLE-V4T-NEXT: bx r1 671 672entry: 673 %cmp = icmp eq i32* %y, null 674 br i1 %cmp, label %cleanup, label %if.end 675 676if.end: 677 %z = load i32, i32* %y, align 4 678 %and = and i32 %z, 2 679 %cmp2 = icmp eq i32 %and, 0 680 br i1 %cmp2, label %cleanup, label %if.end4 681 682if.end4: 683 store i32 %head, i32* %y, align 4 684 br label %cleanup 685 686cleanup: 687 %retval.0 = phi i1 [ 0, %if.end4 ], [ 1, %entry ], [ 1, %if.end ] 688 ret i1 %retval.0 689} 690 691attributes #0 = { noreturn nounwind } 692