10b57cec5SDimitry Andric //===- ImplicitNullChecks.cpp - Fold null checks into memory accesses -----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass turns explicit null checks of the form 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric // test %r10, %r10 120b57cec5SDimitry Andric // je throw_npe 130b57cec5SDimitry Andric // movl (%r10), %esi 140b57cec5SDimitry Andric // ... 150b57cec5SDimitry Andric // 160b57cec5SDimitry Andric // to 170b57cec5SDimitry Andric // 180b57cec5SDimitry Andric // faulting_load_op("movl (%r10), %esi", throw_npe) 190b57cec5SDimitry Andric // ... 200b57cec5SDimitry Andric // 210b57cec5SDimitry Andric // With the help of a runtime that understands the .fault_maps section, 220b57cec5SDimitry Andric // faulting_load_op branches to throw_npe if executing movl (%r10), %esi incurs 230b57cec5SDimitry Andric // a page fault. 240b57cec5SDimitry Andric // Store and LoadStore are also supported. 250b57cec5SDimitry Andric // 260b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 290b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 300b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 310b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 320b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 330b57cec5SDimitry Andric #include "llvm/Analysis/MemoryLocation.h" 340b57cec5SDimitry Andric #include "llvm/CodeGen/FaultMaps.h" 350b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 370b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 380b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 390b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 400b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 410b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 420b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 430b57cec5SDimitry Andric #include "llvm/CodeGen/PseudoSourceValue.h" 440b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 450b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 460b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 470b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 480b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h" 490b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 500b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 51480093f4SDimitry Andric #include "llvm/InitializePasses.h" 520b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 530b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h" 540b57cec5SDimitry Andric #include "llvm/Pass.h" 550b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 560b57cec5SDimitry Andric #include <cassert> 570b57cec5SDimitry Andric #include <cstdint> 580b57cec5SDimitry Andric #include <iterator> 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric using namespace llvm; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric static cl::opt<int> PageSize("imp-null-check-page-size", 630b57cec5SDimitry Andric cl::desc("The page size of the target in bytes"), 640b57cec5SDimitry Andric cl::init(4096), cl::Hidden); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric static cl::opt<unsigned> MaxInstsToConsider( 670b57cec5SDimitry Andric "imp-null-max-insts-to-consider", 680b57cec5SDimitry Andric cl::desc("The max number of instructions to consider hoisting loads over " 690b57cec5SDimitry Andric "(the algorithm is quadratic over this number)"), 700b57cec5SDimitry Andric cl::Hidden, cl::init(8)); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric #define DEBUG_TYPE "implicit-null-checks" 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric STATISTIC(NumImplicitNullChecks, 750b57cec5SDimitry Andric "Number of explicit null checks made implicit"); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric namespace { 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric class ImplicitNullChecks : public MachineFunctionPass { 800b57cec5SDimitry Andric /// Return true if \c computeDependence can process \p MI. 810b57cec5SDimitry Andric static bool canHandle(const MachineInstr *MI); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric /// Helper function for \c computeDependence. Return true if \p A 840b57cec5SDimitry Andric /// and \p B do not have any dependences between them, and can be 850b57cec5SDimitry Andric /// re-ordered without changing program semantics. 860b57cec5SDimitry Andric bool canReorder(const MachineInstr *A, const MachineInstr *B); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric /// A data type for representing the result computed by \c 890b57cec5SDimitry Andric /// computeDependence. States whether it is okay to reorder the 900b57cec5SDimitry Andric /// instruction passed to \c computeDependence with at most one 910b57cec5SDimitry Andric /// dependency. 920b57cec5SDimitry Andric struct DependenceResult { 930b57cec5SDimitry Andric /// Can we actually re-order \p MI with \p Insts (see \c 940b57cec5SDimitry Andric /// computeDependence). 950b57cec5SDimitry Andric bool CanReorder; 960b57cec5SDimitry Andric 9706c3fb27SDimitry Andric /// If non-std::nullopt, then an instruction in \p Insts that also must be 980b57cec5SDimitry Andric /// hoisted. 99bdd1243dSDimitry Andric std::optional<ArrayRef<MachineInstr *>::iterator> PotentialDependence; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric /*implicit*/ DependenceResult( 1020b57cec5SDimitry Andric bool CanReorder, 103bdd1243dSDimitry Andric std::optional<ArrayRef<MachineInstr *>::iterator> PotentialDependence) 1040b57cec5SDimitry Andric : CanReorder(CanReorder), PotentialDependence(PotentialDependence) { 1050b57cec5SDimitry Andric assert((!PotentialDependence || CanReorder) && 1060b57cec5SDimitry Andric "!CanReorder && PotentialDependence.hasValue() not allowed!"); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric }; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric /// Compute a result for the following question: can \p MI be 1110b57cec5SDimitry Andric /// re-ordered from after \p Insts to before it. 1120b57cec5SDimitry Andric /// 1130b57cec5SDimitry Andric /// \c canHandle should return true for all instructions in \p 1140b57cec5SDimitry Andric /// Insts. 1150b57cec5SDimitry Andric DependenceResult computeDependence(const MachineInstr *MI, 1160b57cec5SDimitry Andric ArrayRef<MachineInstr *> Block); 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric /// Represents one null check that can be made implicit. 1190b57cec5SDimitry Andric class NullCheck { 1200b57cec5SDimitry Andric // The memory operation the null check can be folded into. 1210b57cec5SDimitry Andric MachineInstr *MemOperation; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // The instruction actually doing the null check (Ptr != 0). 1240b57cec5SDimitry Andric MachineInstr *CheckOperation; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric // The block the check resides in. 1270b57cec5SDimitry Andric MachineBasicBlock *CheckBlock; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric // The block branched to if the pointer is non-null. 1300b57cec5SDimitry Andric MachineBasicBlock *NotNullSucc; 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric // The block branched to if the pointer is null. 1330b57cec5SDimitry Andric MachineBasicBlock *NullSucc; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric // If this is non-null, then MemOperation has a dependency on this 1360b57cec5SDimitry Andric // instruction; and it needs to be hoisted to execute before MemOperation. 1370b57cec5SDimitry Andric MachineInstr *OnlyDependency; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric public: 1400b57cec5SDimitry Andric explicit NullCheck(MachineInstr *memOperation, MachineInstr *checkOperation, 1410b57cec5SDimitry Andric MachineBasicBlock *checkBlock, 1420b57cec5SDimitry Andric MachineBasicBlock *notNullSucc, 1430b57cec5SDimitry Andric MachineBasicBlock *nullSucc, 1440b57cec5SDimitry Andric MachineInstr *onlyDependency) 1450b57cec5SDimitry Andric : MemOperation(memOperation), CheckOperation(checkOperation), 1460b57cec5SDimitry Andric CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc), 1470b57cec5SDimitry Andric OnlyDependency(onlyDependency) {} 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric MachineInstr *getMemOperation() const { return MemOperation; } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric MachineInstr *getCheckOperation() const { return CheckOperation; } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric MachineBasicBlock *getCheckBlock() const { return CheckBlock; } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric MachineBasicBlock *getNotNullSucc() const { return NotNullSucc; } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric MachineBasicBlock *getNullSucc() const { return NullSucc; } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric MachineInstr *getOnlyDependency() const { return OnlyDependency; } 1600b57cec5SDimitry Andric }; 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric const TargetInstrInfo *TII = nullptr; 1630b57cec5SDimitry Andric const TargetRegisterInfo *TRI = nullptr; 1640b57cec5SDimitry Andric AliasAnalysis *AA = nullptr; 1650b57cec5SDimitry Andric MachineFrameInfo *MFI = nullptr; 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric bool analyzeBlockForNullChecks(MachineBasicBlock &MBB, 1680b57cec5SDimitry Andric SmallVectorImpl<NullCheck> &NullCheckList); 1690b57cec5SDimitry Andric MachineInstr *insertFaultingInstr(MachineInstr *MI, MachineBasicBlock *MBB, 1700b57cec5SDimitry Andric MachineBasicBlock *HandlerMBB); 1710b57cec5SDimitry Andric void rewriteNullChecks(ArrayRef<NullCheck> NullCheckList); 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric enum AliasResult { 1740b57cec5SDimitry Andric AR_NoAlias, 1750b57cec5SDimitry Andric AR_MayAlias, 1760b57cec5SDimitry Andric AR_WillAliasEverything 1770b57cec5SDimitry Andric }; 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric /// Returns AR_NoAlias if \p MI memory operation does not alias with 1800b57cec5SDimitry Andric /// \p PrevMI, AR_MayAlias if they may alias and AR_WillAliasEverything if 1810b57cec5SDimitry Andric /// they may alias and any further memory operation may alias with \p PrevMI. 1820b57cec5SDimitry Andric AliasResult areMemoryOpsAliased(const MachineInstr &MI, 1830b57cec5SDimitry Andric const MachineInstr *PrevMI) const; 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric enum SuitabilityResult { 1860b57cec5SDimitry Andric SR_Suitable, 1870b57cec5SDimitry Andric SR_Unsuitable, 1880b57cec5SDimitry Andric SR_Impossible 1890b57cec5SDimitry Andric }; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric /// Return SR_Suitable if \p MI a memory operation that can be used to 1920b57cec5SDimitry Andric /// implicitly null check the value in \p PointerReg, SR_Unsuitable if 1930b57cec5SDimitry Andric /// \p MI cannot be used to null check and SR_Impossible if there is 1940b57cec5SDimitry Andric /// no sense to continue lookup due to any other instruction will not be able 1950b57cec5SDimitry Andric /// to be used. \p PrevInsts is the set of instruction seen since 1960b57cec5SDimitry Andric /// the explicit null check on \p PointerReg. 1970b57cec5SDimitry Andric SuitabilityResult isSuitableMemoryOp(const MachineInstr &MI, 1980b57cec5SDimitry Andric unsigned PointerReg, 1990b57cec5SDimitry Andric ArrayRef<MachineInstr *> PrevInsts); 2000b57cec5SDimitry Andric 201e8d8bef9SDimitry Andric /// Returns true if \p DependenceMI can clobber the liveIns in NullSucc block 202e8d8bef9SDimitry Andric /// if it was hoisted to the NullCheck block. This is used by caller 203e8d8bef9SDimitry Andric /// canHoistInst to decide if DependenceMI can be hoisted safely. 204e8d8bef9SDimitry Andric bool canDependenceHoistingClobberLiveIns(MachineInstr *DependenceMI, 205e8d8bef9SDimitry Andric MachineBasicBlock *NullSucc); 206e8d8bef9SDimitry Andric 2070b57cec5SDimitry Andric /// Return true if \p FaultingMI can be hoisted from after the 2080b57cec5SDimitry Andric /// instructions in \p InstsSeenSoFar to before them. Set \p Dependence to a 209e8d8bef9SDimitry Andric /// non-null value if we also need to (and legally can) hoist a dependency. 210e8d8bef9SDimitry Andric bool canHoistInst(MachineInstr *FaultingMI, 2110b57cec5SDimitry Andric ArrayRef<MachineInstr *> InstsSeenSoFar, 2120b57cec5SDimitry Andric MachineBasicBlock *NullSucc, MachineInstr *&Dependence); 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric public: 2150b57cec5SDimitry Andric static char ID; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric ImplicitNullChecks() : MachineFunctionPass(ID) { 2180b57cec5SDimitry Andric initializeImplicitNullChecksPass(*PassRegistry::getPassRegistry()); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 2240b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>(); 2250b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 2290b57cec5SDimitry Andric return MachineFunctionProperties().set( 2300b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric }; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric } // end anonymous namespace 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric bool ImplicitNullChecks::canHandle(const MachineInstr *MI) { 2370b57cec5SDimitry Andric if (MI->isCall() || MI->mayRaiseFPException() || 2380b57cec5SDimitry Andric MI->hasUnmodeledSideEffects()) 2390b57cec5SDimitry Andric return false; 2400b57cec5SDimitry Andric auto IsRegMask = [](const MachineOperand &MO) { return MO.isRegMask(); }; 2410b57cec5SDimitry Andric (void)IsRegMask; 2420b57cec5SDimitry Andric 2430eae32dcSDimitry Andric assert(llvm::none_of(MI->operands(), IsRegMask) && 2440b57cec5SDimitry Andric "Calls were filtered out above!"); 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric auto IsUnordered = [](MachineMemOperand *MMO) { return MMO->isUnordered(); }; 2470b57cec5SDimitry Andric return llvm::all_of(MI->memoperands(), IsUnordered); 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric ImplicitNullChecks::DependenceResult 2510b57cec5SDimitry Andric ImplicitNullChecks::computeDependence(const MachineInstr *MI, 2520b57cec5SDimitry Andric ArrayRef<MachineInstr *> Block) { 2530b57cec5SDimitry Andric assert(llvm::all_of(Block, canHandle) && "Check this first!"); 2540b57cec5SDimitry Andric assert(!is_contained(Block, MI) && "Block must be exclusive of MI!"); 2550b57cec5SDimitry Andric 256bdd1243dSDimitry Andric std::optional<ArrayRef<MachineInstr *>::iterator> Dep; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric for (auto I = Block.begin(), E = Block.end(); I != E; ++I) { 2590b57cec5SDimitry Andric if (canReorder(*I, MI)) 2600b57cec5SDimitry Andric continue; 2610b57cec5SDimitry Andric 262bdd1243dSDimitry Andric if (Dep == std::nullopt) { 2630b57cec5SDimitry Andric // Found one possible dependency, keep track of it. 2640b57cec5SDimitry Andric Dep = I; 2650b57cec5SDimitry Andric } else { 2660b57cec5SDimitry Andric // We found two dependencies, so bail out. 267bdd1243dSDimitry Andric return {false, std::nullopt}; 2680b57cec5SDimitry Andric } 2690b57cec5SDimitry Andric } 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric return {true, Dep}; 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric bool ImplicitNullChecks::canReorder(const MachineInstr *A, 2750b57cec5SDimitry Andric const MachineInstr *B) { 2760b57cec5SDimitry Andric assert(canHandle(A) && canHandle(B) && "Precondition!"); 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric // canHandle makes sure that we _can_ correctly analyze the dependencies 2790b57cec5SDimitry Andric // between A and B here -- for instance, we should not be dealing with heap 2800b57cec5SDimitry Andric // load-store dependencies here. 2810b57cec5SDimitry Andric 282e8d8bef9SDimitry Andric for (const auto &MOA : A->operands()) { 2830b57cec5SDimitry Andric if (!(MOA.isReg() && MOA.getReg())) 2840b57cec5SDimitry Andric continue; 2850b57cec5SDimitry Andric 2868bcb0991SDimitry Andric Register RegA = MOA.getReg(); 287e8d8bef9SDimitry Andric for (const auto &MOB : B->operands()) { 2880b57cec5SDimitry Andric if (!(MOB.isReg() && MOB.getReg())) 2890b57cec5SDimitry Andric continue; 2900b57cec5SDimitry Andric 2918bcb0991SDimitry Andric Register RegB = MOB.getReg(); 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric if (TRI->regsOverlap(RegA, RegB) && (MOA.isDef() || MOB.isDef())) 2940b57cec5SDimitry Andric return false; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric return true; 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric bool ImplicitNullChecks::runOnMachineFunction(MachineFunction &MF) { 3020b57cec5SDimitry Andric TII = MF.getSubtarget().getInstrInfo(); 3030b57cec5SDimitry Andric TRI = MF.getRegInfo().getTargetRegisterInfo(); 3040b57cec5SDimitry Andric MFI = &MF.getFrameInfo(); 3050b57cec5SDimitry Andric AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric SmallVector<NullCheck, 16> NullCheckList; 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric for (auto &MBB : MF) 3100b57cec5SDimitry Andric analyzeBlockForNullChecks(MBB, NullCheckList); 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric if (!NullCheckList.empty()) 3130b57cec5SDimitry Andric rewriteNullChecks(NullCheckList); 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric return !NullCheckList.empty(); 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Return true if any register aliasing \p Reg is live-in into \p MBB. 3190b57cec5SDimitry Andric static bool AnyAliasLiveIn(const TargetRegisterInfo *TRI, 3200b57cec5SDimitry Andric MachineBasicBlock *MBB, unsigned Reg) { 3210b57cec5SDimitry Andric for (MCRegAliasIterator AR(Reg, TRI, /*IncludeSelf*/ true); AR.isValid(); 3220b57cec5SDimitry Andric ++AR) 3230b57cec5SDimitry Andric if (MBB->isLiveIn(*AR)) 3240b57cec5SDimitry Andric return true; 3250b57cec5SDimitry Andric return false; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric ImplicitNullChecks::AliasResult 3290b57cec5SDimitry Andric ImplicitNullChecks::areMemoryOpsAliased(const MachineInstr &MI, 3300b57cec5SDimitry Andric const MachineInstr *PrevMI) const { 3310b57cec5SDimitry Andric // If it is not memory access, skip the check. 3320b57cec5SDimitry Andric if (!(PrevMI->mayStore() || PrevMI->mayLoad())) 3330b57cec5SDimitry Andric return AR_NoAlias; 3340b57cec5SDimitry Andric // Load-Load may alias 3350b57cec5SDimitry Andric if (!(MI.mayStore() || PrevMI->mayStore())) 3360b57cec5SDimitry Andric return AR_NoAlias; 3370b57cec5SDimitry Andric // We lost info, conservatively alias. If it was store then no sense to 3380b57cec5SDimitry Andric // continue because we won't be able to check against it further. 3390b57cec5SDimitry Andric if (MI.memoperands_empty()) 3400b57cec5SDimitry Andric return MI.mayStore() ? AR_WillAliasEverything : AR_MayAlias; 3410b57cec5SDimitry Andric if (PrevMI->memoperands_empty()) 3420b57cec5SDimitry Andric return PrevMI->mayStore() ? AR_WillAliasEverything : AR_MayAlias; 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric for (MachineMemOperand *MMO1 : MI.memoperands()) { 3450b57cec5SDimitry Andric // MMO1 should have a value due it comes from operation we'd like to use 3460b57cec5SDimitry Andric // as implicit null check. 3470b57cec5SDimitry Andric assert(MMO1->getValue() && "MMO1 should have a Value!"); 3480b57cec5SDimitry Andric for (MachineMemOperand *MMO2 : PrevMI->memoperands()) { 3490b57cec5SDimitry Andric if (const PseudoSourceValue *PSV = MMO2->getPseudoValue()) { 3500b57cec5SDimitry Andric if (PSV->mayAlias(MFI)) 3510b57cec5SDimitry Andric return AR_MayAlias; 3520b57cec5SDimitry Andric continue; 3530b57cec5SDimitry Andric } 354fe6060f1SDimitry Andric if (!AA->isNoAlias( 355e8d8bef9SDimitry Andric MemoryLocation::getAfter(MMO1->getValue(), MMO1->getAAInfo()), 356fe6060f1SDimitry Andric MemoryLocation::getAfter(MMO2->getValue(), MMO2->getAAInfo()))) 3570b57cec5SDimitry Andric return AR_MayAlias; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric return AR_NoAlias; 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric ImplicitNullChecks::SuitabilityResult 3640b57cec5SDimitry Andric ImplicitNullChecks::isSuitableMemoryOp(const MachineInstr &MI, 3650b57cec5SDimitry Andric unsigned PointerReg, 3660b57cec5SDimitry Andric ArrayRef<MachineInstr *> PrevInsts) { 367e8d8bef9SDimitry Andric // Implementation restriction for faulting_op insertion 368e8d8bef9SDimitry Andric // TODO: This could be relaxed if we find a test case which warrants it. 369e8d8bef9SDimitry Andric if (MI.getDesc().getNumDefs() > 1) 3700b57cec5SDimitry Andric return SR_Unsuitable; 3710b57cec5SDimitry Andric 372e8d8bef9SDimitry Andric if (!MI.mayLoadOrStore() || MI.isPredicable()) 373e8d8bef9SDimitry Andric return SR_Unsuitable; 374e8d8bef9SDimitry Andric auto AM = TII->getAddrModeFromMemoryOp(MI, TRI); 375*5f757f3fSDimitry Andric if (!AM || AM->Form != ExtAddrMode::Formula::Basic) 376e8d8bef9SDimitry Andric return SR_Unsuitable; 377e8d8bef9SDimitry Andric auto AddrMode = *AM; 378e8d8bef9SDimitry Andric const Register BaseReg = AddrMode.BaseReg, ScaledReg = AddrMode.ScaledReg; 379e8d8bef9SDimitry Andric int64_t Displacement = AddrMode.Displacement; 380e8d8bef9SDimitry Andric 381e8d8bef9SDimitry Andric // We need the base of the memory instruction to be same as the register 382e8d8bef9SDimitry Andric // where the null check is performed (i.e. PointerReg). 383e8d8bef9SDimitry Andric if (BaseReg != PointerReg && ScaledReg != PointerReg) 384e8d8bef9SDimitry Andric return SR_Unsuitable; 385e8d8bef9SDimitry Andric const MachineRegisterInfo &MRI = MI.getMF()->getRegInfo(); 386e8d8bef9SDimitry Andric unsigned PointerRegSizeInBits = TRI->getRegSizeInBits(PointerReg, MRI); 387e8d8bef9SDimitry Andric // Bail out of the sizes of BaseReg, ScaledReg and PointerReg are not the 388e8d8bef9SDimitry Andric // same. 389e8d8bef9SDimitry Andric if ((BaseReg && 390e8d8bef9SDimitry Andric TRI->getRegSizeInBits(BaseReg, MRI) != PointerRegSizeInBits) || 391e8d8bef9SDimitry Andric (ScaledReg && 392e8d8bef9SDimitry Andric TRI->getRegSizeInBits(ScaledReg, MRI) != PointerRegSizeInBits)) 393e8d8bef9SDimitry Andric return SR_Unsuitable; 394e8d8bef9SDimitry Andric 395e8d8bef9SDimitry Andric // Returns true if RegUsedInAddr is used for calculating the displacement 396e8d8bef9SDimitry Andric // depending on addressing mode. Also calculates the Displacement. 397e8d8bef9SDimitry Andric auto CalculateDisplacementFromAddrMode = [&](Register RegUsedInAddr, 398e8d8bef9SDimitry Andric int64_t Multiplier) { 399e8d8bef9SDimitry Andric // The register can be NoRegister, which is defined as zero for all targets. 400e8d8bef9SDimitry Andric // Consider instruction of interest as `movq 8(,%rdi,8), %rax`. Here the 401e8d8bef9SDimitry Andric // ScaledReg is %rdi, while there is no BaseReg. 402e8d8bef9SDimitry Andric if (!RegUsedInAddr) 403e8d8bef9SDimitry Andric return false; 404e8d8bef9SDimitry Andric assert(Multiplier && "expected to be non-zero!"); 405e8d8bef9SDimitry Andric MachineInstr *ModifyingMI = nullptr; 406e8d8bef9SDimitry Andric for (auto It = std::next(MachineBasicBlock::const_reverse_iterator(&MI)); 407e8d8bef9SDimitry Andric It != MI.getParent()->rend(); It++) { 408e8d8bef9SDimitry Andric const MachineInstr *CurrMI = &*It; 409e8d8bef9SDimitry Andric if (CurrMI->modifiesRegister(RegUsedInAddr, TRI)) { 410e8d8bef9SDimitry Andric ModifyingMI = const_cast<MachineInstr *>(CurrMI); 411e8d8bef9SDimitry Andric break; 412e8d8bef9SDimitry Andric } 413e8d8bef9SDimitry Andric } 414e8d8bef9SDimitry Andric if (!ModifyingMI) 415e8d8bef9SDimitry Andric return false; 416e8d8bef9SDimitry Andric // Check for the const value defined in register by ModifyingMI. This means 417e8d8bef9SDimitry Andric // all other previous values for that register has been invalidated. 418e8d8bef9SDimitry Andric int64_t ImmVal; 419e8d8bef9SDimitry Andric if (!TII->getConstValDefinedInReg(*ModifyingMI, RegUsedInAddr, ImmVal)) 420e8d8bef9SDimitry Andric return false; 421e8d8bef9SDimitry Andric // Calculate the reg size in bits, since this is needed for bailing out in 422e8d8bef9SDimitry Andric // case of overflow. 423e8d8bef9SDimitry Andric int32_t RegSizeInBits = TRI->getRegSizeInBits(RegUsedInAddr, MRI); 424e8d8bef9SDimitry Andric APInt ImmValC(RegSizeInBits, ImmVal, true /*IsSigned*/); 425e8d8bef9SDimitry Andric APInt MultiplierC(RegSizeInBits, Multiplier); 426e8d8bef9SDimitry Andric assert(MultiplierC.isStrictlyPositive() && 427e8d8bef9SDimitry Andric "expected to be a positive value!"); 428e8d8bef9SDimitry Andric bool IsOverflow; 429e8d8bef9SDimitry Andric // Sign of the product depends on the sign of the ImmVal, since Multiplier 430e8d8bef9SDimitry Andric // is always positive. 431e8d8bef9SDimitry Andric APInt Product = ImmValC.smul_ov(MultiplierC, IsOverflow); 432e8d8bef9SDimitry Andric if (IsOverflow) 433e8d8bef9SDimitry Andric return false; 434e8d8bef9SDimitry Andric APInt DisplacementC(64, Displacement, true /*isSigned*/); 435e8d8bef9SDimitry Andric DisplacementC = Product.sadd_ov(DisplacementC, IsOverflow); 436e8d8bef9SDimitry Andric if (IsOverflow) 437e8d8bef9SDimitry Andric return false; 438e8d8bef9SDimitry Andric 439e8d8bef9SDimitry Andric // We only handle diplacements upto 64 bits wide. 440e8d8bef9SDimitry Andric if (DisplacementC.getActiveBits() > 64) 441e8d8bef9SDimitry Andric return false; 442e8d8bef9SDimitry Andric Displacement = DisplacementC.getSExtValue(); 443e8d8bef9SDimitry Andric return true; 444e8d8bef9SDimitry Andric }; 445e8d8bef9SDimitry Andric 446e8d8bef9SDimitry Andric // If a register used in the address is constant, fold it's effect into the 447e8d8bef9SDimitry Andric // displacement for ease of analysis. 448e8d8bef9SDimitry Andric bool BaseRegIsConstVal = false, ScaledRegIsConstVal = false; 449e8d8bef9SDimitry Andric if (CalculateDisplacementFromAddrMode(BaseReg, 1)) 450e8d8bef9SDimitry Andric BaseRegIsConstVal = true; 451e8d8bef9SDimitry Andric if (CalculateDisplacementFromAddrMode(ScaledReg, AddrMode.Scale)) 452e8d8bef9SDimitry Andric ScaledRegIsConstVal = true; 453e8d8bef9SDimitry Andric 454e8d8bef9SDimitry Andric // The register which is not null checked should be part of the Displacement 455e8d8bef9SDimitry Andric // calculation, otherwise we do not know whether the Displacement is made up 456e8d8bef9SDimitry Andric // by some symbolic values. 457e8d8bef9SDimitry Andric // This matters because we do not want to incorrectly assume that load from 458e8d8bef9SDimitry Andric // falls in the zeroth faulting page in the "sane offset check" below. 459e8d8bef9SDimitry Andric if ((BaseReg && BaseReg != PointerReg && !BaseRegIsConstVal) || 460e8d8bef9SDimitry Andric (ScaledReg && ScaledReg != PointerReg && !ScaledRegIsConstVal)) 4615ffd83dbSDimitry Andric return SR_Unsuitable; 4625ffd83dbSDimitry Andric 4630b57cec5SDimitry Andric // We want the mem access to be issued at a sane offset from PointerReg, 4640b57cec5SDimitry Andric // so that if PointerReg is null then the access reliably page faults. 465e8d8bef9SDimitry Andric if (!(-PageSize < Displacement && Displacement < PageSize)) 4660b57cec5SDimitry Andric return SR_Unsuitable; 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric // Finally, check whether the current memory access aliases with previous one. 4690b57cec5SDimitry Andric for (auto *PrevMI : PrevInsts) { 4700b57cec5SDimitry Andric AliasResult AR = areMemoryOpsAliased(MI, PrevMI); 4710b57cec5SDimitry Andric if (AR == AR_WillAliasEverything) 4720b57cec5SDimitry Andric return SR_Impossible; 4730b57cec5SDimitry Andric if (AR == AR_MayAlias) 4740b57cec5SDimitry Andric return SR_Unsuitable; 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric return SR_Suitable; 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 479e8d8bef9SDimitry Andric bool ImplicitNullChecks::canDependenceHoistingClobberLiveIns( 480e8d8bef9SDimitry Andric MachineInstr *DependenceMI, MachineBasicBlock *NullSucc) { 481e8d8bef9SDimitry Andric for (const auto &DependenceMO : DependenceMI->operands()) { 482e8d8bef9SDimitry Andric if (!(DependenceMO.isReg() && DependenceMO.getReg())) 483e8d8bef9SDimitry Andric continue; 484e8d8bef9SDimitry Andric 485e8d8bef9SDimitry Andric // Make sure that we won't clobber any live ins to the sibling block by 486e8d8bef9SDimitry Andric // hoisting Dependency. For instance, we can't hoist INST to before the 487e8d8bef9SDimitry Andric // null check (even if it safe, and does not violate any dependencies in 488e8d8bef9SDimitry Andric // the non_null_block) if %rdx is live in to _null_block. 489e8d8bef9SDimitry Andric // 490e8d8bef9SDimitry Andric // test %rcx, %rcx 491e8d8bef9SDimitry Andric // je _null_block 492e8d8bef9SDimitry Andric // _non_null_block: 493e8d8bef9SDimitry Andric // %rdx = INST 494e8d8bef9SDimitry Andric // ... 495e8d8bef9SDimitry Andric // 496e8d8bef9SDimitry Andric // This restriction does not apply to the faulting load inst because in 497e8d8bef9SDimitry Andric // case the pointer loaded from is in the null page, the load will not 498e8d8bef9SDimitry Andric // semantically execute, and affect machine state. That is, if the load 499e8d8bef9SDimitry Andric // was loading into %rax and it faults, the value of %rax should stay the 500e8d8bef9SDimitry Andric // same as it would have been had the load not have executed and we'd have 501e8d8bef9SDimitry Andric // branched to NullSucc directly. 502e8d8bef9SDimitry Andric if (AnyAliasLiveIn(TRI, NullSucc, DependenceMO.getReg())) 503e8d8bef9SDimitry Andric return true; 504e8d8bef9SDimitry Andric 505e8d8bef9SDimitry Andric } 506e8d8bef9SDimitry Andric 507e8d8bef9SDimitry Andric // The dependence does not clobber live-ins in NullSucc block. 508e8d8bef9SDimitry Andric return false; 509e8d8bef9SDimitry Andric } 510e8d8bef9SDimitry Andric 5110b57cec5SDimitry Andric bool ImplicitNullChecks::canHoistInst(MachineInstr *FaultingMI, 5120b57cec5SDimitry Andric ArrayRef<MachineInstr *> InstsSeenSoFar, 5130b57cec5SDimitry Andric MachineBasicBlock *NullSucc, 5140b57cec5SDimitry Andric MachineInstr *&Dependence) { 5150b57cec5SDimitry Andric auto DepResult = computeDependence(FaultingMI, InstsSeenSoFar); 5160b57cec5SDimitry Andric if (!DepResult.CanReorder) 5170b57cec5SDimitry Andric return false; 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric if (!DepResult.PotentialDependence) { 5200b57cec5SDimitry Andric Dependence = nullptr; 5210b57cec5SDimitry Andric return true; 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric auto DependenceItr = *DepResult.PotentialDependence; 5250b57cec5SDimitry Andric auto *DependenceMI = *DependenceItr; 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric // We don't want to reason about speculating loads. Note -- at this point 5280b57cec5SDimitry Andric // we should have already filtered out all of the other non-speculatable 5290b57cec5SDimitry Andric // things, like calls and stores. 5300b57cec5SDimitry Andric // We also do not want to hoist stores because it might change the memory 5310b57cec5SDimitry Andric // while the FaultingMI may result in faulting. 5320b57cec5SDimitry Andric assert(canHandle(DependenceMI) && "Should never have reached here!"); 5330b57cec5SDimitry Andric if (DependenceMI->mayLoadOrStore()) 5340b57cec5SDimitry Andric return false; 5350b57cec5SDimitry Andric 536e8d8bef9SDimitry Andric if (canDependenceHoistingClobberLiveIns(DependenceMI, NullSucc)) 5370b57cec5SDimitry Andric return false; 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric auto DepDepResult = 5400b57cec5SDimitry Andric computeDependence(DependenceMI, {InstsSeenSoFar.begin(), DependenceItr}); 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric if (!DepDepResult.CanReorder || DepDepResult.PotentialDependence) 5430b57cec5SDimitry Andric return false; 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric Dependence = DependenceMI; 5460b57cec5SDimitry Andric return true; 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric /// Analyze MBB to check if its terminating branch can be turned into an 5500b57cec5SDimitry Andric /// implicit null check. If yes, append a description of the said null check to 5510b57cec5SDimitry Andric /// NullCheckList and return true, else return false. 5520b57cec5SDimitry Andric bool ImplicitNullChecks::analyzeBlockForNullChecks( 5530b57cec5SDimitry Andric MachineBasicBlock &MBB, SmallVectorImpl<NullCheck> &NullCheckList) { 5540b57cec5SDimitry Andric using MachineBranchPredicate = TargetInstrInfo::MachineBranchPredicate; 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric MDNode *BranchMD = nullptr; 5570b57cec5SDimitry Andric if (auto *BB = MBB.getBasicBlock()) 5580b57cec5SDimitry Andric BranchMD = BB->getTerminator()->getMetadata(LLVMContext::MD_make_implicit); 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric if (!BranchMD) 5610b57cec5SDimitry Andric return false; 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric MachineBranchPredicate MBP; 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric if (TII->analyzeBranchPredicate(MBB, MBP, true)) 5660b57cec5SDimitry Andric return false; 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric // Is the predicate comparing an integer to zero? 5690b57cec5SDimitry Andric if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 && 5700b57cec5SDimitry Andric (MBP.Predicate == MachineBranchPredicate::PRED_NE || 5710b57cec5SDimitry Andric MBP.Predicate == MachineBranchPredicate::PRED_EQ))) 5720b57cec5SDimitry Andric return false; 5730b57cec5SDimitry Andric 574e8d8bef9SDimitry Andric // If there is a separate condition generation instruction, we chose not to 575e8d8bef9SDimitry Andric // transform unless we can remove both condition and consuming branch. 576e8d8bef9SDimitry Andric if (MBP.ConditionDef && !MBP.SingleUseCondition) 5770b57cec5SDimitry Andric return false; 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric MachineBasicBlock *NotNullSucc, *NullSucc; 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric if (MBP.Predicate == MachineBranchPredicate::PRED_NE) { 5820b57cec5SDimitry Andric NotNullSucc = MBP.TrueDest; 5830b57cec5SDimitry Andric NullSucc = MBP.FalseDest; 5840b57cec5SDimitry Andric } else { 5850b57cec5SDimitry Andric NotNullSucc = MBP.FalseDest; 5860b57cec5SDimitry Andric NullSucc = MBP.TrueDest; 5870b57cec5SDimitry Andric } 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric // We handle the simplest case for now. We can potentially do better by using 5900b57cec5SDimitry Andric // the machine dominator tree. 5910b57cec5SDimitry Andric if (NotNullSucc->pred_size() != 1) 5920b57cec5SDimitry Andric return false; 5930b57cec5SDimitry Andric 594e8d8bef9SDimitry Andric const Register PointerReg = MBP.LHS.getReg(); 595e8d8bef9SDimitry Andric 596e8d8bef9SDimitry Andric if (MBP.ConditionDef) { 5970b57cec5SDimitry Andric // To prevent the invalid transformation of the following code: 5980b57cec5SDimitry Andric // 5990b57cec5SDimitry Andric // mov %rax, %rcx 6000b57cec5SDimitry Andric // test %rax, %rax 6010b57cec5SDimitry Andric // %rax = ... 6020b57cec5SDimitry Andric // je throw_npe 6030b57cec5SDimitry Andric // mov(%rcx), %r9 6040b57cec5SDimitry Andric // mov(%rax), %r10 6050b57cec5SDimitry Andric // 6060b57cec5SDimitry Andric // into: 6070b57cec5SDimitry Andric // 6080b57cec5SDimitry Andric // mov %rax, %rcx 6090b57cec5SDimitry Andric // %rax = .... 6100b57cec5SDimitry Andric // faulting_load_op("movl (%rax), %r10", throw_npe) 6110b57cec5SDimitry Andric // mov(%rcx), %r9 6120b57cec5SDimitry Andric // 6130b57cec5SDimitry Andric // we must ensure that there are no instructions between the 'test' and 6140b57cec5SDimitry Andric // conditional jump that modify %rax. 615e8d8bef9SDimitry Andric assert(MBP.ConditionDef->getParent() == &MBB && 616e8d8bef9SDimitry Andric "Should be in basic block"); 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric for (auto I = MBB.rbegin(); MBP.ConditionDef != &*I; ++I) 6190b57cec5SDimitry Andric if (I->modifiesRegister(PointerReg, TRI)) 6200b57cec5SDimitry Andric return false; 621e8d8bef9SDimitry Andric } 6220b57cec5SDimitry Andric // Starting with a code fragment like: 6230b57cec5SDimitry Andric // 6240b57cec5SDimitry Andric // test %rax, %rax 6250b57cec5SDimitry Andric // jne LblNotNull 6260b57cec5SDimitry Andric // 6270b57cec5SDimitry Andric // LblNull: 6280b57cec5SDimitry Andric // callq throw_NullPointerException 6290b57cec5SDimitry Andric // 6300b57cec5SDimitry Andric // LblNotNull: 6310b57cec5SDimitry Andric // Inst0 6320b57cec5SDimitry Andric // Inst1 6330b57cec5SDimitry Andric // ... 6340b57cec5SDimitry Andric // Def = Load (%rax + <offset>) 6350b57cec5SDimitry Andric // ... 6360b57cec5SDimitry Andric // 6370b57cec5SDimitry Andric // 6380b57cec5SDimitry Andric // we want to end up with 6390b57cec5SDimitry Andric // 6400b57cec5SDimitry Andric // Def = FaultingLoad (%rax + <offset>), LblNull 6410b57cec5SDimitry Andric // jmp LblNotNull ;; explicit or fallthrough 6420b57cec5SDimitry Andric // 6430b57cec5SDimitry Andric // LblNotNull: 6440b57cec5SDimitry Andric // Inst0 6450b57cec5SDimitry Andric // Inst1 6460b57cec5SDimitry Andric // ... 6470b57cec5SDimitry Andric // 6480b57cec5SDimitry Andric // LblNull: 6490b57cec5SDimitry Andric // callq throw_NullPointerException 6500b57cec5SDimitry Andric // 6510b57cec5SDimitry Andric // 6520b57cec5SDimitry Andric // To see why this is legal, consider the two possibilities: 6530b57cec5SDimitry Andric // 6540b57cec5SDimitry Andric // 1. %rax is null: since we constrain <offset> to be less than PageSize, the 6550b57cec5SDimitry Andric // load instruction dereferences the null page, causing a segmentation 6560b57cec5SDimitry Andric // fault. 6570b57cec5SDimitry Andric // 6580b57cec5SDimitry Andric // 2. %rax is not null: in this case we know that the load cannot fault, as 6590b57cec5SDimitry Andric // otherwise the load would've faulted in the original program too and the 6600b57cec5SDimitry Andric // original program would've been undefined. 6610b57cec5SDimitry Andric // 6620b57cec5SDimitry Andric // This reasoning cannot be extended to justify hoisting through arbitrary 6630b57cec5SDimitry Andric // control flow. For instance, in the example below (in pseudo-C) 6640b57cec5SDimitry Andric // 6650b57cec5SDimitry Andric // if (ptr == null) { throw_npe(); unreachable; } 6660b57cec5SDimitry Andric // if (some_cond) { return 42; } 6670b57cec5SDimitry Andric // v = ptr->field; // LD 6680b57cec5SDimitry Andric // ... 6690b57cec5SDimitry Andric // 6700b57cec5SDimitry Andric // we cannot (without code duplication) use the load marked "LD" to null check 6710b57cec5SDimitry Andric // ptr -- clause (2) above does not apply in this case. In the above program 6720b57cec5SDimitry Andric // the safety of ptr->field can be dependent on some_cond; and, for instance, 6730b57cec5SDimitry Andric // ptr could be some non-null invalid reference that never gets loaded from 6740b57cec5SDimitry Andric // because some_cond is always true. 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> InstsSeenSoFar; 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric for (auto &MI : *NotNullSucc) { 6790b57cec5SDimitry Andric if (!canHandle(&MI) || InstsSeenSoFar.size() >= MaxInstsToConsider) 6800b57cec5SDimitry Andric return false; 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric MachineInstr *Dependence; 6830b57cec5SDimitry Andric SuitabilityResult SR = isSuitableMemoryOp(MI, PointerReg, InstsSeenSoFar); 6840b57cec5SDimitry Andric if (SR == SR_Impossible) 6850b57cec5SDimitry Andric return false; 6860b57cec5SDimitry Andric if (SR == SR_Suitable && 687e8d8bef9SDimitry Andric canHoistInst(&MI, InstsSeenSoFar, NullSucc, Dependence)) { 6880b57cec5SDimitry Andric NullCheckList.emplace_back(&MI, MBP.ConditionDef, &MBB, NotNullSucc, 6890b57cec5SDimitry Andric NullSucc, Dependence); 6900b57cec5SDimitry Andric return true; 6910b57cec5SDimitry Andric } 6920b57cec5SDimitry Andric 693e8d8bef9SDimitry Andric // If MI re-defines the PointerReg in a way that changes the value of 694e8d8bef9SDimitry Andric // PointerReg if it was null, then we cannot move further. 695e8d8bef9SDimitry Andric if (!TII->preservesZeroValueInReg(&MI, PointerReg, TRI)) 6960b57cec5SDimitry Andric return false; 6970b57cec5SDimitry Andric InstsSeenSoFar.push_back(&MI); 6980b57cec5SDimitry Andric } 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric return false; 7010b57cec5SDimitry Andric } 7020b57cec5SDimitry Andric 7030b57cec5SDimitry Andric /// Wrap a machine instruction, MI, into a FAULTING machine instruction. 7040b57cec5SDimitry Andric /// The FAULTING instruction does the same load/store as MI 7050b57cec5SDimitry Andric /// (defining the same register), and branches to HandlerMBB if the mem access 7060b57cec5SDimitry Andric /// faults. The FAULTING instruction is inserted at the end of MBB. 7070b57cec5SDimitry Andric MachineInstr *ImplicitNullChecks::insertFaultingInstr( 7080b57cec5SDimitry Andric MachineInstr *MI, MachineBasicBlock *MBB, MachineBasicBlock *HandlerMBB) { 7090b57cec5SDimitry Andric const unsigned NoRegister = 0; // Guaranteed to be the NoRegister value for 7100b57cec5SDimitry Andric // all targets. 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric DebugLoc DL; 7130b57cec5SDimitry Andric unsigned NumDefs = MI->getDesc().getNumDefs(); 7140b57cec5SDimitry Andric assert(NumDefs <= 1 && "other cases unhandled!"); 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric unsigned DefReg = NoRegister; 7170b57cec5SDimitry Andric if (NumDefs != 0) { 7180b57cec5SDimitry Andric DefReg = MI->getOperand(0).getReg(); 7190b57cec5SDimitry Andric assert(NumDefs == 1 && "expected exactly one def!"); 7200b57cec5SDimitry Andric } 7210b57cec5SDimitry Andric 7220b57cec5SDimitry Andric FaultMaps::FaultKind FK; 7230b57cec5SDimitry Andric if (MI->mayLoad()) 7240b57cec5SDimitry Andric FK = 7250b57cec5SDimitry Andric MI->mayStore() ? FaultMaps::FaultingLoadStore : FaultMaps::FaultingLoad; 7260b57cec5SDimitry Andric else 7270b57cec5SDimitry Andric FK = FaultMaps::FaultingStore; 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric auto MIB = BuildMI(MBB, DL, TII->get(TargetOpcode::FAULTING_OP), DefReg) 7300b57cec5SDimitry Andric .addImm(FK) 7310b57cec5SDimitry Andric .addMBB(HandlerMBB) 7320b57cec5SDimitry Andric .addImm(MI->getOpcode()); 7330b57cec5SDimitry Andric 7340b57cec5SDimitry Andric for (auto &MO : MI->uses()) { 7350b57cec5SDimitry Andric if (MO.isReg()) { 7360b57cec5SDimitry Andric MachineOperand NewMO = MO; 7370b57cec5SDimitry Andric if (MO.isUse()) { 7380b57cec5SDimitry Andric NewMO.setIsKill(false); 7390b57cec5SDimitry Andric } else { 7400b57cec5SDimitry Andric assert(MO.isDef() && "Expected def or use"); 7410b57cec5SDimitry Andric NewMO.setIsDead(false); 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric MIB.add(NewMO); 7440b57cec5SDimitry Andric } else { 7450b57cec5SDimitry Andric MIB.add(MO); 7460b57cec5SDimitry Andric } 7470b57cec5SDimitry Andric } 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric MIB.setMemRefs(MI->memoperands()); 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric return MIB; 7520b57cec5SDimitry Andric } 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric /// Rewrite the null checks in NullCheckList into implicit null checks. 7550b57cec5SDimitry Andric void ImplicitNullChecks::rewriteNullChecks( 7560b57cec5SDimitry Andric ArrayRef<ImplicitNullChecks::NullCheck> NullCheckList) { 7570b57cec5SDimitry Andric DebugLoc DL; 7580b57cec5SDimitry Andric 759fcaf7f86SDimitry Andric for (const auto &NC : NullCheckList) { 7600b57cec5SDimitry Andric // Remove the conditional branch dependent on the null check. 7610b57cec5SDimitry Andric unsigned BranchesRemoved = TII->removeBranch(*NC.getCheckBlock()); 7620b57cec5SDimitry Andric (void)BranchesRemoved; 7630b57cec5SDimitry Andric assert(BranchesRemoved > 0 && "expected at least one branch!"); 7640b57cec5SDimitry Andric 7650b57cec5SDimitry Andric if (auto *DepMI = NC.getOnlyDependency()) { 7660b57cec5SDimitry Andric DepMI->removeFromParent(); 7670b57cec5SDimitry Andric NC.getCheckBlock()->insert(NC.getCheckBlock()->end(), DepMI); 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric // Insert a faulting instruction where the conditional branch was 7710b57cec5SDimitry Andric // originally. We check earlier ensures that this bit of code motion 7720b57cec5SDimitry Andric // is legal. We do not touch the successors list for any basic block 7730b57cec5SDimitry Andric // since we haven't changed control flow, we've just made it implicit. 7740b57cec5SDimitry Andric MachineInstr *FaultingInstr = insertFaultingInstr( 7750b57cec5SDimitry Andric NC.getMemOperation(), NC.getCheckBlock(), NC.getNullSucc()); 7760b57cec5SDimitry Andric // Now the values defined by MemOperation, if any, are live-in of 7770b57cec5SDimitry Andric // the block of MemOperation. 7780b57cec5SDimitry Andric // The original operation may define implicit-defs alongside 7790b57cec5SDimitry Andric // the value. 7800b57cec5SDimitry Andric MachineBasicBlock *MBB = NC.getMemOperation()->getParent(); 78106c3fb27SDimitry Andric for (const MachineOperand &MO : FaultingInstr->all_defs()) { 7828bcb0991SDimitry Andric Register Reg = MO.getReg(); 7830b57cec5SDimitry Andric if (!Reg || MBB->isLiveIn(Reg)) 7840b57cec5SDimitry Andric continue; 7850b57cec5SDimitry Andric MBB->addLiveIn(Reg); 7860b57cec5SDimitry Andric } 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric if (auto *DepMI = NC.getOnlyDependency()) { 78906c3fb27SDimitry Andric for (auto &MO : DepMI->all_defs()) { 79006c3fb27SDimitry Andric if (!MO.getReg() || MO.isDead()) 7910b57cec5SDimitry Andric continue; 7920b57cec5SDimitry Andric if (!NC.getNotNullSucc()->isLiveIn(MO.getReg())) 7930b57cec5SDimitry Andric NC.getNotNullSucc()->addLiveIn(MO.getReg()); 7940b57cec5SDimitry Andric } 7950b57cec5SDimitry Andric } 7960b57cec5SDimitry Andric 7970b57cec5SDimitry Andric NC.getMemOperation()->eraseFromParent(); 798e8d8bef9SDimitry Andric if (auto *CheckOp = NC.getCheckOperation()) 799e8d8bef9SDimitry Andric CheckOp->eraseFromParent(); 8000b57cec5SDimitry Andric 801e8d8bef9SDimitry Andric // Insert an *unconditional* branch to not-null successor - we expect 802e8d8bef9SDimitry Andric // block placement to remove fallthroughs later. 8030b57cec5SDimitry Andric TII->insertBranch(*NC.getCheckBlock(), NC.getNotNullSucc(), nullptr, 804bdd1243dSDimitry Andric /*Cond=*/std::nullopt, DL); 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric NumImplicitNullChecks++; 8070b57cec5SDimitry Andric } 8080b57cec5SDimitry Andric } 8090b57cec5SDimitry Andric 8100b57cec5SDimitry Andric char ImplicitNullChecks::ID = 0; 8110b57cec5SDimitry Andric 8120b57cec5SDimitry Andric char &llvm::ImplicitNullChecksID = ImplicitNullChecks::ID; 8130b57cec5SDimitry Andric 8140b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(ImplicitNullChecks, DEBUG_TYPE, 8150b57cec5SDimitry Andric "Implicit null checks", false, false) 8160b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) 8170b57cec5SDimitry Andric INITIALIZE_PASS_END(ImplicitNullChecks, DEBUG_TYPE, 8180b57cec5SDimitry Andric "Implicit null checks", false, false) 819