1 # RUN: llc -run-pass x86-flags-copy-lowering -verify-machineinstrs -o - %s | FileCheck %s
3 # Lower various interesting copy patterns of EFLAGS without using LAHF/SAHF.
6 target triple = "x86_64-unknown-unknown"
10 define i32 @test_branch(i64 %a, i64 %b) {
16 define i32 @test_branch_fallthrough(i64 %a, i64 %b) {
22 define void @test_setcc(i64 %a, i64 %b) {
28 define void @test_cmov(i64 %a, i64 %b) {
34 define void @test_adc(i64 %a, i64 %b) {
40 define void @test_sbb(i64 %a, i64 %b) {
46 define void @test_adcx(i64 %a, i64 %b) {
52 define void @test_adox(i64 %a, i64 %b) {
58 define void @test_rcl(i64 %a, i64 %b) {
64 define void @test_rcr(i64 %a, i64 %b) {
70 define void @test_setb_c(i64 %a, i64 %b) {
76 define i64 @test_branch_with_livein_and_kill(i64 %a, i64 %b) {
82 define i64 @test_branch_with_interleaved_livein_and_kill(i64 %a, i64 %b) {
88 define i64 @test_mid_cycle_copies(i64 %a, i64 %b) {
94 define i32 @test_existing_setcc(i64 %a, i64 %b) {
100 define i32 @test_existing_setcc_memory(i64 %a, i64 %b) {
108 # CHECK-LABEL: name: test_branch
110 - { reg: '$rdi', virtual-reg: '%0' }
111 - { reg: '$rsi', virtual-reg: '%1' }
114 successors: %bb.1, %bb.2, %bb.3
119 CMP64rr %0, %1, implicit-def $eflags
120 %2:gr64 = COPY $eflags
121 ; CHECK-NOT: COPY{{( killed)?}} $eflags
122 ; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
123 ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
124 ; CHECK-NOT: COPY{{( killed)?}} $eflags
126 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
127 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
128 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
131 JCC_1 %bb.1, 7, implicit $eflags
132 JCC_1 %bb.2, 2, implicit $eflags
134 ; CHECK-NOT: $eflags =
136 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
137 ; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
138 ; CHECK-SAME: {{$[[:space:]]}}
140 ; CHECK-NEXT: successors: {{.*$}}
141 ; CHECK-SAME: {{$[[:space:]]}}
142 ; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
143 ; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
144 ; CHECK-NEXT: JMP_1 %bb.3
157 %5:gr32 = MOV32r0 implicit-def dead $eflags
163 name: test_branch_fallthrough
164 # CHECK-LABEL: name: test_branch_fallthrough
166 - { reg: '$rdi', virtual-reg: '%0' }
167 - { reg: '$rsi', virtual-reg: '%1' }
170 successors: %bb.1, %bb.2, %bb.3
175 CMP64rr %0, %1, implicit-def $eflags
176 %2:gr64 = COPY $eflags
177 ; CHECK-NOT: COPY{{( killed)?}} $eflags
178 ; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
179 ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
180 ; CHECK-NOT: COPY{{( killed)?}} $eflags
182 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
183 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
184 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
187 JCC_1 %bb.2, 7, implicit $eflags
188 JCC_1 %bb.3, 2, implicit $eflags
189 ; CHECK-NOT: $eflags =
191 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
192 ; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
193 ; CHECK-SAME: {{$[[:space:]]}}
195 ; CHECK-NEXT: successors: {{.*$}}
196 ; CHECK-SAME: {{$[[:space:]]}}
197 ; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
198 ; CHECK-NEXT: JCC_1 %bb.3, 5, implicit killed $eflags
199 ; CHECK-SAME: {{$[[:space:]]}}
203 %5:gr32 = MOV32r0 implicit-def dead $eflags
220 # CHECK-LABEL: name: test_setcc
222 - { reg: '$rdi', virtual-reg: '%0' }
223 - { reg: '$rsi', virtual-reg: '%1' }
230 CMP64rr %0, %1, implicit-def $eflags
231 %2:gr64 = COPY $eflags
232 ; CHECK-NOT: COPY{{( killed)?}} $eflags
233 ; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
234 ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
235 ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
236 ; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETCCr 5, implicit $eflags
237 ; CHECK-NOT: COPY{{( killed)?}} $eflags
239 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
240 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
241 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
244 %3:gr8 = SETCCr 7, implicit $eflags
245 %4:gr8 = SETCCr 2, implicit $eflags
246 %5:gr8 = SETCCr 4, implicit $eflags
247 SETCCm $rsp, 1, $noreg, -16, $noreg, 5, implicit killed $eflags
248 MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %3
249 MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %4
250 MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %5
251 ; CHECK-NOT: $eflags =
252 ; CHECK-NOT: = SET{{.*}}
253 ; CHECK: MOV8mr {{.*}}, killed %[[A_REG]]
254 ; CHECK-NEXT: MOV8mr {{.*}}, killed %[[B_REG]]
255 ; CHECK-NEXT: MOV8mr {{.*}}, killed %[[E_REG]]
256 ; CHECK-NOT: MOV8mr {{.*}}, killed %[[NE_REG]]
263 # CHECK-LABEL: name: test_cmov
265 - { reg: '$rdi', virtual-reg: '%0' }
266 - { reg: '$rsi', virtual-reg: '%1' }
273 CMP64rr %0, %1, implicit-def $eflags
274 %2:gr64 = COPY $eflags
275 ; CHECK-NOT: COPY{{( killed)?}} $eflags
276 ; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
277 ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
278 ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
279 ; CHECK-NOT: COPY{{( killed)?}} $eflags
281 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
282 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
283 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
286 %3:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
287 %4:gr64 = CMOV64rr %0, %1, 2, implicit $eflags
288 %5:gr64 = CMOV64rr %0, %1, 4, implicit $eflags
289 %6:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
290 ; CHECK-NOT: $eflags =
291 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
292 ; CHECK-NEXT: %3:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
293 ; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
294 ; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
295 ; CHECK-NEXT: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
296 ; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
297 ; CHECK-NEXT: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
298 ; CHECK-NEXT: %6:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
299 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %3
300 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
301 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
302 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %6
309 # CHECK-LABEL: name: test_adc
311 - { reg: '$rdi', virtual-reg: '%0' }
312 - { reg: '$rsi', virtual-reg: '%1' }
319 %2:gr64 = ADD64rr %0, %1, implicit-def $eflags
320 %3:gr64 = COPY $eflags
321 ; CHECK-NOT: COPY{{( killed)?}} $eflags
322 ; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
323 ; CHECK-NOT: COPY{{( killed)?}} $eflags
325 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
326 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
327 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
330 %4:gr64 = ADC64ri32 %2:gr64, 42, implicit-def $eflags, implicit $eflags
331 %5:gr64 = ADC64ri32 %4:gr64, 42, implicit-def $eflags, implicit $eflags
332 ; CHECK-NOT: $eflags =
333 ; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
334 ; CHECK-NEXT: %4:gr64 = ADC64ri32 %2, 42, implicit-def $eflags, implicit killed $eflags
335 ; CHECK-NEXT: %5:gr64 = ADC64ri32 %4, 42, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
336 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
343 # CHECK-LABEL: name: test_sbb
345 - { reg: '$rdi', virtual-reg: '%0' }
346 - { reg: '$rsi', virtual-reg: '%1' }
353 %2:gr64 = SUB64rr %0, %1, implicit-def $eflags
354 %3:gr64 = COPY killed $eflags
355 ; CHECK-NOT: COPY{{( killed)?}} $eflags
356 ; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
357 ; CHECK-NOT: COPY{{( killed)?}} $eflags
359 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
360 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
361 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
364 %4:gr64 = SBB64ri32 %2:gr64, 42, implicit-def $eflags, implicit killed $eflags
365 %5:gr64 = SBB64ri32 %4:gr64, 42, implicit-def dead $eflags, implicit killed $eflags
366 ; CHECK-NOT: $eflags =
367 ; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
368 ; CHECK-NEXT: %4:gr64 = SBB64ri32 %2, 42, implicit-def $eflags, implicit killed $eflags
369 ; CHECK-NEXT: %5:gr64 = SBB64ri32 %4, 42, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
370 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
377 # CHECK-LABEL: name: test_adcx
379 - { reg: '$rdi', virtual-reg: '%0' }
380 - { reg: '$rsi', virtual-reg: '%1' }
387 %2:gr64 = ADD64rr %0, %1, implicit-def $eflags
388 %3:gr64 = COPY $eflags
389 ; CHECK-NOT: COPY{{( killed)?}} $eflags
390 ; CHECK: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
391 ; CHECK-NEXT: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
392 ; CHECK-NOT: COPY{{( killed)?}} $eflags
394 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
395 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
396 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
399 %4:gr64 = CMOV64rr %0, %1, 4, implicit $eflags
400 %5:gr64 = MOV64ri32 42
401 %6:gr64 = ADCX64rr %2, %5, implicit-def $eflags, implicit $eflags
402 ; CHECK-NOT: $eflags =
403 ; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
404 ; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
405 ; CHECK-NEXT: %5:gr64 = MOV64ri32 42
406 ; CHECK-NEXT: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
407 ; CHECK-NEXT: %6:gr64 = ADCX64rr %2, %5, implicit-def{{( dead)?}} $eflags, implicit killed $eflags
408 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
409 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %6
416 # CHECK-LABEL: name: test_adox
418 - { reg: '$rdi', virtual-reg: '%0' }
419 - { reg: '$rsi', virtual-reg: '%1' }
426 %2:gr64 = ADD64rr %0, %1, implicit-def $eflags
427 %3:gr64 = COPY $eflags
428 ; CHECK-NOT: COPY{{( killed)?}} $eflags
429 ; CHECK: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
430 ; CHECK-NEXT: %[[OF_REG:[^:]*]]:gr8 = SETCCr 0, implicit $eflags
431 ; CHECK-NOT: COPY{{( killed)?}} $eflags
433 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
434 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
435 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
438 %4:gr64 = CMOV64rr %0, %1, 4, implicit $eflags
439 %5:gr64 = MOV64ri32 42
440 %6:gr64 = ADOX64rr %2, %5, implicit-def $eflags, implicit $eflags
441 ; CHECK-NOT: $eflags =
442 ; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
443 ; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
444 ; CHECK-NEXT: %5:gr64 = MOV64ri32 42
445 ; CHECK-NEXT: dead %{{[^:]*}}:gr8 = ADD8ri %[[OF_REG]], 127, implicit-def $eflags
446 ; CHECK-NEXT: %6:gr64 = ADOX64rr %2, %5, implicit-def{{( dead)?}} $eflags, implicit killed $eflags
447 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
448 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %6
455 # CHECK-LABEL: name: test_rcl
457 - { reg: '$rdi', virtual-reg: '%0' }
458 - { reg: '$rsi', virtual-reg: '%1' }
465 %2:gr64 = ADD64rr %0, %1, implicit-def $eflags
466 %3:gr64 = COPY $eflags
467 ; CHECK-NOT: COPY{{( killed)?}} $eflags
468 ; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
469 ; CHECK-NOT: COPY{{( killed)?}} $eflags
471 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
472 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
473 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
476 %4:gr64 = RCL64r1 %2:gr64, implicit-def $eflags, implicit $eflags
477 %5:gr64 = RCL64r1 %4:gr64, implicit-def $eflags, implicit $eflags
478 ; CHECK-NOT: $eflags =
479 ; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
480 ; CHECK-NEXT: %4:gr64 = RCL64r1 %2, implicit-def $eflags, implicit killed $eflags
481 ; CHECK-NEXT: %5:gr64 = RCL64r1 %4, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
482 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
489 # CHECK-LABEL: name: test_rcr
491 - { reg: '$rdi', virtual-reg: '%0' }
492 - { reg: '$rsi', virtual-reg: '%1' }
499 %2:gr64 = ADD64rr %0, %1, implicit-def $eflags
500 %3:gr64 = COPY $eflags
501 ; CHECK-NOT: COPY{{( killed)?}} $eflags
502 ; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
503 ; CHECK-NOT: COPY{{( killed)?}} $eflags
505 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
506 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
507 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
510 %4:gr64 = RCR64r1 %2:gr64, implicit-def $eflags, implicit $eflags
511 %5:gr64 = RCR64r1 %4:gr64, implicit-def $eflags, implicit $eflags
512 ; CHECK-NOT: $eflags =
513 ; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
514 ; CHECK-NEXT: %4:gr64 = RCR64r1 %2, implicit-def $eflags, implicit killed $eflags
515 ; CHECK-NEXT: %5:gr64 = RCR64r1 %4, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
516 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
523 # CHECK-LABEL: name: test_setb_c
525 - { reg: '$rdi', virtual-reg: '%0' }
526 - { reg: '$rsi', virtual-reg: '%1' }
533 %2:gr64 = ADD64rr %0, %1, implicit-def $eflags
534 %3:gr64 = COPY $eflags
535 ; CHECK-NOT: COPY{{( killed)?}} $eflags
536 ; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
537 ; CHECK-NOT: COPY{{( killed)?}} $eflags
539 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
540 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
541 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
544 %4:gr8 = SETB_C8r implicit-def $eflags, implicit $eflags
545 MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %4
546 ; CHECK-NOT: $eflags =
547 ; CHECK: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags
548 ; CHECK-NEXT: %[[ZERO_SUBREG:[^:]*]]:gr8 = COPY %[[ZERO]].sub_8bit
549 ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr8 = SUB8rr %[[ZERO_SUBREG]], %[[CF_REG]]
550 ; CHECK-NEXT: MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]]
553 %5:gr16 = SETB_C16r implicit-def $eflags, implicit $eflags
554 MOV16mr $rsp, 1, $noreg, -16, $noreg, killed %5
555 ; CHECK-NOT: $eflags =
556 ; CHECK: %[[CF_EXT:[^:]*]]:gr32 = MOVZX32rr8 %[[CF_REG]]
557 ; CHECK-NEXT: %[[CF_TRUNC:[^:]*]]:gr16 = COPY %[[CF_EXT]].sub_16bit
558 ; CHECK-NEXT: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags
559 ; CHECK-NEXT: %[[ZERO_SUBREG:[^:]*]]:gr16 = COPY %[[ZERO]].sub_16bit
560 ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr16 = SUB16rr %[[ZERO_SUBREG]], %[[CF_TRUNC]]
561 ; CHECK-NEXT: MOV16mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]]
564 %6:gr32 = SETB_C32r implicit-def $eflags, implicit $eflags
565 MOV32mr $rsp, 1, $noreg, -16, $noreg, killed %6
566 ; CHECK-NOT: $eflags =
567 ; CHECK: %[[CF_EXT:[^:]*]]:gr32 = MOVZX32rr8 %[[CF_REG]]
568 ; CHECK-NEXT: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags
569 ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr32 = SUB32rr %[[ZERO]], %[[CF_EXT]]
570 ; CHECK-NEXT: MOV32mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]]
573 %7:gr64 = SETB_C64r implicit-def $eflags, implicit $eflags
574 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %7
575 ; CHECK-NOT: $eflags =
576 ; CHECK: %[[CF_EXT1:[^:]*]]:gr32 = MOVZX32rr8 %[[CF_REG]]
577 ; CHECK-NEXT: %[[CF_EXT2:[^:]*]]:gr64 = SUBREG_TO_REG 0, %[[CF_EXT1]], %subreg.sub_32bit
578 ; CHECK-NEXT: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags
579 ; CHECK-NEXT: %[[ZERO_EXT:[^:]*]]:gr64 = SUBREG_TO_REG 0, %[[ZERO]], %subreg.sub_32bit
580 ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr64 = SUB64rr %[[ZERO_EXT]], %[[CF_EXT2]]
581 ; CHECK-NEXT: MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]]
587 name: test_branch_with_livein_and_kill
588 # CHECK-LABEL: name: test_branch_with_livein_and_kill
590 - { reg: '$rdi', virtual-reg: '%0' }
591 - { reg: '$rsi', virtual-reg: '%1' }
594 successors: %bb.1, %bb.2, %bb.3
599 CMP64rr %0, %1, implicit-def $eflags
600 %2:gr64 = COPY $eflags
601 ; CHECK-NOT: COPY{{( killed)?}} $eflags
602 ; CHECK: %[[S_REG:[^:]*]]:gr8 = SETCCr 8, implicit $eflags
603 ; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETCCr 5, implicit $eflags
604 ; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
605 ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
606 ; CHECK-NOT: COPY{{( killed)?}} $eflags
608 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
609 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
610 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
613 JCC_1 %bb.1, 7, implicit $eflags
614 JCC_1 %bb.2, 2, implicit $eflags
616 ; CHECK-NOT: $eflags =
618 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
619 ; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
620 ; CHECK-SAME: {{$[[:space:]]}}
622 ; CHECK-NEXT: successors: {{.*$}}
623 ; CHECK-SAME: {{$[[:space:]]}}
624 ; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
625 ; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
626 ; CHECK-NEXT: JMP_1 %bb.3
631 %3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
632 ; CHECK-NOT: $eflags =
633 ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
634 ; CHECK-NEXT: %3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
641 %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
642 ; CHECK-NOT: $eflags =
643 ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
644 ; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
651 %5:gr64 = CMOV64rr %0, %1, 8, implicit killed $eflags
652 ; CHECK-NOT: $eflags =
653 ; CHECK: TEST8rr %[[S_REG]], %[[S_REG]], implicit-def $eflags
654 ; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
660 name: test_branch_with_interleaved_livein_and_kill
661 # CHECK-LABEL: name: test_branch_with_interleaved_livein_and_kill
663 - { reg: '$rdi', virtual-reg: '%0' }
664 - { reg: '$rsi', virtual-reg: '%1' }
667 successors: %bb.1, %bb.2, %bb.5
672 CMP64rr %0, %1, implicit-def $eflags
673 %2:gr64 = COPY $eflags
674 ; CHECK-NOT: COPY{{( killed)?}} $eflags
675 ; CHECK: %[[S_REG:[^:]*]]:gr8 = SETCCr 8, implicit $eflags
676 ; CHECK-NEXT: %[[P_REG:[^:]*]]:gr8 = SETCCr 10, implicit $eflags
677 ; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETCCr 5, implicit $eflags
678 ; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
679 ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
680 ; CHECK-NEXT: %[[O_REG:[^:]*]]:gr8 = SETCCr 0, implicit $eflags
681 ; CHECK-NOT: COPY{{( killed)?}} $eflags
683 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
684 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
685 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
688 JCC_1 %bb.1, 7, implicit $eflags
689 JCC_1 %bb.2, 2, implicit $eflags
691 ; CHECK-NOT: $eflags =
693 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
694 ; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
695 ; CHECK-SAME: {{$[[:space:]]}}
697 ; CHECK-NEXT: successors: {{.*$}}
698 ; CHECK-SAME: {{$[[:space:]]}}
699 ; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
700 ; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
701 ; CHECK-NEXT: JMP_1 %bb.5
706 %3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
707 ; CHECK-NOT: $eflags =
708 ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
709 ; CHECK-NEXT: %3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
714 ; The goal is to have another batch of successors discovered in a block
715 ; between two successors which kill $eflags. This ensures that neither of
716 ; the surrounding kills impact recursing through this block.
717 successors: %bb.3, %bb.4
720 JCC_1 %bb.3, 0, implicit $eflags
722 ; CHECK-NOT: $eflags =
724 ; CHECK: TEST8rr %[[O_REG]], %[[O_REG]], implicit-def $eflags
725 ; CHECK-NEXT: JCC_1 %bb.3, 5, implicit killed $eflags
726 ; CHECK-NEXT: JMP_1 %bb.4
731 %4:gr64 = CMOV64rr %0, %1, 5, implicit $eflags
732 ; CHECK-NOT: $eflags =
733 ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
734 ; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
741 %5:gr64 = CMOV64rr %0, %1, 10, implicit $eflags
742 ; CHECK-NOT: $eflags =
743 ; CHECK: TEST8rr %[[P_REG]], %[[P_REG]], implicit-def $eflags
744 ; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
751 %6:gr64 = CMOV64rr %0, %1, 8, implicit killed $eflags
752 ; CHECK-NOT: $eflags =
753 ; CHECK: TEST8rr %[[S_REG]], %[[S_REG]], implicit-def $eflags
754 ; CHECK-NEXT: %6:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
760 # This test case is designed to exercise a particularly challenging situation:
761 # when the flags are copied and restored *inside* of a complex and cyclic CFG
762 # all of which have live-in flags. To correctly handle this case we have to walk
763 # up the dominator tree and locate a viable reaching definition location,
764 # checking for clobbers along any path. The CFG for this function looks like the
765 # following diagram, control flowing out the bottom of blocks and in the top:
768 # | __________________
781 # | ________/ \____/ |
784 # |\__________________/
788 # We set EFLAGS in bb.0, clobber them in bb.3, and copy them in bb.2 and bb.6.
789 # Because of the cycles this requires hoisting the `SETcc` instructions to
790 # capture the flags for the bb.6 copy to bb.1 and using them for the copy in
791 # `bb.2` as well despite the clobber in `bb.3`. The clobber in `bb.3` also
792 # prevents hoisting the `SETcc`s up to `bb.0`.
794 # Throughout the test we use branch instructions that are totally bogus (as the
795 # flags are obviously not changing!) but this is just to allow us to send
796 # a small but complex CFG structure through the backend and force it to choose
797 # plausible lowering decisions based on the core CFG presented, regardless of
798 # the futility of the actual branches.
799 name: test_mid_cycle_copies
800 # CHECK-LABEL: name: test_mid_cycle_copies
802 - { reg: '$rdi', virtual-reg: '%0' }
803 - { reg: '$rsi', virtual-reg: '%1' }
811 CMP64rr %0, %1, implicit-def $eflags
813 ; CHECK-NOT: COPY{{( killed)?}} $eflags
814 ; CHECK: CMP64rr %0, %1, implicit-def $eflags
815 ; CHECK-NOT: COPY{{( killed)?}} $eflags
819 successors: %bb.2, %bb.4
822 ; Outer loop header, target for one set of hoisting.
823 JCC_1 %bb.2, 4, implicit $eflags
826 ; CHECK-NOT: COPY{{( killed)?}} $eflags
827 ; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
828 ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
829 ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
830 ; CHECK-NOT: COPY{{( killed)?}} $eflags
833 successors: %bb.2, %bb.3
836 ; Inner loop with a local copy. We should eliminate this but can't hoist.
837 %2:gr64 = COPY $eflags
839 JCC_1 %bb.2, 4, implicit $eflags
842 ; CHECK-NOT: COPY{{( killed)?}} $eflags
843 ; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
844 ; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
845 ; CHECK-NOT: COPY{{( killed)?}} $eflags
851 ; Use and then clobber $eflags. Then hop to the outer loop latch.
852 %3:gr64 = ADC64ri32 %0, 42, implicit-def dead $eflags, implicit $eflags
854 ; CHECK-NOT: COPY{{( killed)?}} $eflags
855 ; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[B_REG]], 255, implicit-def $eflags
856 ; CHECK-NEXT: %3:gr64 = ADC64ri32 %0, 42, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
857 ; CHECK-NOT: COPY{{( killed)?}} $eflags
858 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %3
862 successors: %bb.5, %bb.6
865 ; Another inner loop, this one with a diamond.
866 JCC_1 %bb.5, 4, implicit $eflags
869 ; CHECK-NOT: COPY{{( killed)?}} $eflags
870 ; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
871 ; CHECK-NEXT: JCC_1 %bb.5, 5, implicit killed $eflags
872 ; CHECK-NOT: COPY{{( killed)?}} $eflags
878 ; Just use $eflags on this side of the diamond.
879 %4:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
881 ; CHECK-NOT: COPY{{( killed)?}} $eflags
882 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
883 ; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
884 ; CHECK-NOT: COPY{{( killed)?}} $eflags
885 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
892 ; Use, copy, and then use $eflags again.
893 %5:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
895 ; CHECK-NOT: COPY{{( killed)?}} $eflags
896 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
897 ; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
898 ; CHECK-NOT: COPY{{( killed)?}} $eflags
899 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
901 %6:gr64 = COPY $eflags
902 $eflags = COPY %6:gr64
904 %7:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
905 ; CHECK-NOT: COPY{{( killed)?}} $eflags
906 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
907 ; CHECK-NEXT: %7:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
908 ; CHECK-NOT: COPY{{( killed)?}} $eflags
909 MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %7
913 successors: %bb.4, %bb.8
917 JCC_1 %bb.4, 4, implicit $eflags
920 ; CHECK-NOT: COPY{{( killed)?}} $eflags
921 ; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
922 ; CHECK-NEXT: JCC_1 %bb.4, 5, implicit killed $eflags
923 ; CHECK-NOT: COPY{{( killed)?}} $eflags
926 successors: %bb.1, %bb.9
928 ; Outer loop latch. Note that we cannot have EFLAGS live-in here as that
929 ; immediately require PHIs.
930 CMP64rr %0, %1, implicit-def $eflags
931 JCC_1 %bb.1, 4, implicit $eflags
934 ; CHECK-NOT: COPY{{( killed)?}} $eflags
935 ; CHECK: CMP64rr %0, %1, implicit-def $eflags
936 ; CHECK-NEXT: JCC_1 %bb.1, 4, implicit $eflags
937 ; CHECK-NOT: COPY{{( killed)?}} $eflags
943 %8:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
948 ; CHECK: %8:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
952 name: test_existing_setcc
953 # CHECK-LABEL: name: test_existing_setcc
955 - { reg: '$rdi', virtual-reg: '%0' }
956 - { reg: '$rsi', virtual-reg: '%1' }
959 successors: %bb.1, %bb.2, %bb.3
964 CMP64rr %0, %1, implicit-def $eflags
965 %2:gr8 = SETCCr 7, implicit $eflags
966 %3:gr8 = SETCCr 3, implicit $eflags
967 %4:gr64 = COPY $eflags
968 ; CHECK: CMP64rr %0, %1, implicit-def $eflags
969 ; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
970 ; CHECK-NEXT: %[[AE_REG:[^:]*]]:gr8 = SETCCr 3, implicit $eflags
971 ; CHECK-NOT: COPY{{( killed)?}} $eflags
973 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
974 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
975 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
978 JCC_1 %bb.1, 7, implicit $eflags
979 JCC_1 %bb.2, 2, implicit $eflags
981 ; CHECK-NOT: $eflags =
983 ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
984 ; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
985 ; CHECK-SAME: {{$[[:space:]]}}
987 ; CHECK-NEXT: successors: {{.*$}}
988 ; CHECK-SAME: {{$[[:space:]]}}
989 ; CHECK-NEXT: TEST8rr %[[AE_REG]], %[[AE_REG]], implicit-def $eflags
990 ; CHECK-NEXT: JCC_1 %bb.2, 4, implicit killed $eflags
991 ; CHECK-NEXT: JMP_1 %bb.3
1004 %7:gr32 = MOV32r0 implicit-def dead $eflags
1010 name: test_existing_setcc_memory
1011 # CHECK-LABEL: name: test_existing_setcc_memory
1013 - { reg: '$rdi', virtual-reg: '%0' }
1014 - { reg: '$rsi', virtual-reg: '%1' }
1017 successors: %bb.1, %bb.2
1022 CMP64rr %0, %1, implicit-def $eflags
1023 SETCCm %0, 1, $noreg, -16, $noreg, 4, implicit $eflags
1024 %2:gr64 = COPY $eflags
1025 ; CHECK: CMP64rr %0, %1, implicit-def $eflags
1026 ; We cannot reuse this SETE because it stores the flag directly to memory,
1027 ; so we have two SETEs here. FIXME: It'd be great if something could fold
1028 ; these automatically. If not, maybe we want to unfold SETcc instructions
1029 ; writing to memory so we can reuse them.
1030 ; CHECK-NEXT: SETCCm {{.*}} 4, implicit $eflags
1031 ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
1032 ; CHECK-NOT: COPY{{( killed)?}} $eflags
1034 ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
1035 CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
1036 ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
1039 JCC_1 %bb.1, 4, implicit $eflags
1041 ; CHECK-NOT: $eflags =
1043 ; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
1044 ; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
1045 ; CHECK-NEXT: JMP_1 %bb.2
1048 %3:gr32 = MOV32ri 42
1053 %4:gr32 = MOV32ri 43