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 62 define 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 67 true: 68 store i32 %a, i32* %tmp, align 4 69 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) 70 br label %false 71 72 false: 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 99 define 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 104 true: 105 store i32 %a, i32* %tmp, align 4 106 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) 107 br label %false 108 109 false: 110 ret i32 42 111 } 112 113 ; Function Attrs: optsize 114 declare 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 164 define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) { 165 entry: 166 %tobool = icmp eq i32 %cond, 0 167 br i1 %tobool, label %if.else, label %for.preheader 168 169 for.preheader: 170 tail call void asm "nop", ""() 171 br label %for.body 172 173 for.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 182 for.end: ; preds = %for.body 183 %shl = shl i32 %add, 3 184 br label %if.end 185 186 if.else: ; preds = %entry 187 %mul = shl nsw i32 %N, 1 188 br label %if.end 189 190 if.end: ; preds = %if.else, %for.end 191 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ] 192 ret i32 %sum.1 193 } 194 195 declare 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 219 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) { 220 entry: 221 br label %for.preheader 222 223 for.preheader: 224 tail call void asm "nop", ""() 225 br label %for.body 226 227 for.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 236 for.exit: 237 tail call void asm "nop", ""() 238 br label %for.end 239 240 for.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 294 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) { 295 entry: 296 %tobool = icmp eq i32 %cond, 0 297 br i1 %tobool, label %if.else, label %for.preheader 298 299 for.preheader: 300 tail call void asm "nop", ""() 301 br label %for.body 302 303 for.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 312 for.end: ; preds = %for.body 313 tail call void asm "nop", "~{r4}"() 314 %shl = shl i32 %add, 3 315 br label %if.end 316 317 if.else: ; preds = %entry 318 %mul = shl nsw i32 %N, 1 319 br label %if.end 320 321 if.end: ; preds = %if.else, %for.end 322 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ] 323 ret i32 %sum.1 324 } 325 326 declare 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 378 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 { 379 entry: 380 %tobool = icmp eq i32 %cond, 0 381 br i1 %tobool, label %if.else, label %if.then 382 383 if.then: ; preds = %entry 384 tail call void asm "nop", "~{r4}"() 385 br label %for.body 386 387 for.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 396 for.end: ; preds = %for.body 397 %shl = shl i32 %add, 3 398 br label %if.end 399 400 if.else: ; preds = %entry 401 %mul = shl nsw i32 %N, 1 402 br label %if.end 403 404 if.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 414 define i32 @emptyFrame() { 415 entry: 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 463 define i32 @inlineAsm(i32 %cond, i32 %N) { 464 entry: 465 %tobool = icmp eq i32 %cond, 0 466 br i1 %tobool, label %if.else, label %for.preheader 467 468 for.preheader: 469 tail call void asm "nop", ""() 470 br label %for.body 471 472 for.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 479 for.exit: 480 tail call void asm "nop", ""() 481 br label %if.end 482 483 if.else: ; preds = %entry 484 %mul = shl nsw i32 %N, 1 485 br label %if.end 486 487 if.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 546 define i32 @callVariadicFunc(i32 %cond, i32 %N) { 547 entry: 548 %tobool = icmp eq i32 %cond, 0 549 br i1 %tobool, label %if.else, label %if.then 550 551 if.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 556 if.else: ; preds = %entry 557 %mul = shl nsw i32 %N, 1 558 br label %if.end 559 560 if.end: ; preds = %if.else, %if.then 561 %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ] 562 ret i32 %sum.0 563 } 564 565 declare 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 590 define i32 @noreturn(i8 signext %bad_thing) { 591 entry: 592 %tobool = icmp eq i8 %bad_thing, 0 593 br i1 %tobool, label %if.end, label %if.abort 594 595 if.abort: 596 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"() 597 tail call void @abort() #0 598 unreachable 599 600 if.end: 601 ret i32 42 602 } 603 604 declare void @abort() #0 605 606 define 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 633 entry: 634 %cmp = icmp slt i32 %value, 50 635 br i1 %cmp, label %if.then, label %if.else 636 637 if.then: 638 %div = sdiv i32 5000, %value 639 br label %if.end 640 641 if.else: 642 %mul = shl nsw i32 %value, 1 643 br label %if.end 644 645 if.end: 646 %value.addr.0 = phi i32 [ %div, %if.then ], [ %mul, %if.else ] 647 ret i32 %value.addr.0 648 } 649 650 define 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 672 entry: 673 %cmp = icmp eq i32* %y, null 674 br i1 %cmp, label %cleanup, label %if.end 675 676 if.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 682 if.end4: 683 store i32 %head, i32* %y, align 4 684 br label %cleanup 685 686 cleanup: 687 %retval.0 = phi i1 [ 0, %if.end4 ], [ 1, %entry ], [ 1, %if.end ] 688 ret i1 %retval.0 689 } 690 691 attributes #0 = { noreturn nounwind } 692