This patch fixes a potential crash due to RegAllocFast not rewriting virtual registers. This essentially happens because of a call to MachineInstr::addRegisterKilled() in the process of allocating a "killed" vreg. The former can eventually delete implicit operands without RegAllocFast noticing, leading to some operands being "skipped" and not rewritten to use physical registers. Note that I noticed this crash when working on a solution for tying a register with one/multiple of its sub-registers within an instruction. (See problem description here: https://discourse.llvm.org/t/pass-to-tie-an-output-operand-to-a-subregister-of-an-input-operand/67184). Aside from this fix, I believe there could be further improvements to the RegAllocFast when it comes to instructions with multiple uses of a same virtual register. You can see it in the added test where the implicit uses have been re-written in a somewhat surprising way because of phase ordering. Ultimately, when allocating vregs for an instruction, I believe we should iterate on the vregs it uses (and then process all the operands that use this vregs), instead of directly iterating on operands and somewhat assuming each operand uses a different vreg. This would in the end be quite close to what greedy+virtregrewriter does. If that makes sense, I would probably spin off another patch (after I get more familiar with RegAllocFast). Differential Revision: https://reviews.llvm.org/D145169
79 lines
3.0 KiB
YAML
79 lines
3.0 KiB
YAML
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
|
# RUN: llc -mtriple=armv7-apple-ios -run-pass=regallocfast -o - %s | FileCheck %s
|
|
|
|
|
|
# tBX_RET uses an implicit vreg with a sub-register. That implicit use will
|
|
# typically be rewritten as a use of the relevant super-register. Make sure
|
|
# regallocfast is able to process the remaining operands (here, %2) and rewrite
|
|
# them to use physical registers.
|
|
---
|
|
name: different_vreg
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0:
|
|
liveins: $d2, $d4, $d7
|
|
|
|
; CHECK-LABEL: name: different_vreg
|
|
; CHECK: liveins: $d2, $d4, $d7
|
|
; CHECK-NEXT: {{ $}}
|
|
; CHECK-NEXT: renamable $d5 = COPY killed $d4
|
|
; CHECK-NEXT: renamable $d4 = COPY killed $d2
|
|
; CHECK-NEXT: undef renamable $d0 = COPY renamable $d5, implicit-def $q0_q1
|
|
; CHECK-NEXT: renamable $d1 = COPY renamable $d4
|
|
; CHECK-NEXT: renamable $d2 = COPY killed renamable $d5
|
|
; CHECK-NEXT: renamable $d3 = COPY killed renamable $d4
|
|
; CHECK-NEXT: tBX_RET 14 /* CC::al */, $noreg, implicit killed renamable $d7, implicit killed $q0_q1
|
|
%0:dpr_vfp2 = COPY $d4
|
|
%1:dpr_vfp2 = COPY $d2
|
|
%2:dpr_vfp2 = COPY $d7
|
|
undef %4.dsub_0:dquad = COPY %0
|
|
%4.dsub_1:dquad = COPY %1
|
|
%4.dsub_2:dquad = COPY %0
|
|
%4.dsub_3:dquad = COPY %1
|
|
tBX_RET 14, $noreg, implicit %4.dsub_3, implicit %2
|
|
...
|
|
|
|
|
|
# tBX_RET uses the same vreg twice, make sure regallocfast is able to allocate a
|
|
# physical register for it and replace both references.
|
|
---
|
|
name: same_vreg_twice
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0:
|
|
liveins: $d2, $d4
|
|
|
|
; CHECK-LABEL: name: same_vreg_twice
|
|
; CHECK: liveins: $d2, $d4
|
|
; CHECK-NEXT: {{ $}}
|
|
; CHECK-NEXT: renamable $d5 = COPY killed $d4
|
|
; CHECK-NEXT: renamable $d4 = COPY killed $d2
|
|
; CHECK-NEXT: undef renamable $d0 = COPY renamable $d5, implicit-def $q0_q1
|
|
; CHECK-NEXT: renamable $d1 = COPY renamable $d4
|
|
; CHECK-NEXT: renamable $d2 = COPY killed renamable $d5
|
|
; CHECK-NEXT: renamable $d3 = COPY killed renamable $d4
|
|
; CHECK-NEXT: tBX_RET 14 /* CC::al */, $noreg, implicit renamable $d3, implicit killed $q0_q1
|
|
%0:dpr_vfp2 = COPY $d4
|
|
%1:dpr_vfp2 = COPY $d2
|
|
undef %4.dsub_0:dquad = COPY %0
|
|
%4.dsub_1:dquad = COPY %1
|
|
%4.dsub_2:dquad = COPY %0
|
|
%4.dsub_3:dquad = COPY %1
|
|
tBX_RET 14, $noreg, implicit %4.dsub_1, implicit %4.dsub_3
|
|
...
|
|
|
|
# tBL partially defines two vregs, which turn out to be dead. Make sure
|
|
# regallocfast allocates a phys reg for both %0 and %1.
|
|
---
|
|
name: partial_dead
|
|
tracksRegLiveness: true
|
|
body: |
|
|
bb.0:
|
|
|
|
; CHECK-LABEL: name: partial_dead
|
|
; CHECK: tBL 14 /* CC::al */, $noreg, 0, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $q0_q1, implicit-def dead $q2_q3
|
|
; CHECK-NEXT: tBX_RET 14 /* CC::al */, $noreg
|
|
tBL 14, $noreg, 0, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def undef %0.dsub_0:dquad, implicit-def undef %1.dsub_2:dquad
|
|
tBX_RET 14, $noreg
|
|
...
|