This time with the right bug number. When we rewrite the setcc we replace set old setcc output register with the new CondReg. But since CondReg can be shared by other replacements, we don't know if the kill flags for the old register are valid for CondReg. So be conservative and remove them. The test case has a SETCCr and a SETCCm on the same condition so they end up sharing the same CondReg. The SETCCr had one use with a kill flag. This kill flag isn't valid after the replacement because CondReg needs a live range extending to the later SETCCm replacment. Fixes PR51903.
1034 lines
36 KiB
YAML
1034 lines
36 KiB
YAML
# RUN: llc -run-pass x86-flags-copy-lowering -verify-machineinstrs -o - %s | FileCheck %s
|
|
#
|
|
# Lower various interesting copy patterns of EFLAGS without using LAHF/SAHF.
|
|
|
|
--- |
|
|
target triple = "x86_64-unknown-unknown"
|
|
|
|
declare void @foo()
|
|
|
|
define i32 @test_branch(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @test_branch_fallthrough(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret i32 0
|
|
}
|
|
|
|
define void @test_setcc(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_cmov(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_adc(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_sbb(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_adcx(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_adox(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_rcl(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_rcr(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @test_setb_c(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define i64 @test_branch_with_livein_and_kill(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret i64 0
|
|
}
|
|
|
|
define i64 @test_branch_with_interleaved_livein_and_kill(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret i64 0
|
|
}
|
|
|
|
define i64 @test_mid_cycle_copies(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret i64 0
|
|
}
|
|
|
|
define i32 @test_existing_setcc(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @test_existing_setcc_memory(i64 %a, i64 %b) {
|
|
entry:
|
|
call void @foo()
|
|
ret i32 0
|
|
}
|
|
...
|
|
---
|
|
name: test_branch
|
|
# CHECK-LABEL: name: test_branch
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1, %bb.2, %bb.3
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
%2:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %2
|
|
JCC_1 %bb.1, 7, implicit $eflags
|
|
JCC_1 %bb.2, 2, implicit $eflags
|
|
JMP_1 %bb.3
|
|
; CHECK-NOT: $eflags =
|
|
;
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: bb.4:
|
|
; CHECK-NEXT: successors: {{.*$}}
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
|
|
; CHECK-NEXT: JMP_1 %bb.3
|
|
|
|
bb.1:
|
|
%3:gr32 = MOV32ri 42
|
|
$eax = COPY %3
|
|
RET 0, $eax
|
|
|
|
bb.2:
|
|
%4:gr32 = MOV32ri 43
|
|
$eax = COPY %4
|
|
RET 0, $eax
|
|
|
|
bb.3:
|
|
%5:gr32 = MOV32r0 implicit-def dead $eflags
|
|
$eax = COPY %5
|
|
RET 0, $eax
|
|
|
|
...
|
|
---
|
|
name: test_branch_fallthrough
|
|
# CHECK-LABEL: name: test_branch_fallthrough
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1, %bb.2, %bb.3
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
%2:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %2
|
|
JCC_1 %bb.2, 7, implicit $eflags
|
|
JCC_1 %bb.3, 2, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
;
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: bb.4:
|
|
; CHECK-NEXT: successors: {{.*$}}
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.3, 5, implicit killed $eflags
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: bb.1:
|
|
|
|
bb.1:
|
|
%5:gr32 = MOV32r0 implicit-def dead $eflags
|
|
$eax = COPY %5
|
|
RET 0, $eax
|
|
|
|
bb.2:
|
|
%3:gr32 = MOV32ri 42
|
|
$eax = COPY %3
|
|
RET 0, $eax
|
|
|
|
bb.3:
|
|
%4:gr32 = MOV32ri 43
|
|
$eax = COPY %4
|
|
RET 0, $eax
|
|
|
|
...
|
|
---
|
|
name: test_setcc
|
|
# CHECK-LABEL: name: test_setcc
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
%2:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
|
|
; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETCCr 5, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %2
|
|
%3:gr8 = SETCCr 7, implicit $eflags
|
|
%4:gr8 = SETCCr 2, implicit $eflags
|
|
%5:gr8 = SETCCr 4, implicit $eflags
|
|
SETCCm $rsp, 1, $noreg, -16, $noreg, 5, implicit killed $eflags
|
|
MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %3
|
|
MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %4
|
|
MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK-NOT: = SET{{.*}}
|
|
; CHECK: MOV8mr {{.*}}, %[[A_REG]]
|
|
; CHECK-NEXT: MOV8mr {{.*}}, %[[B_REG]]
|
|
; CHECK-NEXT: MOV8mr {{.*}}, %[[E_REG]]
|
|
; CHECK-NOT: MOV8mr {{.*}}, %[[NE_REG]]
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_cmov
|
|
# CHECK-LABEL: name: test_cmov
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
%2:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %2
|
|
%3:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
|
|
%4:gr64 = CMOV64rr %0, %1, 2, implicit $eflags
|
|
%5:gr64 = CMOV64rr %0, %1, 4, implicit $eflags
|
|
%6:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %3:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NEXT: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NEXT: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %6:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %3
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %6
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_adc
|
|
# CHECK-LABEL: name: test_adc
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
%2:gr64 = ADD64rr %0, %1, implicit-def $eflags
|
|
%3:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %3
|
|
%4:gr64 = ADC64ri32 %2:gr64, 42, implicit-def $eflags, implicit $eflags
|
|
%5:gr64 = ADC64ri32 %4:gr64, 42, implicit-def $eflags, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = ADC64ri32 %2, 42, implicit-def $eflags, implicit killed $eflags
|
|
; CHECK-NEXT: %5:gr64 = ADC64ri32 %4, 42, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_sbb
|
|
# CHECK-LABEL: name: test_sbb
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
%2:gr64 = SUB64rr %0, %1, implicit-def $eflags
|
|
%3:gr64 = COPY killed $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %3
|
|
%4:gr64 = SBB64ri32 %2:gr64, 42, implicit-def $eflags, implicit killed $eflags
|
|
%5:gr64 = SBB64ri32 %4:gr64, 42, implicit-def dead $eflags, implicit killed $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = SBB64ri32 %2, 42, implicit-def $eflags, implicit killed $eflags
|
|
; CHECK-NEXT: %5:gr64 = SBB64ri32 %4, 42, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_adcx
|
|
# CHECK-LABEL: name: test_adcx
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
%2:gr64 = ADD64rr %0, %1, implicit-def $eflags
|
|
%3:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
|
|
; CHECK-NEXT: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %3
|
|
%4:gr64 = CMOV64rr %0, %1, 4, implicit $eflags
|
|
%5:gr64 = MOV64ri32 42
|
|
%6:gr64 = ADCX64rr %2, %5, implicit-def $eflags, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NEXT: %5:gr64 = MOV64ri32 42
|
|
; CHECK-NEXT: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %6:gr64 = ADCX64rr %2, %5, implicit-def{{( dead)?}} $eflags, implicit killed $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %6
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_adox
|
|
# CHECK-LABEL: name: test_adox
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
%2:gr64 = ADD64rr %0, %1, implicit-def $eflags
|
|
%3:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
|
|
; CHECK-NEXT: %[[OF_REG:[^:]*]]:gr8 = SETCCr 0, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %3
|
|
%4:gr64 = CMOV64rr %0, %1, 4, implicit $eflags
|
|
%5:gr64 = MOV64ri32 42
|
|
%6:gr64 = ADOX64rr %2, %5, implicit-def $eflags, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NEXT: %5:gr64 = MOV64ri32 42
|
|
; CHECK-NEXT: dead %{{[^:]*}}:gr8 = ADD8ri %[[OF_REG]], 127, implicit-def $eflags
|
|
; CHECK-NEXT: %6:gr64 = ADOX64rr %2, %5, implicit-def{{( dead)?}} $eflags, implicit killed $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %6
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_rcl
|
|
# CHECK-LABEL: name: test_rcl
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
%2:gr64 = ADD64rr %0, %1, implicit-def $eflags
|
|
%3:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %3
|
|
%4:gr64 = RCL64r1 %2:gr64, implicit-def $eflags, implicit $eflags
|
|
%5:gr64 = RCL64r1 %4:gr64, implicit-def $eflags, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = RCL64r1 %2, implicit-def $eflags, implicit killed $eflags
|
|
; CHECK-NEXT: %5:gr64 = RCL64r1 %4, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_rcr
|
|
# CHECK-LABEL: name: test_rcr
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
%2:gr64 = ADD64rr %0, %1, implicit-def $eflags
|
|
%3:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %3
|
|
%4:gr64 = RCR64r1 %2:gr64, implicit-def $eflags, implicit $eflags
|
|
%5:gr64 = RCR64r1 %4:gr64, implicit-def $eflags, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = RCR64r1 %2, implicit-def $eflags, implicit killed $eflags
|
|
; CHECK-NEXT: %5:gr64 = RCR64r1 %4, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_setb_c
|
|
# CHECK-LABEL: name: test_setb_c
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
%2:gr64 = ADD64rr %0, %1, implicit-def $eflags
|
|
%3:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[CF_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %3
|
|
%4:gr32 = SETB_C32r implicit-def $eflags, implicit $eflags
|
|
MOV32mr $rsp, 1, $noreg, -16, $noreg, killed %4
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %[[SETB:[^:]*]]:gr32 = SETB_C32r implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
|
|
; CHECK-NEXT: MOV32mr $rsp, 1, $noreg, -16, $noreg, killed %[[SETB]]
|
|
|
|
$eflags = COPY %3
|
|
%5:gr64 = SETB_C64r implicit-def $eflags, implicit $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[CF_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %[[SETB:[^:]*]]:gr64 = SETB_C64r implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
|
|
; CHECK-NEXT: MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %[[SETB]]
|
|
|
|
RET 0
|
|
|
|
...
|
|
---
|
|
name: test_branch_with_livein_and_kill
|
|
# CHECK-LABEL: name: test_branch_with_livein_and_kill
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1, %bb.2, %bb.3
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
%2:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[S_REG:[^:]*]]:gr8 = SETCCr 8, implicit $eflags
|
|
; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETCCr 5, implicit $eflags
|
|
; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %2
|
|
JCC_1 %bb.1, 7, implicit $eflags
|
|
JCC_1 %bb.2, 2, implicit $eflags
|
|
JMP_1 %bb.3
|
|
; CHECK-NOT: $eflags =
|
|
;
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: bb.4:
|
|
; CHECK-NEXT: successors: {{.*$}}
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
|
|
; CHECK-NEXT: JMP_1 %bb.3
|
|
|
|
bb.1:
|
|
liveins: $eflags
|
|
|
|
%3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
|
|
$rax = COPY %3
|
|
RET 0, $rax
|
|
|
|
bb.2:
|
|
liveins: $eflags
|
|
|
|
%4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
$rax = COPY %4
|
|
RET 0, $rax
|
|
|
|
bb.3:
|
|
liveins: $eflags
|
|
|
|
%5:gr64 = CMOV64rr %0, %1, 8, implicit killed $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[S_REG]], %[[S_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
$rax = COPY %5
|
|
RET 0, $rax
|
|
|
|
...
|
|
---
|
|
name: test_branch_with_interleaved_livein_and_kill
|
|
# CHECK-LABEL: name: test_branch_with_interleaved_livein_and_kill
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1, %bb.2, %bb.5
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
%2:gr64 = COPY $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[S_REG:[^:]*]]:gr8 = SETCCr 8, implicit $eflags
|
|
; CHECK-NEXT: %[[P_REG:[^:]*]]:gr8 = SETCCr 10, implicit $eflags
|
|
; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETCCr 5, implicit $eflags
|
|
; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NEXT: %[[O_REG:[^:]*]]:gr8 = SETCCr 0, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %2
|
|
JCC_1 %bb.1, 7, implicit $eflags
|
|
JCC_1 %bb.2, 2, implicit $eflags
|
|
JMP_1 %bb.5
|
|
; CHECK-NOT: $eflags =
|
|
;
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: bb.6:
|
|
; CHECK-NEXT: successors: {{.*$}}
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
|
|
; CHECK-NEXT: JMP_1 %bb.5
|
|
|
|
bb.1:
|
|
liveins: $eflags
|
|
|
|
%3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %3:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
|
|
$rax = COPY %3
|
|
RET 0, $rax
|
|
|
|
bb.2:
|
|
; The goal is to have another batch of successors discovered in a block
|
|
; between two successors which kill $eflags. This ensures that neither of
|
|
; the surrounding kills impact recursing through this block.
|
|
successors: %bb.3, %bb.4
|
|
liveins: $eflags
|
|
|
|
JCC_1 %bb.3, 0, implicit $eflags
|
|
JMP_1 %bb.4
|
|
; CHECK-NOT: $eflags =
|
|
;
|
|
; CHECK: TEST8rr %[[O_REG]], %[[O_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.3, 5, implicit killed $eflags
|
|
; CHECK-NEXT: JMP_1 %bb.4
|
|
|
|
bb.3:
|
|
liveins: $eflags
|
|
|
|
%4:gr64 = CMOV64rr %0, %1, 5, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
$rax = COPY %4
|
|
RET 0, $rax
|
|
|
|
bb.4:
|
|
liveins: $eflags
|
|
|
|
%5:gr64 = CMOV64rr %0, %1, 10, implicit $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[P_REG]], %[[P_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
$rax = COPY %5
|
|
RET 0, $rax
|
|
|
|
bb.5:
|
|
liveins: $eflags
|
|
|
|
%6:gr64 = CMOV64rr %0, %1, 8, implicit killed $eflags
|
|
; CHECK-NOT: $eflags =
|
|
; CHECK: TEST8rr %[[S_REG]], %[[S_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %6:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
$rax = COPY %6
|
|
RET 0, $rax
|
|
|
|
...
|
|
---
|
|
# This test case is designed to exercise a particularly challenging situation:
|
|
# when the flags are copied and restored *inside* of a complex and cyclic CFG
|
|
# all of which have live-in flags. To correctly handle this case we have to walk
|
|
# up the dominator tree and locate a viable reaching definition location,
|
|
# checking for clobbers along any path. The CFG for this function looks like the
|
|
# following diagram, control flowing out the bottom of blocks and in the top:
|
|
#
|
|
# bb.0
|
|
# | __________________
|
|
# |/ \
|
|
# bb.1 |
|
|
# |\_________ |
|
|
# | __ \ ____ |
|
|
# |/ \ |/ \ |
|
|
# bb.2 | bb.4 | |
|
|
# |\__/ / \ | |
|
|
# | / \ | |
|
|
# bb.3 bb.5 bb.6 | |
|
|
# | \ / | |
|
|
# | \ / | |
|
|
# | bb.7 | |
|
|
# | ________/ \____/ |
|
|
# |/ |
|
|
# bb.8 |
|
|
# |\__________________/
|
|
# |
|
|
# bb.9
|
|
#
|
|
# We set EFLAGS in bb.0, clobber them in bb.3, and copy them in bb.2 and bb.6.
|
|
# Because of the cycles this requires hoisting the `SETcc` instructions to
|
|
# capture the flags for the bb.6 copy to bb.1 and using them for the copy in
|
|
# `bb.2` as well despite the clobber in `bb.3`. The clobber in `bb.3` also
|
|
# prevents hoisting the `SETcc`s up to `bb.0`.
|
|
#
|
|
# Throughout the test we use branch instructions that are totally bogus (as the
|
|
# flags are obviously not changing!) but this is just to allow us to send
|
|
# a small but complex CFG structure through the backend and force it to choose
|
|
# plausible lowering decisions based on the core CFG presented, regardless of
|
|
# the futility of the actual branches.
|
|
name: test_mid_cycle_copies
|
|
# CHECK-LABEL: name: test_mid_cycle_copies
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
; CHECK: bb.0:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: CMP64rr %0, %1, implicit-def $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
JMP_1 %bb.1
|
|
|
|
bb.1:
|
|
successors: %bb.2, %bb.4
|
|
liveins: $eflags
|
|
|
|
; Outer loop header, target for one set of hoisting.
|
|
JCC_1 %bb.2, 4, implicit $eflags
|
|
JMP_1 %bb.4
|
|
; CHECK: bb.1:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
|
|
; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETCCr 2, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
bb.2:
|
|
successors: %bb.2, %bb.3
|
|
liveins: $eflags
|
|
|
|
; Inner loop with a local copy. We should eliminate this but can't hoist.
|
|
%2:gr64 = COPY $eflags
|
|
$eflags = COPY %2
|
|
JCC_1 %bb.2, 4, implicit $eflags
|
|
JMP_1 %bb.3
|
|
; CHECK: bb.2:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.2, 5, implicit killed $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
bb.3:
|
|
successors: %bb.8
|
|
liveins: $eflags
|
|
|
|
; Use and then clobber $eflags. Then hop to the outer loop latch.
|
|
%3:gr64 = ADC64ri32 %0, 42, implicit-def dead $eflags, implicit $eflags
|
|
; CHECK: bb.3:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: dead %{{[^:]*}}:gr8 = ADD8ri %[[B_REG]], 255, implicit-def $eflags
|
|
; CHECK-NEXT: %3:gr64 = ADC64ri32 %0, 42, implicit-def{{( dead)?}} $eflags, implicit{{( killed)?}} $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %3
|
|
JMP_1 %bb.8
|
|
|
|
bb.4:
|
|
successors: %bb.5, %bb.6
|
|
liveins: $eflags
|
|
|
|
; Another inner loop, this one with a diamond.
|
|
JCC_1 %bb.5, 4, implicit $eflags
|
|
JMP_1 %bb.6
|
|
; CHECK: bb.4:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.5, 5, implicit killed $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
bb.5:
|
|
successors: %bb.7
|
|
liveins: $eflags
|
|
|
|
; Just use $eflags on this side of the diamond.
|
|
%4:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
|
|
; CHECK: bb.5:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %4:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %4
|
|
JMP_1 %bb.7
|
|
|
|
bb.6:
|
|
successors: %bb.7
|
|
liveins: $eflags
|
|
|
|
; Use, copy, and then use $eflags again.
|
|
%5:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
|
|
; CHECK: bb.6:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %5:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %5
|
|
|
|
%6:gr64 = COPY $eflags
|
|
$eflags = COPY %6:gr64
|
|
|
|
%7:gr64 = CMOV64rr %0, %1, 7, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: %7:gr64 = CMOV64rr %0, %1, 5, implicit killed $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %7
|
|
JMP_1 %bb.7
|
|
|
|
bb.7:
|
|
successors: %bb.4, %bb.8
|
|
liveins: $eflags
|
|
|
|
; Inner loop latch.
|
|
JCC_1 %bb.4, 4, implicit $eflags
|
|
JMP_1 %bb.8
|
|
; CHECK: bb.7:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.4, 5, implicit killed $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
bb.8:
|
|
successors: %bb.1, %bb.9
|
|
|
|
; Outer loop latch. Note that we cannot have EFLAGS live-in here as that
|
|
; immediately require PHIs.
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
JCC_1 %bb.1, 4, implicit $eflags
|
|
JMP_1 %bb.9
|
|
; CHECK: bb.8:
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
; CHECK: CMP64rr %0, %1, implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.1, 4, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
bb.9:
|
|
liveins: $eflags
|
|
|
|
; And we're done.
|
|
%8:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
|
|
$rax = COPY %8
|
|
RET 0, $rax
|
|
; CHECK: bb.9:
|
|
; CHECK-NOT: $eflags
|
|
; CHECK: %8:gr64 = CMOV64rr %0, %1, 4, implicit killed $eflags
|
|
|
|
...
|
|
---
|
|
name: test_existing_setcc
|
|
# CHECK-LABEL: name: test_existing_setcc
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1, %bb.2, %bb.3
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
%2:gr8 = SETCCr 7, implicit $eflags
|
|
%3:gr8 = SETCCr 3, implicit $eflags
|
|
%4:gr64 = COPY $eflags
|
|
; CHECK: CMP64rr %0, %1, implicit-def $eflags
|
|
; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETCCr 7, implicit $eflags
|
|
; CHECK-NEXT: %[[AE_REG:[^:]*]]:gr8 = SETCCr 3, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %4
|
|
JCC_1 %bb.1, 7, implicit $eflags
|
|
JCC_1 %bb.2, 2, implicit $eflags
|
|
JMP_1 %bb.3
|
|
; CHECK-NOT: $eflags =
|
|
;
|
|
; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: bb.4:
|
|
; CHECK-NEXT: successors: {{.*$}}
|
|
; CHECK-SAME: {{$[[:space:]]}}
|
|
; CHECK-NEXT: TEST8rr %[[AE_REG]], %[[AE_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.2, 4, implicit killed $eflags
|
|
; CHECK-NEXT: JMP_1 %bb.3
|
|
|
|
bb.1:
|
|
%5:gr32 = MOV32ri 42
|
|
$eax = COPY %5
|
|
RET 0, $eax
|
|
|
|
bb.2:
|
|
%6:gr32 = MOV32ri 43
|
|
$eax = COPY %6
|
|
RET 0, $eax
|
|
|
|
bb.3:
|
|
%7:gr32 = MOV32r0 implicit-def dead $eflags
|
|
$eax = COPY %7
|
|
RET 0, $eax
|
|
|
|
...
|
|
---
|
|
name: test_existing_setcc_memory
|
|
# CHECK-LABEL: name: test_existing_setcc_memory
|
|
liveins:
|
|
- { reg: '$rdi', virtual-reg: '%0' }
|
|
- { reg: '$rsi', virtual-reg: '%1' }
|
|
body: |
|
|
bb.0:
|
|
successors: %bb.1, %bb.2
|
|
liveins: $rdi, $rsi
|
|
|
|
%0:gr64 = COPY $rdi
|
|
%1:gr64 = COPY $rsi
|
|
CMP64rr %0, %1, implicit-def $eflags
|
|
SETCCm %0, 1, $noreg, -16, $noreg, 4, implicit $eflags
|
|
%2:gr64 = COPY $eflags
|
|
; CHECK: CMP64rr %0, %1, implicit-def $eflags
|
|
; We cannot reuse this SETE because it stores the flag directly to memory,
|
|
; so we have two SETEs here. FIXME: It'd be great if something could fold
|
|
; these automatically. If not, maybe we want to unfold SETcc instructions
|
|
; writing to memory so we can reuse them.
|
|
; CHECK-NEXT: SETCCm {{.*}} 4, implicit $eflags
|
|
; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETCCr 4, implicit $eflags
|
|
; CHECK-NOT: COPY{{( killed)?}} $eflags
|
|
|
|
ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
CALL64pcrel32 @foo, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
|
|
ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
|
|
|
|
$eflags = COPY %2
|
|
JCC_1 %bb.1, 4, implicit $eflags
|
|
JMP_1 %bb.2
|
|
; CHECK-NOT: $eflags =
|
|
;
|
|
; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags
|
|
; CHECK-NEXT: JCC_1 %bb.1, 5, implicit killed $eflags
|
|
; CHECK-NEXT: JMP_1 %bb.2
|
|
|
|
bb.1:
|
|
%3:gr32 = MOV32ri 42
|
|
$eax = COPY %3
|
|
RET 0, $eax
|
|
|
|
bb.2:
|
|
%4:gr32 = MOV32ri 43
|
|
$eax = COPY %4
|
|
RET 0, $eax
|
|
|
|
...
|