
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
214 lines
6.3 KiB
C++
214 lines
6.3 KiB
C++
//===- RDFCopy.cpp --------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// RDF-based copy propagation.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "RDFCopy.h"
|
|
#include "RDFGraph.h"
|
|
#include "RDFLiveness.h"
|
|
#include "RDFRegisters.h"
|
|
#include "llvm/CodeGen/MachineDominators.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/TargetOpcodes.h"
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <utility>
|
|
|
|
using namespace llvm;
|
|
using namespace rdf;
|
|
|
|
#ifndef NDEBUG
|
|
static cl::opt<unsigned> CpLimit("rdf-cp-limit", cl::init(0), cl::Hidden);
|
|
static unsigned CpCount = 0;
|
|
#endif
|
|
|
|
bool CopyPropagation::interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) {
|
|
unsigned Opc = MI->getOpcode();
|
|
switch (Opc) {
|
|
case TargetOpcode::COPY: {
|
|
const MachineOperand &Dst = MI->getOperand(0);
|
|
const MachineOperand &Src = MI->getOperand(1);
|
|
RegisterRef DstR = DFG.makeRegRef(Dst.getReg(), Dst.getSubReg());
|
|
RegisterRef SrcR = DFG.makeRegRef(Src.getReg(), Src.getSubReg());
|
|
assert(TargetRegisterInfo::isPhysicalRegister(DstR.Reg));
|
|
assert(TargetRegisterInfo::isPhysicalRegister(SrcR.Reg));
|
|
const TargetRegisterInfo &TRI = DFG.getTRI();
|
|
if (TRI.getMinimalPhysRegClass(DstR.Reg) !=
|
|
TRI.getMinimalPhysRegClass(SrcR.Reg))
|
|
return false;
|
|
EM.insert(std::make_pair(DstR, SrcR));
|
|
return true;
|
|
}
|
|
case TargetOpcode::REG_SEQUENCE:
|
|
llvm_unreachable("Unexpected REG_SEQUENCE");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CopyPropagation::recordCopy(NodeAddr<StmtNode*> SA, EqualityMap &EM) {
|
|
CopyMap.insert(std::make_pair(SA.Id, EM));
|
|
Copies.push_back(SA.Id);
|
|
}
|
|
|
|
bool CopyPropagation::scanBlock(MachineBasicBlock *B) {
|
|
bool Changed = false;
|
|
NodeAddr<BlockNode*> BA = DFG.findBlock(B);
|
|
|
|
for (NodeAddr<InstrNode*> IA : BA.Addr->members(DFG)) {
|
|
if (DFG.IsCode<NodeAttrs::Stmt>(IA)) {
|
|
NodeAddr<StmtNode*> SA = IA;
|
|
EqualityMap EM;
|
|
if (interpretAsCopy(SA.Addr->getCode(), EM))
|
|
recordCopy(SA, EM);
|
|
}
|
|
}
|
|
|
|
MachineDomTreeNode *N = MDT.getNode(B);
|
|
for (auto I : *N)
|
|
Changed |= scanBlock(I->getBlock());
|
|
|
|
return Changed;
|
|
}
|
|
|
|
NodeId CopyPropagation::getLocalReachingDef(RegisterRef RefRR,
|
|
NodeAddr<InstrNode*> IA) {
|
|
NodeAddr<RefNode*> RA = L.getNearestAliasedRef(RefRR, IA);
|
|
if (RA.Id != 0) {
|
|
if (RA.Addr->getKind() == NodeAttrs::Def)
|
|
return RA.Id;
|
|
assert(RA.Addr->getKind() == NodeAttrs::Use);
|
|
if (NodeId RD = RA.Addr->getReachingDef())
|
|
return RD;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool CopyPropagation::run() {
|
|
scanBlock(&DFG.getMF().front());
|
|
|
|
if (trace()) {
|
|
dbgs() << "Copies:\n";
|
|
for (NodeId I : Copies) {
|
|
dbgs() << "Instr: " << *DFG.addr<StmtNode*>(I).Addr->getCode();
|
|
dbgs() << " eq: {";
|
|
for (auto J : CopyMap[I])
|
|
dbgs() << ' ' << Print<RegisterRef>(J.first, DFG) << '='
|
|
<< Print<RegisterRef>(J.second, DFG);
|
|
dbgs() << " }\n";
|
|
}
|
|
}
|
|
|
|
bool Changed = false;
|
|
#ifndef NDEBUG
|
|
bool HasLimit = CpLimit.getNumOccurrences() > 0;
|
|
#endif
|
|
|
|
auto MinPhysReg = [this] (RegisterRef RR) -> unsigned {
|
|
const TargetRegisterInfo &TRI = DFG.getTRI();
|
|
const TargetRegisterClass &RC = *TRI.getMinimalPhysRegClass(RR.Reg);
|
|
if ((RC.LaneMask & RR.Mask) == RC.LaneMask)
|
|
return RR.Reg;
|
|
for (MCSubRegIndexIterator S(RR.Reg, &TRI); S.isValid(); ++S)
|
|
if (RR.Mask == TRI.getSubRegIndexLaneMask(S.getSubRegIndex()))
|
|
return S.getSubReg();
|
|
llvm_unreachable("Should have found a register");
|
|
return 0;
|
|
};
|
|
|
|
for (NodeId C : Copies) {
|
|
#ifndef NDEBUG
|
|
if (HasLimit && CpCount >= CpLimit)
|
|
break;
|
|
#endif
|
|
auto SA = DFG.addr<InstrNode*>(C);
|
|
auto FS = CopyMap.find(SA.Id);
|
|
if (FS == CopyMap.end())
|
|
continue;
|
|
|
|
EqualityMap &EM = FS->second;
|
|
for (NodeAddr<DefNode*> DA : SA.Addr->members_if(DFG.IsDef, DFG)) {
|
|
RegisterRef DR = DA.Addr->getRegRef(DFG);
|
|
auto FR = EM.find(DR);
|
|
if (FR == EM.end())
|
|
continue;
|
|
RegisterRef SR = FR->second;
|
|
if (DR == SR)
|
|
continue;
|
|
|
|
NodeId AtCopy = getLocalReachingDef(SR, SA);
|
|
|
|
for (NodeId N = DA.Addr->getReachedUse(), NextN; N; N = NextN) {
|
|
auto UA = DFG.addr<UseNode*>(N);
|
|
NextN = UA.Addr->getSibling();
|
|
uint16_t F = UA.Addr->getFlags();
|
|
if ((F & NodeAttrs::PhiRef) || (F & NodeAttrs::Fixed))
|
|
continue;
|
|
if (UA.Addr->getRegRef(DFG) != DR)
|
|
continue;
|
|
|
|
NodeAddr<InstrNode*> IA = UA.Addr->getOwner(DFG);
|
|
assert(DFG.IsCode<NodeAttrs::Stmt>(IA));
|
|
NodeId AtUse = getLocalReachingDef(SR, IA);
|
|
if (AtCopy != AtUse)
|
|
continue;
|
|
|
|
MachineOperand &Op = UA.Addr->getOp();
|
|
if (Op.isTied())
|
|
continue;
|
|
if (trace()) {
|
|
dbgs() << "Can replace " << Print<RegisterRef>(DR, DFG)
|
|
<< " with " << Print<RegisterRef>(SR, DFG) << " in "
|
|
<< *NodeAddr<StmtNode*>(IA).Addr->getCode();
|
|
}
|
|
|
|
unsigned NewReg = MinPhysReg(SR);
|
|
Op.setReg(NewReg);
|
|
Op.setSubReg(0);
|
|
DFG.unlinkUse(UA, false);
|
|
if (AtCopy != 0) {
|
|
UA.Addr->linkToDef(UA.Id, DFG.addr<DefNode*>(AtCopy));
|
|
} else {
|
|
UA.Addr->setReachingDef(0);
|
|
UA.Addr->setSibling(0);
|
|
}
|
|
|
|
Changed = true;
|
|
#ifndef NDEBUG
|
|
if (HasLimit && CpCount >= CpLimit)
|
|
break;
|
|
CpCount++;
|
|
#endif
|
|
|
|
auto FC = CopyMap.find(IA.Id);
|
|
if (FC != CopyMap.end()) {
|
|
// Update the EM map in the copy's entry.
|
|
auto &M = FC->second;
|
|
for (auto &J : M) {
|
|
if (J.second != DR)
|
|
continue;
|
|
J.second = SR;
|
|
break;
|
|
}
|
|
}
|
|
} // for (N in reached-uses)
|
|
} // for (DA in defs)
|
|
} // for (C in Copies)
|
|
|
|
return Changed;
|
|
}
|