Skip to content

Commit c74271c

Browse files
committed
[LiveRange] Reset the VNIs when splitting subranges
When splitting a subrange we end up with two different subranges covering two different, non overlapping, lanes. As part of this splitting the VNIs of the original live-range need to be dispatched to the subranges according to which lanes they are actually defining. Prior to this patch we were assuming that all values were defining all lanes. This was wrong as demonstrated by llvm.org/PR40835. Differential Revision: https://reviews.llvm.org/D59731 llvm-svn: 357032
1 parent 55d4954 commit c74271c

File tree

6 files changed

+189
-33
lines changed

6 files changed

+189
-33
lines changed

llvm/include/llvm/CodeGen/LiveInterval.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -789,8 +789,15 @@ namespace llvm {
789789
/// L000F, refining for mask L0018. Will split the L00F0 lane into
790790
/// L00E0 and L0010 and the L000F lane into L0007 and L0008. The Mod
791791
/// function will be applied to the L0010 and L0008 subranges.
792+
///
793+
/// \p Indexes and \p TRI are required to clean up the VNIs that
794+
/// don't defne the related lane masks after they get shrunk. E.g.,
795+
/// when L000F gets split into L0007 and L0008 maybe only a subset
796+
/// of the VNIs that defined L000F defines L0007.
792797
void refineSubRanges(BumpPtrAllocator &Allocator, LaneBitmask LaneMask,
793-
std::function<void(LiveInterval::SubRange&)> Apply);
798+
std::function<void(LiveInterval::SubRange &)> Apply,
799+
const SlotIndexes &Indexes,
800+
const TargetRegisterInfo &TRI);
794801

