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