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 {{.*}}, killed %[[A_REG]]
|
|
; CHECK-NEXT: MOV8mr {{.*}}, killed %[[B_REG]]
|
|
; CHECK-NEXT: MOV8mr {{.*}}, killed %[[E_REG]]
|
|
; CHECK-NOT: MOV8mr {{.*}}, killed %[[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
|
|
|
|
...
|