[RegisterCoalescer] Shrink to uses if needed after removeCopyByCommutingDef

llvm-svn: 339912
This commit is contained in:
Krzysztof Parzyszek 2018-08-16 18:02:59 +00:00
parent 2f5cf8511a
commit 17143f6111
2 changed files with 102 additions and 24 deletions

View File

@ -226,8 +226,12 @@ namespace {
/// If the source value number is defined by a commutable instruction and
/// its other operand is coalesced to the copy dest register, see if we
/// can transform the copy into a noop by commuting the definition.
/// This returns true if an interval was modified.
bool removeCopyByCommutingDef(const CoalescerPair &CP,MachineInstr *CopyMI);
/// This returns a pair of two flags:
/// - the first element is true if an interval was modified,
/// - the second element is true if the destination interval needs
/// to be shrunk after deleting the copy.
std::pair<bool,bool> removeCopyByCommutingDef(const CoalescerPair &CP,
MachineInstr *CopyMI);
/// We found a copy which can be moved to its less frequent predecessor.
bool removePartialRedundancy(const CoalescerPair &CP, MachineInstr &CopyMI);
@ -686,20 +690,32 @@ bool RegisterCoalescer::hasOtherReachingDefs(LiveInterval &IntA,
/// Copy segments with value number @p SrcValNo from liverange @p Src to live
/// range @Dst and use value number @p DstValNo there.
static bool addSegmentsWithValNo(LiveRange &Dst, VNInfo *DstValNo,
const LiveRange &Src, const VNInfo *SrcValNo) {
static std::pair<bool,bool>
addSegmentsWithValNo(LiveRange &Dst, VNInfo *DstValNo, const LiveRange &Src,
const VNInfo *SrcValNo) {
bool Changed = false;
bool MergedWithDead = false;
for (const LiveRange::Segment &S : Src.segments) {
if (S.valno != SrcValNo)
continue;
Dst.addSegment(LiveRange::Segment(S.start, S.end, DstValNo));
// This is adding a segment from Src that ends in a copy that is about
// to be removed. This segment is going to be merged with a pre-existing
// segment in Dst. This works, except in cases when the corresponding
// segment in Dst is dead. For example: adding [192r,208r:1) from Src
// to [208r,208d:1) in Dst would create [192r,208d:1) in Dst.
// Recognized such cases, so that the segments can be shrunk.
LiveRange::Segment Added = LiveRange::Segment(S.start, S.end, DstValNo);
LiveRange::Segment &Merged = *Dst.addSegment(Added);
if (Merged.end.isDead())
MergedWithDead = true;
Changed = true;
}
return Changed;
return std::make_pair(Changed, MergedWithDead);
}
bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
MachineInstr *CopyMI) {
std::pair<bool,bool>
RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
MachineInstr *CopyMI) {
assert(!CP.isPhys());
LiveInterval &IntA =
@ -737,19 +753,19 @@ bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
VNInfo *AValNo = IntA.getVNInfoAt(CopyIdx.getRegSlot(true));
assert(AValNo && !AValNo->isUnused() && "COPY source not live");
if (AValNo->isPHIDef())
return false;
return { false, false };
MachineInstr *DefMI = LIS->getInstructionFromIndex(AValNo->def);
if (!DefMI)
return false;
return { false, false };
if (!DefMI->isCommutable())
return false;
return { false, false };
// If DefMI is a two-address instruction then commuting it will change the
// destination register.
int DefIdx = DefMI->findRegisterDefOperandIdx(IntA.reg);
assert(DefIdx != -1);
unsigned UseOpIdx;
if (!DefMI->isRegTiedToUseOperand(DefIdx, &UseOpIdx))
return false;
return { false, false };
// FIXME: The code below tries to commute 'UseOpIdx' operand with some other
// commutable operand which is expressed by 'CommuteAnyOperandIndex'value
@ -762,17 +778,17 @@ bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
// op#2<->op#3) of commute transformation should be considered/tried here.
unsigned NewDstIdx = TargetInstrInfo::CommuteAnyOperandIndex;
if (!TII->findCommutedOpIndices(*DefMI, UseOpIdx, NewDstIdx))
return false;
return { false, false };
MachineOperand &NewDstMO = DefMI->getOperand(NewDstIdx);
unsigned NewReg = NewDstMO.getReg();
if (NewReg != IntB.reg || !IntB.Query(AValNo->def).isKill())
return false;
return { false, false };
// Make sure there are no other definitions of IntB that would reach the
// uses which the new definition can reach.
if (hasOtherReachingDefs(IntA, IntB, AValNo, BValNo))
return false;
return { false, false };
// If some of the uses of IntA.reg is already coalesced away, return false.
// It's not possible to determine whether it's safe to perform the coalescing.
@ -785,7 +801,7 @@ bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
continue;
// If this use is tied to a def, we can't rewrite the register.
if (UseMI->isRegTiedToDefOperand(OpNo))
return false;
return { false, false };
}
LLVM_DEBUG(dbgs() << "\tremoveCopyByCommutingDef: " << AValNo->def << '\t'
@ -797,11 +813,11 @@ bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
MachineInstr *NewMI =
TII->commuteInstruction(*DefMI, false, UseOpIdx, NewDstIdx);
if (!NewMI)
return false;
return { false, false };
if (TargetRegisterInfo::isVirtualRegister(IntA.reg) &&
TargetRegisterInfo::isVirtualRegister(IntB.reg) &&
!MRI->constrainRegClass(IntB.reg, MRI->getRegClass(IntA.reg)))
return false;
return { false, false };
if (NewMI != DefMI) {
LIS->ReplaceMachineInstrInMaps(*DefMI, *NewMI);
MachineBasicBlock::iterator Pos = DefMI;
@ -875,6 +891,7 @@ bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
// Extend BValNo by merging in IntA live segments of AValNo. Val# definition
// is updated.
bool ShrinkB = false;
BumpPtrAllocator &Allocator = LIS->getVNInfoAllocator();
if (IntA.hasSubRanges() || IntB.hasSubRanges()) {
if (!IntA.hasSubRanges()) {
@ -890,26 +907,30 @@ bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
assert(ASubValNo != nullptr);
IntB.refineSubRanges(Allocator, SA.LaneMask,
[&Allocator,&SA,CopyIdx,ASubValNo](LiveInterval::SubRange &SR) {
[&Allocator,&SA,CopyIdx,ASubValNo,&ShrinkB]
(LiveInterval::SubRange &SR) {
VNInfo *BSubValNo = SR.empty()
? SR.getNextValue(CopyIdx, Allocator)
: SR.getVNInfoAt(CopyIdx);
assert(BSubValNo != nullptr);
if (addSegmentsWithValNo(SR, BSubValNo, SA, ASubValNo))
auto P = addSegmentsWithValNo(SR, BSubValNo, SA, ASubValNo);
ShrinkB |= P.second;
if (P.first)
BSubValNo->def = ASubValNo->def;
});
}
}
BValNo->def = AValNo->def;
addSegmentsWithValNo(IntB, BValNo, IntA, AValNo);
auto P = addSegmentsWithValNo(IntB, BValNo, IntA, AValNo);
ShrinkB |= P.second;
LLVM_DEBUG(dbgs() << "\t\textended: " << IntB << '\n');
LIS->removeVRegDefAt(IntA, AValNo->def);
LLVM_DEBUG(dbgs() << "\t\ttrimmed: " << IntA << '\n');
++numCommutes;
return true;
return { true, ShrinkB };
}
/// For copy B = A in BB2, if A is defined by A = B in BB0 which is a
@ -1795,9 +1816,18 @@ bool RegisterCoalescer::joinCopy(MachineInstr *CopyMI, bool &Again) {
// If we can eliminate the copy without merging the live segments, do so
// now.
if (!CP.isPartial() && !CP.isPhys()) {
if (adjustCopiesBackFrom(CP, CopyMI) ||
removeCopyByCommutingDef(CP, CopyMI)) {
bool Changed = adjustCopiesBackFrom(CP, CopyMI);
bool Shrink = false;
if (!Changed)
std::tie(Changed, Shrink) = removeCopyByCommutingDef(CP, CopyMI);
if (Changed) {
deleteInstr(CopyMI);
if (Shrink) {
unsigned DstReg = CP.isFlipped() ? CP.getSrcReg() : CP.getDstReg();
LiveInterval &DstLI = LIS->getInterval(DstReg);
shrinkToUses(&DstLI);
LLVM_DEBUG(dbgs() << "\t\tshrunk: " << DstLI << '\n');
}
LLVM_DEBUG(dbgs() << "\tTrivial!\n");
return true;
}

View File

@ -0,0 +1,48 @@
; RUN: llc -mtriple=s390x-linux-gnu -mcpu=z10 -verify-machineinstrs -systemz-subreg-liveness < %s | FileCheck %s
; Check for successful compilation.
; CHECK: lgfrl %r1, g_65
target datalayout = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"
target triple = "s390x-ibm-linux"
@g_65 = external global i32, align 4
; Function Attrs: nounwind
define void @main() #0 {
bb:
br label %bb1
bb1: ; preds = %bb
%tmp = load i32, i32* @g_65, align 4
%tmp2 = sext i32 %tmp to i64
%tmp3 = shl i32 %tmp, 16
%tmp4 = ashr exact i32 %tmp3, 16
%tmp5 = shl i32 %tmp4, 0
%tmp6 = zext i32 %tmp5 to i64
%tmp7 = shl i64 %tmp6, 48
%tmp8 = ashr exact i64 %tmp7, 48
br i1 undef, label %bb12, label %bb9
bb9: ; preds = %bb1
%tmp10 = select i1 undef, i64 0, i64 %tmp2
%tmp11 = add nsw i64 %tmp10, %tmp8
br label %bb12
bb12: ; preds = %bb9, %bb1
%tmp13 = phi i64 [ %tmp11, %bb9 ], [ %tmp8, %bb1 ]
%tmp14 = trunc i64 %tmp13 to i32
%tmp15 = and i32 %tmp14, 255
%tmp16 = shl i32 %tmp15, 0
%tmp17 = trunc i32 %tmp16 to i8
%tmp18 = icmp eq i8 %tmp17, 0
br i1 %tmp18, label %bb20, label %bb19
bb19: ; preds = %bb12
unreachable
bb20: ; preds = %bb12
unreachable
}
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="z10" "unsafe-fp-math"="false" "use-soft-float"="false" }