forked from OSchip/llvm-project
[RegisterCoalescer] Shrink to uses if needed after removeCopyByCommutingDef
llvm-svn: 339912
This commit is contained in:
parent
2f5cf8511a
commit
17143f6111
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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" }
|
Loading…
Reference in New Issue