| # 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 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETBr 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 |
| JA_1 %bb.1, implicit $eflags |
| JB_1 %bb.2, implicit $eflags |
| JMP_1 %bb.3 |
| ; CHECK-NOT: $eflags = |
| ; |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: JNE_1 %bb.1, 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: JNE_1 %bb.2, implicit killed $eflags |
| ; CHECK-NEXT: JMP_1 %bb.3 |
| |
| bb.1: |
| %3:gr32 = MOV32ri64 42 |
| $eax = COPY %3 |
| RET 0, $eax |
| |
| bb.2: |
| %4:gr32 = MOV32ri64 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 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETBr 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 |
| JA_1 %bb.2, implicit $eflags |
| JB_1 %bb.3, implicit $eflags |
| ; CHECK-NOT: $eflags = |
| ; |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: JNE_1 %bb.2, 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: JNE_1 %bb.3, 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 = MOV32ri64 42 |
| $eax = COPY %3 |
| RET 0, $eax |
| |
| bb.3: |
| %4:gr32 = MOV32ri64 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 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETBr implicit $eflags |
| ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETEr implicit $eflags |
| ; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETNEr 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 = SETAr implicit $eflags |
| %4:gr8 = SETBr implicit $eflags |
| %5:gr8 = SETEr implicit $eflags |
| SETNEm $rsp, 1, $noreg, -16, $noreg, 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 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETBr implicit $eflags |
| ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETEr 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 = CMOVA64rr %0, %1, implicit $eflags |
| %4:gr64 = CMOVB64rr %0, %1, implicit $eflags |
| %5:gr64 = CMOVE64rr %0, %1, implicit $eflags |
| %6:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %3:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| ; CHECK-NEXT: TEST8rr %[[B_REG]], %[[B_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %4:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| ; CHECK-NEXT: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %5:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| ; CHECK-NEXT: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %6:gr64 = CMOVE64rr %0, %1, 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 = SETBr 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 = SETBr 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 = SETEr implicit $eflags |
| ; CHECK-NEXT: %[[CF_REG:[^:]*]]:gr8 = SETBr 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 = CMOVE64rr %0, %1, 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 = CMOVNE64rr %0, %1, 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 = SETEr implicit $eflags |
| ; CHECK-NEXT: %[[OF_REG:[^:]*]]:gr8 = SETOr 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 = CMOVE64rr %0, %1, 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 = CMOVNE64rr %0, %1, 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 = SETBr 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 = SETBr 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 = SETBr 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:gr8 = SETB_C8r implicit-def $eflags, implicit $eflags |
| MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %4 |
| ; CHECK-NOT: $eflags = |
| ; CHECK: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags |
| ; CHECK-NEXT: %[[ZERO_SUBREG:[^:]*]]:gr8 = COPY %[[ZERO]].sub_8bit |
| ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr8 = SUB8rr %[[ZERO_SUBREG]], %[[CF_REG]] |
| ; CHECK-NEXT: MOV8mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]] |
| |
| $eflags = COPY %3 |
| %5:gr16 = SETB_C16r implicit-def $eflags, implicit $eflags |
| MOV16mr $rsp, 1, $noreg, -16, $noreg, killed %5 |
| ; CHECK-NOT: $eflags = |
| ; CHECK: %[[CF_EXT:[^:]*]]:gr32 = MOVZX32rr8 %[[CF_REG]] |
| ; CHECK-NEXT: %[[CF_TRUNC:[^:]*]]:gr16 = COPY %[[CF_EXT]].sub_16bit |
| ; CHECK-NEXT: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags |
| ; CHECK-NEXT: %[[ZERO_SUBREG:[^:]*]]:gr16 = COPY %[[ZERO]].sub_16bit |
| ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr16 = SUB16rr %[[ZERO_SUBREG]], %[[CF_TRUNC]] |
| ; CHECK-NEXT: MOV16mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]] |
| |
| $eflags = COPY %3 |
| %6:gr32 = SETB_C32r implicit-def $eflags, implicit $eflags |
| MOV32mr $rsp, 1, $noreg, -16, $noreg, killed %6 |
| ; CHECK-NOT: $eflags = |
| ; CHECK: %[[CF_EXT:[^:]*]]:gr32 = MOVZX32rr8 %[[CF_REG]] |
| ; CHECK-NEXT: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags |
| ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr32 = SUB32rr %[[ZERO]], %[[CF_EXT]] |
| ; CHECK-NEXT: MOV32mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]] |
| |
| $eflags = COPY %3 |
| %7:gr64 = SETB_C64r implicit-def $eflags, implicit $eflags |
| MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %7 |
| ; CHECK-NOT: $eflags = |
| ; CHECK: %[[CF_EXT1:[^:]*]]:gr32 = MOVZX32rr8 %[[CF_REG]] |
| ; CHECK-NEXT: %[[CF_EXT2:[^:]*]]:gr64 = SUBREG_TO_REG 0, %[[CF_EXT1]], %subreg.sub_32bit |
| ; CHECK-NEXT: %[[ZERO:[^:]*]]:gr32 = MOV32r0 implicit-def $eflags |
| ; CHECK-NEXT: %[[ZERO_EXT:[^:]*]]:gr64 = SUBREG_TO_REG 0, %[[ZERO]], %subreg.sub_32bit |
| ; CHECK-NEXT: %[[REPLACEMENT:[^:]*]]:gr64 = SUB64rr %[[ZERO_EXT]], %[[CF_EXT2]] |
| ; CHECK-NEXT: MOV64mr $rsp, 1, $noreg, -16, $noreg, killed %[[REPLACEMENT]] |
| |
| 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 = SETSr implicit $eflags |
| ; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETNEr implicit $eflags |
| ; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETBr 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 |
| JA_1 %bb.1, implicit $eflags |
| JB_1 %bb.2, implicit $eflags |
| JMP_1 %bb.3 |
| ; CHECK-NOT: $eflags = |
| ; |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: JNE_1 %bb.1, 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: JNE_1 %bb.2, implicit killed $eflags |
| ; CHECK-NEXT: JMP_1 %bb.3 |
| |
| bb.1: |
| liveins: $eflags |
| |
| %3:gr64 = CMOVE64rr %0, %1, implicit killed $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %3:gr64 = CMOVE64rr %0, %1, implicit killed $eflags |
| $rax = COPY %3 |
| RET 0, $rax |
| |
| bb.2: |
| liveins: $eflags |
| |
| %4:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %4:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| $rax = COPY %4 |
| RET 0, $rax |
| |
| bb.3: |
| liveins: $eflags |
| |
| %5:gr64 = CMOVS64rr %0, %1, implicit killed $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[S_REG]], %[[S_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %5:gr64 = CMOVNE64rr %0, %1, 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 = SETSr implicit $eflags |
| ; CHECK-NEXT: %[[P_REG:[^:]*]]:gr8 = SETPr implicit $eflags |
| ; CHECK-NEXT: %[[NE_REG:[^:]*]]:gr8 = SETNEr implicit $eflags |
| ; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETBr implicit $eflags |
| ; CHECK-NEXT: %[[O_REG:[^:]*]]:gr8 = SETOr 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 |
| JA_1 %bb.1, implicit $eflags |
| JB_1 %bb.2, implicit $eflags |
| JMP_1 %bb.5 |
| ; CHECK-NOT: $eflags = |
| ; |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: JNE_1 %bb.1, 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: JNE_1 %bb.2, implicit killed $eflags |
| ; CHECK-NEXT: JMP_1 %bb.5 |
| |
| bb.1: |
| liveins: $eflags |
| |
| %3:gr64 = CMOVE64rr %0, %1, implicit killed $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %3:gr64 = CMOVE64rr %0, %1, 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 |
| |
| JO_1 %bb.3, implicit $eflags |
| JMP_1 %bb.4 |
| ; CHECK-NOT: $eflags = |
| ; |
| ; CHECK: TEST8rr %[[O_REG]], %[[O_REG]], implicit-def $eflags |
| ; CHECK-NEXT: JNE_1 %bb.3, implicit killed $eflags |
| ; CHECK-NEXT: JMP_1 %bb.4 |
| |
| bb.3: |
| liveins: $eflags |
| |
| %4:gr64 = CMOVNE64rr %0, %1, implicit $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[NE_REG]], %[[NE_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %4:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| $rax = COPY %4 |
| RET 0, $rax |
| |
| bb.4: |
| liveins: $eflags |
| |
| %5:gr64 = CMOVP64rr %0, %1, implicit $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[P_REG]], %[[P_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %5:gr64 = CMOVNE64rr %0, %1, implicit killed $eflags |
| $rax = COPY %5 |
| RET 0, $rax |
| |
| bb.5: |
| liveins: $eflags |
| |
| %6:gr64 = CMOVS64rr %0, %1, implicit killed $eflags |
| ; CHECK-NOT: $eflags = |
| ; CHECK: TEST8rr %[[S_REG]], %[[S_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %6:gr64 = CMOVNE64rr %0, %1, 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. |
| JE_1 %bb.2, implicit $eflags |
| JMP_1 %bb.4 |
| ; CHECK: bb.1: |
| ; CHECK-NOT: COPY{{( killed)?}} $eflags |
| ; CHECK: %[[A_REG:[^:]*]]:gr8 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETEr implicit $eflags |
| ; CHECK-NEXT: %[[B_REG:[^:]*]]:gr8 = SETBr 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 |
| JE_1 %bb.2, 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: JNE_1 %bb.2, 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. |
| JE_1 %bb.5, 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: JNE_1 %bb.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 = CMOVA64rr %0, %1, implicit $eflags |
| ; CHECK: bb.5: |
| ; CHECK-NOT: COPY{{( killed)?}} $eflags |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %4:gr64 = CMOVNE64rr %0, %1, 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 = CMOVA64rr %0, %1, implicit $eflags |
| ; CHECK: bb.6: |
| ; CHECK-NOT: COPY{{( killed)?}} $eflags |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %5:gr64 = CMOVNE64rr %0, %1, 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 = CMOVA64rr %0, %1, implicit $eflags |
| ; CHECK-NOT: COPY{{( killed)?}} $eflags |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: %7:gr64 = CMOVNE64rr %0, %1, 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. |
| JE_1 %bb.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: JNE_1 %bb.4, 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 |
| JE_1 %bb.1, implicit $eflags |
| JMP_1 %bb.9 |
| ; CHECK: bb.8: |
| ; CHECK-NOT: COPY{{( killed)?}} $eflags |
| ; CHECK: CMP64rr %0, %1, implicit-def $eflags |
| ; CHECK-NEXT: JE_1 %bb.1, implicit $eflags |
| ; CHECK-NOT: COPY{{( killed)?}} $eflags |
| |
| bb.9: |
| liveins: $eflags |
| |
| ; And we're done. |
| %8:gr64 = CMOVE64rr %0, %1, implicit killed $eflags |
| $rax = COPY %8 |
| RET 0, $rax |
| ; CHECK: bb.9: |
| ; CHECK-NOT: $eflags |
| ; CHECK: %8:gr64 = CMOVE64rr %0, %1, 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 = SETAr implicit $eflags |
| %3:gr8 = SETAEr implicit $eflags |
| %4:gr64 = COPY $eflags |
| ; CHECK: CMP64rr %0, %1, implicit-def $eflags |
| ; CHECK-NEXT: %[[A_REG:[^:]*]]:gr8 = SETAr implicit $eflags |
| ; CHECK-NEXT: %[[AE_REG:[^:]*]]:gr8 = SETAEr 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 |
| JA_1 %bb.1, implicit $eflags |
| JB_1 %bb.2, implicit $eflags |
| JMP_1 %bb.3 |
| ; CHECK-NOT: $eflags = |
| ; |
| ; CHECK: TEST8rr %[[A_REG]], %[[A_REG]], implicit-def $eflags |
| ; CHECK-NEXT: JNE_1 %bb.1, 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: JE_1 %bb.2, implicit killed $eflags |
| ; CHECK-NEXT: JMP_1 %bb.3 |
| |
| bb.1: |
| %5:gr32 = MOV32ri64 42 |
| $eax = COPY %5 |
| RET 0, $eax |
| |
| bb.2: |
| %6:gr32 = MOV32ri64 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 |
| SETEm %0, 1, $noreg, -16, $noreg, 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: SETEm {{.*}} implicit $eflags |
| ; CHECK-NEXT: %[[E_REG:[^:]*]]:gr8 = SETEr 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 |
| JE_1 %bb.1, implicit $eflags |
| JMP_1 %bb.2 |
| ; CHECK-NOT: $eflags = |
| ; |
| ; CHECK: TEST8rr %[[E_REG]], %[[E_REG]], implicit-def $eflags |
| ; CHECK-NEXT: JNE_1 %bb.1, implicit killed $eflags |
| ; CHECK-NEXT: JMP_1 %bb.2 |
| |
| bb.1: |
| %3:gr32 = MOV32ri64 42 |
| $eax = COPY %3 |
| RET 0, $eax |
| |
| bb.2: |
| %4:gr32 = MOV32ri64 43 |
| $eax = COPY %4 |
| RET 0, $eax |
| |
| ... |