| # RUN: llc -mtriple=x86_64-unknown-linux-gnu -run-pass x86-fixup-bw-insts %s -o - | FileCheck %s |
| |
| --- | |
| define void @test1() { ret void } |
| define void @test2() { ret void } |
| |
| define i16 @test3(i16* readonly %p) { |
| ; Keep original IR to show how the situation like this might happen |
| ; due to preceding CG passes. |
| ; |
| ; %0 is used in %if.end BB (before tail-duplication), so its |
| ; corresponding super-register (EAX) is live-in into that BB (%if.end) |
| ; and also has an EAX<imp-def> flag. Make sure that we still change |
| ; the movw into movzwl because EAX is not live before the load (which |
| ; can be seen by the fact that EAX<imp-use> flag is missing). |
| entry: |
| %tobool = icmp eq i16* %p, null |
| br i1 %tobool, label %if.end, label %if.then |
| |
| if.then: ; preds = %entry |
| %0 = load i16, i16* %p, align 2 |
| br label %if.end |
| |
| if.end: ; preds = %if.then, %entry |
| %i.0 = phi i16 [ %0, %if.then ], [ 0, %entry ] |
| ret i16 %i.0 |
| } |
| |
| ... |
| --- |
| # CHECK-LABEL: name: test1 |
| name: test1 |
| alignment: 4 |
| exposesReturnsTwice: false |
| legalized: false |
| regBankSelected: false |
| selected: false |
| tracksRegLiveness: true |
| registers: |
| liveins: |
| - { reg: '%rax' } |
| frameInfo: |
| stackSize: 0 |
| fixedStack: |
| stack: |
| constants: |
| # Verify that "movw (%rax), %ax" is changed to "movzwl (%rax), %rax". |
| # |
| # For that to happen, the liveness information after the MOV16rm |
| # instruction should be used, not before it because %rax is live |
| # before the MOV and is killed by it. |
| body: | |
| bb.0: |
| liveins: %rax |
| |
| %ax = MOV16rm killed %rax, 1, _, 0, _ |
| ; CHECK: %eax = MOVZX32rm16 killed %rax |
| |
| RETQ %ax |
| |
| ... |
| --- |
| # CHECK-LABEL: name: test2 |
| name: test2 |
| alignment: 4 |
| exposesReturnsTwice: false |
| legalized: false |
| regBankSelected: false |
| selected: false |
| tracksRegLiveness: true |
| registers: |
| liveins: |
| - { reg: '%rax' } |
| frameInfo: |
| stackSize: 0 |
| fixedStack: |
| stack: |
| constants: |
| # Imp-use of any super-register means the register is live before the MOV |
| body: | |
| bb.0: |
| liveins: %dl, %rbx, %rcx, %r14 |
| |
| %cl = MOV8rr killed %dl, implicit killed %rcx, implicit-def %rcx |
| ; CHECK: %cl = MOV8rr killed %dl, implicit killed %rcx, implicit-def %rcx |
| JMP_1 %bb.1 |
| bb.1: |
| liveins: %rcx |
| |
| RETQ %cl |
| |
| ... |
| --- |
| # CHECK-LABEL: name: test3 |
| name: test3 |
| alignment: 4 |
| exposesReturnsTwice: false |
| legalized: false |
| regBankSelected: false |
| selected: false |
| tracksRegLiveness: true |
| registers: |
| liveins: |
| - { reg: '%rdi', virtual-reg: '' } |
| frameInfo: |
| isFrameAddressTaken: false |
| isReturnAddressTaken: false |
| hasStackMap: false |
| hasPatchPoint: false |
| stackSize: 0 |
| offsetAdjustment: 0 |
| maxAlignment: 0 |
| adjustsStack: false |
| hasCalls: false |
| stackProtector: '' |
| maxCallFrameSize: 0 |
| hasOpaqueSPAdjustment: false |
| hasVAStart: false |
| hasMustTailInVarArgFunc: false |
| savePoint: '' |
| restorePoint: '' |
| fixedStack: |
| stack: |
| constants: |
| # After MOV16rm the whole %eax is not *really* live, as can be seen by |
| # missing implicit-uses of it in that MOV. Make sure that MOV is |
| # transformed into MOVZX. |
| # See the comment near the original IR on what preceding decisions can |
| # lead to that. |
| body: | |
| bb.0.entry: |
| successors: %bb.1(0x30000000), %bb.2.if.then(0x50000000) |
| liveins: %rdi |
| |
| TEST64rr %rdi, %rdi, implicit-def %eflags |
| JE_1 %bb.1, implicit %eflags |
| |
| bb.2.if.then: |
| liveins: %rdi |
| |
| %ax = MOV16rm killed %rdi, 1, _, 0, _, implicit-def %eax :: (load 2 from %ir.p) |
| ; CHECK: %eax = MOVZX32rm16 killed %rdi, 1, _, 0, _, implicit-def %eax :: (load 2 from %ir.p) |
| %ax = KILL %ax, implicit killed %eax |
| RETQ %ax |
| |
| bb.1: |
| %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags |
| %ax = KILL %ax, implicit killed %eax |
| RETQ %ax |
| |
| ... |