795802
bool operator<(const LiveInterval& other) const {
796803
const SlotIndex &thisIndex = beginIndex();

llvm/lib/CodeGen/LiveInterval.cpp

+51-2
Original file line numberDiff line numberDiff line change
@@ -879,8 +879,53 @@ void LiveInterval::clearSubRanges() {
879879
SubRanges = nullptr;
880880
}
881881

882-
void LiveInterval::refineSubRanges(BumpPtrAllocator &Allocator,
883-
LaneBitmask LaneMask, std::function<void(LiveInterval::SubRange&)> Apply) {
882+
/// For each VNI in \p SR, check whether or not that value defines part
883+
/// of the mask describe by \p LaneMask and if not, remove that value
884+
/// from \p SR.
885+
static void stripValuesNotDefiningMask(unsigned Reg, LiveInterval::SubRange &SR,
886+
LaneBitmask LaneMask,
887+
const SlotIndexes &Indexes,
888+
const TargetRegisterInfo &TRI) {
889+
// Phys reg should not be tracked at subreg level.
890+
// Same for noreg (Reg == 0).
891+
if (!TargetRegisterInfo::isVirtualRegister(Reg) || !Reg)
892+
return;
893+
// Remove the values that don't define those lanes.
894+
SmallVector<VNInfo *, 8> ToBeRemoved;
895+
for (VNInfo *VNI : SR.valnos) {
896+
if (VNI->isUnused())
897+
continue;
898+
// PHI definitions don't have MI attached, so there is nothing
899+
// we can use to strip the VNI.
900+
if (VNI->isPHIDef())
901+
continue;
902+
const MachineInstr *MI = Indexes.getInstructionFromIndex(VNI->def);
903+
assert(MI && "Cannot find the definition of a value");
904+
bool hasDef = false;
905+
for (ConstMIBundleOperands MOI(*MI); MOI.isValid(); ++MOI) {
906+
if (!MOI->isReg() || !MOI->isDef())
907+
continue;
908+
if (MOI->getReg() != Reg)
909+
continue;
910+
if ((TRI.getSubRegIndexLaneMask(MOI->getSubReg()) & LaneMask).none())
911+
continue;
912+
hasDef = true;
913+
break;
914+
}
915+
916+
if (!hasDef)
917+
ToBeRemoved.push_back(VNI);
918+
}
919+
for (VNInfo *VNI : ToBeRemoved)
920+
SR.removeValNo(VNI);
921+
922+
assert(!SR.empty() && "At least one value should be defined by this mask");
923+
}
924+
925+
void LiveInterval::refineSubRanges(
926+
BumpPtrAllocator &Allocator, LaneBitmask LaneMask,
927+
std::function<void(LiveInterval::SubRange &)> Apply,
928+
const SlotIndexes &Indexes, const TargetRegisterInfo &TRI) {
884929
LaneBitmask ToApply = LaneMask;
885930
for (SubRange &SR : subranges()) {
886931
LaneBitmask SRMask = SR.LaneMask;
@@ -898,6 +943,10 @@ void LiveInterval::refineSubRanges(BumpPtrAllocator &Allocator,
898943
SR.LaneMask = SRMask & ~Matching;
899944
// Create a new subrange for the matching part
900945
MatchingRange = createSubRangeFrom(Allocator, Matching, SR);
946+
// Now that the subrange is split in half, make sure we
947+
// only keep in the subranges the VNIs that touch the related half.
948+
stripValuesNotDefiningMask(reg, *MatchingRange, Matching, Indexes, TRI);
949+
stripValuesNotDefiningMask(reg, SR, SR.LaneMask, Indexes, TRI);
901950
}
902951
Apply(*MatchingRange);
903952
ToApply &= ~Matching;

llvm/lib/CodeGen/LiveRangeCalc.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,11 @@ void LiveRangeCalc::calculate(LiveInterval &LI, bool TrackSubRegs) {
9595
}
9696

9797
LI.refineSubRanges(*Alloc, SubMask,
98-
[&MO, this](LiveInterval::SubRange &SR) {
99-
if (MO.isDef())
100-
createDeadDef(*Indexes, *Alloc, SR, MO);
101-
});
98+
[&MO, this](LiveInterval::SubRange &SR) {
99+
if (MO.isDef())
100+
createDeadDef(*Indexes, *Alloc, SR, MO);
101+
},
102+
*Indexes, TRI);
102103
}
103104

104105
// Create the def in the main liverange. We do not have to do this if

llvm/lib/CodeGen/RegisterCoalescer.cpp

+26-22
Original file line numberDiff line numberDiff line change
@@ -924,23 +924,25 @@ RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
924924
}
925925
SlotIndex AIdx = CopyIdx.getRegSlot(true);
926926
LaneBitmask MaskA;
927+
const SlotIndexes &Indexes = *LIS->getSlotIndexes();
927928
for (LiveInterval::SubRange &SA : IntA.subranges()) {
928929
VNInfo *ASubValNo = SA.getVNInfoAt(AIdx);
929930
assert(ASubValNo != nullptr);
930931
MaskA |= SA.LaneMask;
931932

932-
IntB.refineSubRanges(Allocator, SA.LaneMask,
933-
[&Allocator,&SA,CopyIdx,ASubValNo,&ShrinkB]
934-
(LiveInterval::SubRange &SR) {
935-
VNInfo *BSubValNo = SR.empty()
936-
? SR.getNextValue(CopyIdx, Allocator)
937-
: SR.getVNInfoAt(CopyIdx);
938-
assert(BSubValNo != nullptr);
939-
auto P = addSegmentsWithValNo(SR, BSubValNo, SA, ASubValNo);
940-
ShrinkB |= P.second;
941-
if (P.first)
942-
BSubValNo->def = ASubValNo->def;
943-
});
933+
IntB.refineSubRanges(
934+
Allocator, SA.LaneMask,
935+
[&Allocator, &SA, CopyIdx, ASubValNo,
936+
&ShrinkB](LiveInterval::SubRange &SR) {
937+
VNInfo *BSubValNo = SR.empty() ? SR.getNextValue(CopyIdx, Allocator)
938+
: SR.getVNInfoAt(CopyIdx);
939+
assert(BSubValNo != nullptr);
940+
auto P = addSegmentsWithValNo(SR, BSubValNo, SA, ASubValNo);
941+
ShrinkB |= P.second;
942+
if (P.first)
943+
BSubValNo->def = ASubValNo->def;
944+
},
945+
Indexes, *TRI);
944946
}
945947
// Go over all subranges of IntB that have not been covered by IntA,
946948
// and delete the segments starting at CopyIdx. This can happen if
@@ -3262,16 +3264,18 @@ void RegisterCoalescer::mergeSubRangeInto(LiveInterval &LI,
32623264
LaneBitmask LaneMask,
32633265
CoalescerPair &CP) {
32643266
BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator();
3265-
LI.refineSubRanges(Allocator, LaneMask,
3266-
[this,&Allocator,&ToMerge,&CP](LiveInterval::SubRange &SR) {
3267-
if (SR.empty()) {
3268-
SR.assign(ToMerge, Allocator);
3269-
} else {
3270-
// joinSubRegRange() destroys the merged range, so we need a copy.
3271-
LiveRange RangeCopy(ToMerge, Allocator);
3272-
joinSubRegRanges(SR, RangeCopy, SR.LaneMask, CP);
3273-
}
3274-
});
3267+
LI.refineSubRanges(
3268+
Allocator, LaneMask,
3269+
[this, &Allocator, &ToMerge, &CP](LiveInterval::SubRange &SR) {
3270+
if (SR.empty()) {
3271+
SR.assign(ToMerge, Allocator);
3272+
} else {
3273+
// joinSubRegRange() destroys the merged range, so we need a copy.
3274+
LiveRange RangeCopy(ToMerge, Allocator);
3275+
joinSubRegRanges(SR, RangeCopy, SR.LaneMask, CP);
3276+
}
3277+
},
3278+
*LIS->getSlotIndexes(), *TRI);
32753279
}
32763280

32773281
bool RegisterCoalescer::isHighCostLiveInterval(LiveInterval &LI) {

llvm/lib/CodeGen/SplitKit.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -520,17 +520,18 @@ SlotIndex SplitEditor::buildSingleSubRegCopy(unsigned FromReg, unsigned ToReg,
520520
.addReg(FromReg, 0, SubIdx);
521521

522522
BumpPtrAllocator &Allocator = LIS.getVNInfoAllocator();
523+
SlotIndexes &Indexes = *LIS.getSlotIndexes();
523524
if (FirstCopy) {
524-
SlotIndexes &Indexes = *LIS.getSlotIndexes();
525525
Def = Indexes.insertMachineInstrInMaps(*CopyMI, Late).getRegSlot();
526526
} else {
527527
CopyMI->bundleWithPred();
528528
}
529529
LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubIdx);
530530
DestLI.refineSubRanges(Allocator, LaneMask,
531-
[Def, &Allocator](LiveInterval::SubRange& SR) {
532-
SR.createDeadDef(Def, Allocator);
533-
});
531+
[Def, &Allocator](LiveInterval::SubRange &SR) {
532+
SR.createDeadDef(Def, Allocator);
533+
},
534+
Indexes, TRI);
534535
return Def;
535536
}
536537

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple s390x-ibm-linux -mcpu=z13 -systemz-subreg-liveness -verify-machineinstrs -start-before simple-register-coalescing -stop-after greedy -o - %s | FileCheck %s
3+
4+
# Check that when we split the live-range with several active lanes
5+
# as part of the live-range update, we correctly eliminate the VNI from
6+
# the relevant part.
7+
#
8+
# In this specific test, the register coalescer will:
9+
# 1. Merge %0 with %1, creating a live-range for the full value subreg_l32 + subreg_h32
10+
# (actually %0 gets merge with %1 via rematerialization, and technically %0 and %1
11+
# remain two different live-ranges.)
12+
# 2. Merge %2 with %1 triggering a split into the subreg_l32 + subreg_h32 ranges, since
13+
# %2 only touches subreg_l32. As part of the split the subrange covering subreg_h32
14+
# must contain only the VNI for the high part (i.e., the one tied with the remaaat of %0).
15+
# This used to be broken and trigger a machine verifier error, because we were not
16+
# clearing the dead value w.r.t. lanes when doing the splitting. I.e., we were ending
17+
# with a subrange referring a value that did not define that lane.
18+
#
19+
# PR40835
20+
---
21+
name: main
22+
tracksRegLiveness: true
23+
body: |
24+
bb.0:
25+
26+
; CHECK-LABEL: name: main
27+
; CHECK: [[LGHI:%[0-9]+]]:gr64bit = LGHI 43
28+
; CHECK: [[LGHI1:%[0-9]+]]:gr64bit = LGHI 43
29+
; CHECK: [[LGHI1]].subreg_l32:gr64bit = MSR [[LGHI1]].subreg_l32, [[LGHI1]].subreg_l32
30+
; CHECK: [[LGHI1]].subreg_l32:gr64bit = AHIMux [[LGHI1]].subreg_l32, 9, implicit-def dead $cc
31+
; CHECK: undef %3.subreg_l64:gr128bit = LGFI -245143785, implicit [[LGHI1]].subreg_l32
32+
; CHECK: [[DLGR:%[0-9]+]]:gr128bit = DLGR [[DLGR]], [[LGHI]]
33+
; CHECK: Return implicit [[DLGR]]
34+
%0:gr64bit = LGHI 43
35+
%1:gr32bit = COPY %0.subreg_l32
36+
%1:gr32bit = MSR %1, %1
37+
%2:gr32bit = COPY killed %1
38+
%2:gr32bit = AHIMux killed %2, 9, implicit-def dead $cc
39+
undef %3.subreg_l64:gr128bit = LGFI -245143785, implicit killed %2
40+
%3:gr128bit = DLGR %3:gr128bit, killed %0
41+
Return implicit killed %3
42+
43+
...
44+
45+
# Make sure the compiler does not choke on VNIs that don't
46+
# an explicit MI as definition.
47+
# In that specific example, this is the PHI not explicitly
48+
# represented for the value carried by %7.
49+
---
50+
name: segfault
51+
tracksRegLiveness: true
52+
liveins: []
53+
body: |
54+
; CHECK-LABEL: name: segfault
55+
; CHECK: bb.0:
56+
; CHECK: successors: %bb.1(0x80000000)
57+
; CHECK: [[LGHI:%[0-9]+]]:addr64bit = LGHI 0
58+
; CHECK: bb.1:
59+
; CHECK: successors: %bb.1(0x80000000)
60+
; CHECK: ADJCALLSTACKDOWN 0, 0
61+
; CHECK: [[LGFR:%[0-9]+]]:gr64bit = LGFR [[LGHI]].subreg_l32
62+
; CHECK: $r2d = LGHI 123
63+
; CHECK: $r3d = LGHI 0
64+
; CHECK: $r4d = LGHI 0
65+
; CHECK: $r5d = COPY [[LGFR]]
66+
; CHECK: KILL killed $r2d, killed $r3d, killed $r4d, $r5d, csr_systemz, implicit-def dead $r14d, implicit-def dead $cc
67+
; CHECK: ADJCALLSTACKUP 0, 0
68+
; CHECK: [[LGHI]]:addr64bit = nuw nsw LA [[LGHI]], 1, $noreg
69+
; CHECK: J %bb.1
70+
bb.0:
71+
successors: %bb.1(0x80000000)
72+
73+
%2:gr64bit = LGHI 0
74+
%5:gr64bit = LGHI 123
75+
%7:addr64bit = COPY %2
76+
77+
bb.1:
78+
successors: %bb.1(0x80000000)
79+
80+
%0:addr64bit = COPY killed %7
81+
ADJCALLSTACKDOWN 0, 0
82+
%3:gr32bit = COPY %0.subreg_l32
83+
%4:gr64bit = LGFR killed %3
84+
$r2d = COPY %5
85+
$r3d = COPY %2
86+
$r4d = COPY %2
87+
$r5d = COPY killed %4
88+
KILL killed $r2d, killed $r3d, killed $r4d, killed $r5d, csr_systemz, implicit-def dead $r14d, implicit-def dead $cc
89+
ADJCALLSTACKUP 0, 0
90+
%1:gr64bit = nuw nsw LA killed %0, 1, $noreg
91+
%7:addr64bit = COPY killed %1
92+
J %bb.1
93+
94+
...

0 commit comments

Comments
 (0)