[RegisterCoalescer] Update empty subranges when rematerializing
authorQuentin Colombet <qcolombet@apple.com>
Wed, 3 Jun 2020 23:15:23 +0000 (16:15 -0700)
committerQuentin Colombet <qcolombet@apple.com>
Thu, 4 Jun 2020 00:10:55 +0000 (17:10 -0700)
commitccb3c8e8613413846d6c2f17cc1c1e2a8b6a98ef
treed83e6f69f8f7f59a4900daa8b52895109ead529f
parenteb9ca9da3e94e0c0d5eb8d98a388e92da0df9f12
[RegisterCoalescer] Update empty subranges when rematerializing

When we rematerialize a value as part of the coalescing, we may
widen the register class of the destination register.
When this happens, updateRegDefUses may create additional subranges
to account for the wider register class.
The created subranges are empty and if they are not defined by
the rematerialized instruction we clean them up.
However, if they are defined by the rematerialized instruction but
unused, we failed to flag them as dead definition and would leave
them as empty live-range.
This is wrong because empty live-ranges don't interfere with anything,
thus if we don't fix them, we would fail to account that the
rematerialized instruction clobbers some lanes.

E.g., let us consider the following pseudo code:
def.lane_low64:reg128 = ldimm
newdef:reg32 = COPY def.lane_low64_low32

When rematerialization happens for newdef, we end up with:
newdef.lane_low64:reg128 = ldimm
 = use newdef.lane_low64_low32

Let's look at the live interval of newdef.
Before rematerialization, we would get:
newdef [defIdx, useIdx:0) 0@defIdx

Right after updateRegDefUses, newdef register class is widen to reg128
and the subrange definitions will be augmented to fill the subreg that
is used at the definition point, here lane_low64.
The resulting live interval would be:
newdef [newDefIdx, useIdx:0) 0@newDefIdx
 * lane_low64_high32 EMPTY
 * lane_low64_low32 [newDefIdx, useIdx:0)

Before this patch this would be the final status of the live interval.
Therefore we miss that lane_low64_high32 is actually live on the
definition point of newdef.

With this patch, after rematerializing, we check all the added subranges
and for the ones that are defined but empty, we flag them as dead def.
Thus, in that case, newdef would look like this:
newdef [newDefIdx, useIdx:0) 0@newDefIdx
 * lane_low64_high32 [newDefIdx, newDefIdxDead) ; <-- instead of EMPTY
 * lane_low64_low32 [newDefIdx, useIdx:0)

This fixes https://www.llvm.org/PR46154
llvm/lib/CodeGen/RegisterCoalescer.cpp
llvm/test/CodeGen/SystemZ/regcoal_remat_empty_subrange.ll [new file with mode: 0644]