63                             cl::desc(
"The page size of the target in bytes"),
 
   67    "imp-null-max-insts-to-consider",
 
   68    cl::desc(
"The max number of instructions to consider hoisting loads over " 
   69             "(the algorithm is quadratic over this number)"),
 
   72#define DEBUG_TYPE "implicit-null-checks" 
   75          "Number of explicit null checks made implicit");
 
   92  struct DependenceResult {
 
   99    std::optional<ArrayRef<MachineInstr *>::iterator> PotentialDependence;
 
  104        : CanReorder(CanReorder), PotentialDependence(PotentialDependence) {
 
  105      assert((!PotentialDependence || CanReorder) &&
 
  106             "!CanReorder && PotentialDependence.hasValue() not allowed!");
 
  115  DependenceResult computeDependence(
const MachineInstr *
MI,
 
  121    MachineInstr *MemOperation;
 
  124    MachineInstr *CheckOperation;
 
  127    MachineBasicBlock *CheckBlock;
 
  130    MachineBasicBlock *NotNullSucc;
 
  133    MachineBasicBlock *NullSucc;
 
  137    MachineInstr *OnlyDependency;
 
  140    explicit NullCheck(MachineInstr *memOperation, MachineInstr *checkOperation,
 
  141                       MachineBasicBlock *checkBlock,
 
  142                       MachineBasicBlock *notNullSucc,
 
  143                       MachineBasicBlock *nullSucc,
 
  144                       MachineInstr *onlyDependency)
 
  145        : MemOperation(memOperation), CheckOperation(checkOperation),
 
  146          CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc),
 
  147          OnlyDependency(onlyDependency) {}
 
  149    MachineInstr *getMemOperation()
 const { 
return MemOperation; }
 
  151    MachineInstr *getCheckOperation()
 const { 
return CheckOperation; }
 
  153    MachineBasicBlock *getCheckBlock()
 const { 
return CheckBlock; }
 
  155    MachineBasicBlock *getNotNullSucc()
 const { 
return NotNullSucc; }
 
  157    MachineBasicBlock *getNullSucc()
 const { 
return NullSucc; }
 
  159    MachineInstr *getOnlyDependency()
 const { 
return OnlyDependency; }
 
  162  const TargetInstrInfo *TII = 
nullptr;
 
  163  const TargetRegisterInfo *TRI = 
nullptr;
 
  165  MachineFrameInfo *MFI = 
nullptr;
 
  167  bool analyzeBlockForNullChecks(MachineBasicBlock &
MBB,
 
  168                                 SmallVectorImpl<NullCheck> &NullCheckList);
 
  169  MachineInstr *insertFaultingInstr(MachineInstr *
MI, MachineBasicBlock *
MBB,
 
  170                                    MachineBasicBlock *HandlerMBB);
 
  176    AR_WillAliasEverything
 
  182  AliasResult areMemoryOpsAliased(
const MachineInstr &
MI,
 
  183                                  const MachineInstr *PrevMI) 
const;
 
  185  enum SuitabilityResult {
 
  197  SuitabilityResult isSuitableMemoryOp(
const MachineInstr &
MI,
 
  204  bool canDependenceHoistingClobberLiveIns(MachineInstr *DependenceMI,
 
  205                                           MachineBasicBlock *NullSucc);
 
  210  bool canHoistInst(MachineInstr *FaultingMI,
 
  212                    MachineBasicBlock *NullSucc, MachineInstr *&Dependence);
 
  217  ImplicitNullChecks() : MachineFunctionPass(ID) {
 
  221  bool runOnMachineFunction(MachineFunction &MF) 
override;
 
  223  void getAnalysisUsage(AnalysisUsage &AU)
 const override {
 
  228  MachineFunctionProperties getRequiredProperties()
 const override {
 
  229    return MachineFunctionProperties().setNoVRegs();
 
  236  if (
MI->isCall() || 
MI->mayRaiseFPException() ||
 
  237      MI->hasUnmodeledSideEffects())
 
  239  auto IsRegMask = [](
const MachineOperand &MO) { 
return MO.isRegMask(); };
 
  243         "Calls were filtered out above!");
 
  245  auto IsUnordered = [](MachineMemOperand *MMO) { 
return MMO->isUnordered(); };
 
  249ImplicitNullChecks::DependenceResult
 
  250ImplicitNullChecks::computeDependence(
const MachineInstr *
MI,
 
  255  std::optional<ArrayRef<MachineInstr *>::iterator> Dep;
 
  258    if (canReorder(*
I, 
MI))
 
  261    if (Dep == std::nullopt) {
 
  266      return {
false, std::nullopt};
 
  273bool ImplicitNullChecks::canReorder(
const MachineInstr *
A,
 
  274                                    const MachineInstr *
B) {
 
  275  assert(canHandle(
A) && canHandle(
B) && 
"Precondition!");
 
  281  for (
const auto &MOA : 
A->operands()) {
 
  282    if (!(MOA.isReg() && MOA.getReg()))
 
  286    for (
const auto &MOB : 
B->operands()) {
 
  287      if (!(MOB.isReg() && MOB.getReg()))
 
  292      if (
TRI->regsOverlap(RegA, RegB) && (MOA.isDef() || MOB.isDef()))
 
  300bool ImplicitNullChecks::runOnMachineFunction(MachineFunction &MF) {
 
  304  AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
 
  309    analyzeBlockForNullChecks(
MBB, NullCheckList);
 
  311  if (!NullCheckList.
empty())
 
  312    rewriteNullChecks(NullCheckList);
 
  314  return !NullCheckList.
empty();
 
  322    if (
MBB->isLiveIn(*AR))
 
 
  327ImplicitNullChecks::AliasResult
 
  328ImplicitNullChecks::areMemoryOpsAliased(
const MachineInstr &
MI,
 
  329                                        const MachineInstr *PrevMI)
 const {
 
  338  if (
MI.memoperands_empty())
 
  339    return MI.mayStore() ? AR_WillAliasEverything : AR_MayAlias;
 
  341    return PrevMI->
mayStore() ? AR_WillAliasEverything : AR_MayAlias;
 
  343  for (MachineMemOperand *MMO1 : 
MI.memoperands()) {
 
  346    assert(MMO1->getValue() && 
"MMO1 should have a Value!");
 
  347    for (MachineMemOperand *MMO2 : PrevMI->
memoperands()) {
 
  348      if (
const PseudoSourceValue *PSV = MMO2->getPseudoValue()) {
 
  349        if (PSV->mayAlias(MFI))
 
  362ImplicitNullChecks::SuitabilityResult
 
  363ImplicitNullChecks::isSuitableMemoryOp(
const MachineInstr &
MI,
 
  368  if (
MI.getDesc().getNumDefs() > 1)
 
  369   return SR_Unsuitable;
 
  371  if (!
MI.mayLoadOrStore() || 
MI.isPredicable())
 
  372    return SR_Unsuitable;
 
  373  auto AM = 
TII->getAddrModeFromMemoryOp(
MI, 
TRI);
 
  374  if (!AM || AM->Form != ExtAddrMode::Formula::Basic)
 
  375    return SR_Unsuitable;
 
  378  int64_t Displacement = 
AddrMode.Displacement;
 
  382  if (BaseReg != PointerReg && ScaledReg != PointerReg)
 
  383    return SR_Unsuitable;
 
  384  const MachineRegisterInfo &
MRI = 
MI.getMF()->getRegInfo();
 
  385  unsigned PointerRegSizeInBits = 
TRI->getRegSizeInBits(PointerReg, 
MRI);
 
  389       TRI->getRegSizeInBits(BaseReg, 
MRI) != PointerRegSizeInBits) ||
 
  391       TRI->getRegSizeInBits(ScaledReg, 
MRI) != PointerRegSizeInBits))
 
  392    return SR_Unsuitable;
 
  396  auto CalculateDisplacementFromAddrMode = [&](
Register RegUsedInAddr,
 
  397                                               int64_t Multiplier) {
 
  403    assert(Multiplier && 
"expected to be non-zero!");
 
  404    MachineInstr *ModifyingMI = 
nullptr;
 
  406         It != 
MI.getParent()->
rend(); It++) {
 
  407      const MachineInstr *CurrMI = &*It;
 
  409        ModifyingMI = 
const_cast<MachineInstr *
>(CurrMI);
 
  418    if (!
TII->getConstValDefinedInReg(*ModifyingMI, RegUsedInAddr, ImmVal))
 
  425    assert(MultiplierC.isStrictlyPositive() &&
 
  426           "expected to be a positive value!");
 
  430    APInt Product = ImmValC.smul_ov(MultiplierC, IsOverflow);
 
  433    APInt DisplacementC(64, Displacement, 
true );
 
  434    DisplacementC = Product.
sadd_ov(DisplacementC, IsOverflow);
 
  439    if (DisplacementC.getActiveBits() > 64)
 
  441    Displacement = DisplacementC.getSExtValue();
 
  447  bool BaseRegIsConstVal = 
false, ScaledRegIsConstVal = 
false;
 
  448  if (CalculateDisplacementFromAddrMode(BaseReg, 1))
 
  449    BaseRegIsConstVal = 
true;
 
  450  if (CalculateDisplacementFromAddrMode(ScaledReg, 
AddrMode.Scale))
 
  451    ScaledRegIsConstVal = 
true;
 
  458  if ((BaseReg && BaseReg != PointerReg && !BaseRegIsConstVal) ||
 
  459      (ScaledReg && ScaledReg != PointerReg && !ScaledRegIsConstVal))
 
  460    return SR_Unsuitable;
 
  465    return SR_Unsuitable;
 
  468  for (
auto *PrevMI : PrevInsts) {
 
  469    AliasResult AR = areMemoryOpsAliased(
MI, PrevMI);
 
  470    if (AR == AR_WillAliasEverything)
 
  471      return SR_Impossible;
 
  472    if (AR == AR_MayAlias)
 
  473      return SR_Unsuitable;
 
  478bool ImplicitNullChecks::canDependenceHoistingClobberLiveIns(
 
  479    MachineInstr *DependenceMI, MachineBasicBlock *NullSucc) {
 
  480  for (
const auto &DependenceMO : DependenceMI->
operands()) {
 
  481    if (!(DependenceMO.isReg() && DependenceMO.getReg()))
 
  510bool ImplicitNullChecks::canHoistInst(MachineInstr *FaultingMI,
 
  512                                      MachineBasicBlock *NullSucc,
 
  513                                      MachineInstr *&Dependence) {
 
  514  auto DepResult = computeDependence(FaultingMI, InstsSeenSoFar);
 
  515  if (!DepResult.CanReorder)
 
  518  if (!DepResult.PotentialDependence) {
 
  519    Dependence = 
nullptr;
 
  523  auto DependenceItr = *DepResult.PotentialDependence;
 
  524  auto *DependenceMI = *DependenceItr;
 
  531  assert(canHandle(DependenceMI) && 
"Should never have reached here!");
 
  535  if (canDependenceHoistingClobberLiveIns(DependenceMI, NullSucc))
 
  539      computeDependence(DependenceMI, {InstsSeenSoFar.
begin(), DependenceItr});
 
  541  if (!DepDepResult.CanReorder || DepDepResult.PotentialDependence)
 
  544  Dependence = DependenceMI;
 
  551bool ImplicitNullChecks::analyzeBlockForNullChecks(
 
  552    MachineBasicBlock &
MBB, SmallVectorImpl<NullCheck> &NullCheckList) {
 
  553  using MachineBranchPredicate = TargetInstrInfo::MachineBranchPredicate;
 
  555  MDNode *BranchMD = 
nullptr;
 
  557    BranchMD = BB->getTerminator()->getMetadata(LLVMContext::MD_make_implicit);
 
  562  MachineBranchPredicate MBP;
 
  564  if (
TII->analyzeBranchPredicate(
MBB, MBP, 
true))
 
  568  if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&
 
  569        (MBP.Predicate == MachineBranchPredicate::PRED_NE ||
 
  570         MBP.Predicate == MachineBranchPredicate::PRED_EQ)))
 
  575  if (MBP.ConditionDef && !MBP.SingleUseCondition)
 
  578  MachineBasicBlock *NotNullSucc, *NullSucc;
 
  580  if (MBP.Predicate == MachineBranchPredicate::PRED_NE) {
 
  581    NotNullSucc = MBP.TrueDest;
 
  582    NullSucc = MBP.FalseDest;
 
  584    NotNullSucc = MBP.FalseDest;
 
  585    NullSucc = MBP.TrueDest;
 
  593  const Register PointerReg = MBP.LHS.getReg();
 
  595  if (MBP.ConditionDef) {
 
  614    assert(MBP.ConditionDef->getParent() ==  &
MBB &&
 
  615           "Should be in basic block");
 
  617    for (
auto I = 
MBB.
rbegin(); MBP.ConditionDef != &*
I; ++
I)
 
  618      if (
I->modifiesRegister(PointerReg, 
TRI))
 
  675  SmallVector<MachineInstr *, 8> InstsSeenSoFar;
 
  677  for (
auto &
MI : *NotNullSucc) {
 
  681    MachineInstr *Dependence;
 
  682    SuitabilityResult SR = isSuitableMemoryOp(
MI, PointerReg, InstsSeenSoFar);
 
  683    if (SR == SR_Impossible)
 
  685    if (SR == SR_Suitable &&
 
  686        canHoistInst(&
MI, InstsSeenSoFar, NullSucc, Dependence)) {
 
  688                                 NullSucc, Dependence);
 
  694    if (!
TII->preservesZeroValueInReg(&
MI, PointerReg, 
TRI))
 
  706MachineInstr *ImplicitNullChecks::insertFaultingInstr(
 
  707    MachineInstr *
MI, MachineBasicBlock *
MBB, MachineBasicBlock *HandlerMBB) {
 
  709  unsigned NumDefs = 
MI->getDesc().getNumDefs();
 
  710  assert(NumDefs <= 1 && 
"other cases unhandled!");
 
  714    DefReg = 
MI->getOperand(0).getReg();
 
  715    assert(NumDefs == 1 && 
"expected exactly one def!");
 
  725  auto MIB = 
BuildMI(
MBB, 
DL, 
TII->get(TargetOpcode::FAULTING_OP), DefReg)
 
  730  for (
auto &MO : 
MI->uses()) {
 
  732      MachineOperand NewMO = MO;
 
  736        assert(MO.isDef() && 
"Expected def or use");
 
  751void ImplicitNullChecks::rewriteNullChecks(
 
  755  for (
const auto &
NC : NullCheckList) {
 
  758    (void)BranchesRemoved;
 
  759    assert(BranchesRemoved > 0 && 
"expected at least one branch!");
 
  761    if (
auto *DepMI = 
NC.getOnlyDependency()) {
 
  762      DepMI->removeFromParent();
 
  763      NC.getCheckBlock()->insert(
NC.getCheckBlock()->end(), DepMI);
 
  770    MachineInstr *FaultingInstr = insertFaultingInstr(
 
  771        NC.getMemOperation(), 
NC.getCheckBlock(), 
NC.getNullSucc());
 
  777    for (
const MachineOperand &MO : FaultingInstr->
all_defs()) {
 
  784    if (
auto *DepMI = 
NC.getOnlyDependency()) {
 
  785      for (
auto &MO : DepMI->all_defs()) {
 
  786        if (!MO.getReg() || MO.isDead())
 
  788        if (!
NC.getNotNullSucc()->isLiveIn(MO.getReg()))
 
  789          NC.getNotNullSucc()->addLiveIn(MO.getReg());
 
  793    NC.getMemOperation()->eraseFromParent();
 
  794    if (
auto *CheckOp = 
NC.getCheckOperation())
 
  795      CheckOp->eraseFromParent();
 
  802    NumImplicitNullChecks++;
 
  806char ImplicitNullChecks::ID = 0;
 
  811                      "Implicit null checks", 
false, 
false)
 
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
static bool AnyAliasLiveIn(const TargetRegisterInfo *TRI, MachineBasicBlock *MBB, Register Reg)
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
static cl::opt< unsigned > MaxInstsToConsider("imp-null-max-insts-to-consider", cl::desc("The max number of instructions to consider hoisting loads over " "(the algorithm is quadratic over this number)"), cl::Hidden, cl::init(8))
Register const TargetRegisterInfo * TRI
Promote Memory to Register
This file provides utility analysis objects describing memory locations.
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
uint16_t RegSizeInBits(const MCRegisterInfo &MRI, MCRegister RegNo)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
bool isNoAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are no-alias.
LLVM_ABI APInt sadd_ov(const APInt &RHS, bool &Overflow) const
AnalysisUsage & addRequired()
unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const override
Remove the branching code at the end of the specific MBB.
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef< MachineOperand > Cond, const DebugLoc &DL, int *BytesAdded=nullptr) const override
Insert branch code into the end of the specified MachineBasicBlock.
MCRegAliasIterator enumerates all registers aliasing Reg.
unsigned pred_size() const
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
void addLiveIn(MCRegister PhysReg, LaneBitmask LaneMask=LaneBitmask::getAll())
Adds the specified register as a live in.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
reverse_iterator rbegin()
MachineInstrBundleIterator< const MachineInstr, true > const_reverse_iterator
LLVM_ABI bool isLiveIn(MCRegister Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineInstrBuilder & setMemRefs(ArrayRef< MachineMemOperand * > MMOs) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
bool mayLoadOrStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read or modify memory.
filtered_mop_range all_defs()
Returns an iterator range over all operands that are (explicit or implicit) register defs.
bool memoperands_empty() const
Return true if we don't have any memory operands which described the memory access done by this instr...
bool modifiesRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr modifies (fully define or partially define) the specified register.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
ArrayRef< MachineMemOperand * > memoperands() const
Access to memory operands of the instruction.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
void setIsDead(bool Val=true)
void setIsKill(bool Val=true)
const TargetRegisterInfo * getTargetRegisterInfo() const
static MemoryLocation getAfter(const Value *Ptr, const AAMDNodes &AATags=AAMDNodes())
Return a location that may access any location after Ptr, while remaining within the underlying objec...
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Wrapper class representing virtual and physical registers.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
initializer< Ty > init(const Ty &Val)
std::reverse_iterator< iterator > rend() const
BaseReg
Stack frame base register. Bit 0 of FREInfo.Info.
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI char & ImplicitNullChecksID
ImplicitNullChecks - This pass folds null pointer checks into nearby memory operations.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
ArrayRef(const T &OneElt) -> ArrayRef< T >
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI void initializeImplicitNullChecksPass(PassRegistry &)
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.