123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- //===- CSEInfo.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
- //
- //===----------------------------------------------------------------------===//
- //
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
- #include "llvm/CodeGen/MachineRegisterInfo.h"
- #include "llvm/InitializePasses.h"
- #include "llvm/Support/Error.h"
- #define DEBUG_TYPE "cseinfo"
- using namespace llvm;
- char llvm::GISelCSEAnalysisWrapperPass::ID = 0;
- GISelCSEAnalysisWrapperPass::GISelCSEAnalysisWrapperPass()
- : MachineFunctionPass(ID) {
- initializeGISelCSEAnalysisWrapperPassPass(*PassRegistry::getPassRegistry());
- }
- INITIALIZE_PASS_BEGIN(GISelCSEAnalysisWrapperPass, DEBUG_TYPE,
- "Analysis containing CSE Info", false, true)
- INITIALIZE_PASS_END(GISelCSEAnalysisWrapperPass, DEBUG_TYPE,
- "Analysis containing CSE Info", false, true)
- /// -------- UniqueMachineInstr -------------//
- void UniqueMachineInstr::Profile(FoldingSetNodeID &ID) {
- GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI);
- }
- /// -----------------------------------------
- /// --------- CSEConfigFull ---------- ///
- bool CSEConfigFull::shouldCSEOpc(unsigned Opc) {
- switch (Opc) {
- default:
- break;
- case TargetOpcode::G_ADD:
- case TargetOpcode::G_AND:
- case TargetOpcode::G_ASHR:
- case TargetOpcode::G_LSHR:
- case TargetOpcode::G_MUL:
- case TargetOpcode::G_OR:
- case TargetOpcode::G_SHL:
- case TargetOpcode::G_SUB:
- case TargetOpcode::G_XOR:
- case TargetOpcode::G_UDIV:
- case TargetOpcode::G_SDIV:
- case TargetOpcode::G_UREM:
- case TargetOpcode::G_SREM:
- case TargetOpcode::G_CONSTANT:
- case TargetOpcode::G_FCONSTANT:
- case TargetOpcode::G_IMPLICIT_DEF:
- case TargetOpcode::G_ZEXT:
- case TargetOpcode::G_SEXT:
- case TargetOpcode::G_ANYEXT:
- case TargetOpcode::G_UNMERGE_VALUES:
- case TargetOpcode::G_TRUNC:
- case TargetOpcode::G_PTR_ADD:
- case TargetOpcode::G_EXTRACT:
- return true;
- }
- return false;
- }
- bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc) {
- return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_IMPLICIT_DEF;
- }
- std::unique_ptr<CSEConfigBase>
- llvm::getStandardCSEConfigForOpt(CodeGenOpt::Level Level) {
- std::unique_ptr<CSEConfigBase> Config;
- if (Level == CodeGenOpt::None)
- Config = std::make_unique<CSEConfigConstantOnly>();
- else
- Config = std::make_unique<CSEConfigFull>();
- return Config;
- }
- /// -----------------------------------------
- /// -------- GISelCSEInfo -------------//
- void GISelCSEInfo::setMF(MachineFunction &MF) {
- this->MF = &MF;
- this->MRI = &MF.getRegInfo();
- }
- GISelCSEInfo::~GISelCSEInfo() {}
- bool GISelCSEInfo::isUniqueMachineInstValid(
- const UniqueMachineInstr &UMI) const {
- // Should we check here and assert that the instruction has been fully
- // constructed?
- // FIXME: Any other checks required to be done here? Remove this method if
- // none.
- return true;
- }
- void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) {
- bool Removed = CSEMap.RemoveNode(UMI);
- (void)Removed;
- assert(Removed && "Invalidation called on invalid UMI");
- // FIXME: Should UMI be deallocated/destroyed?
- }
- UniqueMachineInstr *GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID,
- MachineBasicBlock *MBB,
- void *&InsertPos) {
- auto *Node = CSEMap.FindNodeOrInsertPos(ID, InsertPos);
- if (Node) {
- if (!isUniqueMachineInstValid(*Node)) {
- invalidateUniqueMachineInstr(Node);
- return nullptr;
- }
- if (Node->MI->getParent() != MBB)
- return nullptr;
- }
- return Node;
- }
- void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI, void *InsertPos) {
- handleRecordedInsts();
- assert(UMI);
- UniqueMachineInstr *MaybeNewNode = UMI;
- if (InsertPos)
- CSEMap.InsertNode(UMI, InsertPos);
- else
- MaybeNewNode = CSEMap.GetOrInsertNode(UMI);
- if (MaybeNewNode != UMI) {
- // A similar node exists in the folding set. Let's ignore this one.
- return;
- }
- assert(InstrMapping.count(UMI->MI) == 0 &&
- "This instruction should not be in the map");
- InstrMapping[UMI->MI] = MaybeNewNode;
- }
- UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) {
- assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node");
- auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI);
- return Node;
- }
- void GISelCSEInfo::insertInstr(MachineInstr *MI, void *InsertPos) {
- assert(MI);
- // If it exists in temporary insts, remove it.
- TemporaryInsts.remove(MI);
- auto *Node = getUniqueInstrForMI(MI);
- insertNode(Node, InsertPos);
- }
- MachineInstr *GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID,
- MachineBasicBlock *MBB,
- void *&InsertPos) {
- handleRecordedInsts();
- if (auto *Inst = getNodeIfExists(ID, MBB, InsertPos)) {
- LLVM_DEBUG(dbgs() << "CSEInfo::Found Instr " << *Inst->MI;);
- return const_cast<MachineInstr *>(Inst->MI);
- }
- return nullptr;
- }
- void GISelCSEInfo::countOpcodeHit(unsigned Opc) {
- #ifndef NDEBUG
- if (OpcodeHitTable.count(Opc))
- OpcodeHitTable[Opc] += 1;
- else
- OpcodeHitTable[Opc] = 1;
- #endif
- // Else do nothing.
- }
- void GISelCSEInfo::recordNewInstruction(MachineInstr *MI) {
- if (shouldCSE(MI->getOpcode())) {
- TemporaryInsts.insert(MI);
- LLVM_DEBUG(dbgs() << "CSEInfo::Recording new MI " << *MI);
- }
- }
- void GISelCSEInfo::handleRecordedInst(MachineInstr *MI) {
- assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE");
- auto *UMI = InstrMapping.lookup(MI);
- LLVM_DEBUG(dbgs() << "CSEInfo::Handling recorded MI " << *MI);
- if (UMI) {
- // Invalidate this MI.
- invalidateUniqueMachineInstr(UMI);
- InstrMapping.erase(MI);
- }
- /// Now insert the new instruction.
- if (UMI) {
- /// We'll reuse the same UniqueMachineInstr to avoid the new
- /// allocation.
- *UMI = UniqueMachineInstr(MI);
- insertNode(UMI, nullptr);
- } else {
- /// This is a new instruction. Allocate a new UniqueMachineInstr and
- /// Insert.
- insertInstr(MI);
- }
- }
- void GISelCSEInfo::handleRemoveInst(MachineInstr *MI) {
- if (auto *UMI = InstrMapping.lookup(MI)) {
- invalidateUniqueMachineInstr(UMI);
- InstrMapping.erase(MI);
- }
- TemporaryInsts.remove(MI);
- }
- void GISelCSEInfo::handleRecordedInsts() {
- while (!TemporaryInsts.empty()) {
- auto *MI = TemporaryInsts.pop_back_val();
- handleRecordedInst(MI);
- }
- }
- bool GISelCSEInfo::shouldCSE(unsigned Opc) const {
- assert(CSEOpt.get() && "CSEConfig not set");
- return CSEOpt->shouldCSEOpc(Opc);
- }
- void GISelCSEInfo::erasingInstr(MachineInstr &MI) { handleRemoveInst(&MI); }
- void GISelCSEInfo::createdInstr(MachineInstr &MI) { recordNewInstruction(&MI); }
- void GISelCSEInfo::changingInstr(MachineInstr &MI) {
- // For now, perform erase, followed by insert.
- erasingInstr(MI);
- createdInstr(MI);
- }
- void GISelCSEInfo::changedInstr(MachineInstr &MI) { changingInstr(MI); }
- void GISelCSEInfo::analyze(MachineFunction &MF) {
- setMF(MF);
- for (auto &MBB : MF) {
- if (MBB.empty())
- continue;
- for (MachineInstr &MI : MBB) {
- if (!shouldCSE(MI.getOpcode()))
- continue;
- LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI);
- insertInstr(&MI);
- }
- }
- }
- void GISelCSEInfo::releaseMemory() {
- print();
- CSEMap.clear();
- InstrMapping.clear();
- UniqueInstrAllocator.Reset();
- TemporaryInsts.clear();
- CSEOpt.reset();
- MRI = nullptr;
- MF = nullptr;
- #ifndef NDEBUG
- OpcodeHitTable.clear();
- #endif
- }
- #ifndef NDEBUG
- static const char *stringify(const MachineInstr *MI, std::string &S) {
- raw_string_ostream OS(S);
- OS << *MI;
- return OS.str().c_str();
- }
- #endif
- Error GISelCSEInfo::verify() {
- #ifndef NDEBUG
- std::string S1, S2;
- handleRecordedInsts();
- // For each instruction in map from MI -> UMI,
- // Profile(MI) and make sure UMI is found for that profile.
- for (auto &It : InstrMapping) {
- FoldingSetNodeID TmpID;
- GISelInstProfileBuilder(TmpID, *MRI).addNodeID(It.first);
- void *InsertPos;
- UniqueMachineInstr *FoundNode =
- CSEMap.FindNodeOrInsertPos(TmpID, InsertPos);
- if (FoundNode != It.second)
- return createStringError(std::errc::not_supported,
- "CSEMap mismatch, InstrMapping has MIs without "
- "corresponding Nodes in CSEMap:\n%s",
- stringify(It.second->MI, S1));
- }
- // For every node in the CSEMap, make sure that the InstrMapping
- // points to it.
- for (const UniqueMachineInstr &UMI : CSEMap) {
- if (!InstrMapping.count(UMI.MI))
- return createStringError(std::errc::not_supported,
- "Node in CSE without InstrMapping:\n%s",
- stringify(UMI.MI, S1));
- if (InstrMapping[UMI.MI] != &UMI)
- return createStringError(std::make_error_code(std::errc::not_supported),
- "Mismatch in CSE mapping:\n%s\n%s",
- stringify(InstrMapping[UMI.MI]->MI, S1),
- stringify(UMI.MI, S2));
- }
- #endif
- return Error::success();
- }
- void GISelCSEInfo::print() {
- LLVM_DEBUG(for (auto &It
- : OpcodeHitTable) {
- dbgs() << "CSEInfo::CSE Hit for Opc " << It.first << " : " << It.second
- << "\n";
- };);
- }
- /// -----------------------------------------
- // ---- Profiling methods for FoldingSetNode --- //
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeID(const MachineInstr *MI) const {
- addNodeIDMBB(MI->getParent());
- addNodeIDOpcode(MI->getOpcode());
- for (auto &Op : MI->operands())
- addNodeIDMachineOperand(Op);
- addNodeIDFlag(MI->getFlags());
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDOpcode(unsigned Opc) const {
- ID.AddInteger(Opc);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDRegType(const LLT Ty) const {
- uint64_t Val = Ty.getUniqueRAWLLTData();
- ID.AddInteger(Val);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDRegType(const TargetRegisterClass *RC) const {
- ID.AddPointer(RC);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDRegType(const RegisterBank *RB) const {
- ID.AddPointer(RB);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDImmediate(int64_t Imm) const {
- ID.AddInteger(Imm);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDRegNum(Register Reg) const {
- ID.AddInteger(Reg);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDRegType(const Register Reg) const {
- addNodeIDMachineOperand(MachineOperand::CreateReg(Reg, false));
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDMBB(const MachineBasicBlock *MBB) const {
- ID.AddPointer(MBB);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDFlag(unsigned Flag) const {
- if (Flag)
- ID.AddInteger(Flag);
- return *this;
- }
- const GISelInstProfileBuilder &
- GISelInstProfileBuilder::addNodeIDReg(Register Reg) const {
- LLT Ty = MRI.getType(Reg);
- if (Ty.isValid())
- addNodeIDRegType(Ty);
- if (const RegClassOrRegBank &RCOrRB = MRI.getRegClassOrRegBank(Reg)) {
- if (const auto *RB = RCOrRB.dyn_cast<const RegisterBank *>())
- addNodeIDRegType(RB);
- else if (const auto *RC = RCOrRB.dyn_cast<const TargetRegisterClass *>())
- addNodeIDRegType(RC);
- }
- return *this;
- }
- const GISelInstProfileBuilder &GISelInstProfileBuilder::addNodeIDMachineOperand(
- const MachineOperand &MO) const {
- if (MO.isReg()) {
- Register Reg = MO.getReg();
- if (!MO.isDef())
- addNodeIDRegNum(Reg);
- // Profile the register properties.
- addNodeIDReg(Reg);
- assert(!MO.isImplicit() && "Unhandled case");
- } else if (MO.isImm())
- ID.AddInteger(MO.getImm());
- else if (MO.isCImm())
- ID.AddPointer(MO.getCImm());
- else if (MO.isFPImm())
- ID.AddPointer(MO.getFPImm());
- else if (MO.isPredicate())
- ID.AddInteger(MO.getPredicate());
- else
- llvm_unreachable("Unhandled operand type");
- // Handle other types
- return *this;
- }
- GISelCSEInfo &
- GISelCSEAnalysisWrapper::get(std::unique_ptr<CSEConfigBase> CSEOpt,
- bool Recompute) {
- if (!AlreadyComputed || Recompute) {
- Info.releaseMemory();
- Info.setCSEConfig(std::move(CSEOpt));
- Info.analyze(*MF);
- AlreadyComputed = true;
- }
- return Info;
- }
- void GISelCSEAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.setPreservesAll();
- MachineFunctionPass::getAnalysisUsage(AU);
- }
- bool GISelCSEAnalysisWrapperPass::runOnMachineFunction(MachineFunction &MF) {
- releaseMemory();
- Wrapper.setMF(MF);
- return false;
- }
|