#pragma once #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif //===- llvm/CodeGen/LiveRegUnits.h - Register Unit Set ----------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // /// \file /// A set of register units. It is intended for register liveness tracking. // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_LIVEREGUNITS_H #define LLVM_CODEGEN_LIVEREGUNITS_H #include "llvm/ADT/BitVector.h" #include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/MC/LaneBitmask.h" #include "llvm/MC/MCRegisterInfo.h" #include namespace llvm { class MachineInstr; class MachineBasicBlock; /// A set of register units used to track register liveness. class LiveRegUnits { const TargetRegisterInfo *TRI = nullptr; BitVector Units; public: /// Constructs a new empty LiveRegUnits set. LiveRegUnits() = default; /// Constructs and initialize an empty LiveRegUnits set. LiveRegUnits(const TargetRegisterInfo &TRI) { init(TRI); } /// For a machine instruction \p MI, adds all register units used in /// \p UsedRegUnits and defined or clobbered in \p ModifiedRegUnits. This is /// useful when walking over a range of instructions to track registers /// used or defined seperately. static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI) { for (ConstMIBundleOperands O(MI); O.isValid(); ++O) { if (O->isRegMask()) ModifiedRegUnits.addRegsInMask(O->getRegMask()); if (!O->isReg()) continue; Register Reg = O->getReg(); if (!Reg.isPhysical()) continue; if (O->isDef()) { // Some architectures (e.g. AArch64 XZR/WZR) have registers that are // constant and may be used as destinations to indicate the generated // value is discarded. No need to track such case as a def. if (!TRI->isConstantPhysReg(Reg)) ModifiedRegUnits.addReg(Reg); } else { assert(O->isUse() && "Reg operand not a def and not a use"); UsedRegUnits.addReg(Reg); } } } /// Initialize and clear the set. void init(const TargetRegisterInfo &TRI) { this->TRI = &TRI; Units.reset(); Units.resize(TRI.getNumRegUnits()); } /// Clears the set. void clear() { Units.reset(); } /// Returns true if the set is empty. bool empty() const { return Units.none(); } /// Adds register units covered by physical register \p Reg. void addReg(MCPhysReg Reg) { for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) Units.set(*Unit); } /// Adds register units covered by physical register \p Reg that are /// part of the lanemask \p Mask. void addRegMasked(MCPhysReg Reg, LaneBitmask Mask) { for (MCRegUnitMaskIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) { LaneBitmask UnitMask = (*Unit).second; if (UnitMask.none() || (UnitMask & Mask).any()) Units.set((*Unit).first); } } /// Removes all register units covered by physical register \p Reg. void removeReg(MCPhysReg Reg) { for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) Units.reset(*Unit); } /// Removes register units not preserved by the regmask \p RegMask. /// The regmask has the same format as the one in the RegMask machine operand. void removeRegsNotPreserved(const uint32_t *RegMask); /// Adds register units not preserved by the regmask \p RegMask. /// The regmask has the same format as the one in the RegMask machine operand. void addRegsInMask(const uint32_t *RegMask); /// Returns true if no part of physical register \p Reg is live. bool available(MCPhysReg Reg) const { for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) { if (Units.test(*Unit)) return false; } return true; } /// Updates liveness when stepping backwards over the instruction \p MI. /// This removes all register units defined or clobbered in \p MI and then /// adds the units used (as in use operands) in \p MI. void stepBackward(const MachineInstr &MI); /// Adds all register units used, defined or clobbered in \p MI. /// This is useful when walking over a range of instruction to find registers /// unused over the whole range. void accumulate(const MachineInstr &MI); /// Adds registers living out of block \p MBB. /// Live out registers are the union of the live-in registers of the successor /// blocks and pristine registers. Live out registers of the end block are the /// callee saved registers. void addLiveOuts(const MachineBasicBlock &MBB); /// Adds registers living into block \p MBB. void addLiveIns(const MachineBasicBlock &MBB); /// Adds all register units marked in the bitvector \p RegUnits. void addUnits(const BitVector &RegUnits) { Units |= RegUnits; } /// Removes all register units marked in the bitvector \p RegUnits. void removeUnits(const BitVector &RegUnits) { Units.reset(RegUnits); } /// Return the internal bitvector representation of the set. const BitVector &getBitVector() const { return Units; } private: /// Adds pristine registers. Pristine registers are callee saved registers /// that are unused in the function. void addPristines(const MachineFunction &MF); }; /// Returns an iterator range over all physical register and mask operands for /// \p MI and bundled instructions. This also skips any debug operands. inline iterator_range>> phys_regs_and_masks(const MachineInstr &MI) { std::function Pred = [](const MachineOperand &MOP) { return MOP.isRegMask() || (MOP.isReg() && !MOP.isDebug() && Register::isPhysicalRegister(MOP.getReg())); }; return make_filter_range(const_mi_bundle_ops(MI), Pred); } } // end namespace llvm #endif // LLVM_CODEGEN_LIVEREGUNITS_H #ifdef __GNUC__ #pragma GCC diagnostic pop #endif