169fad079SSanjoy Das //===-- ImplicitNullChecks.cpp - Fold null checks into memory accesses ----===//
269fad079SSanjoy Das //
369fad079SSanjoy Das //                     The LLVM Compiler Infrastructure
469fad079SSanjoy Das //
569fad079SSanjoy Das // This file is distributed under the University of Illinois Open Source
669fad079SSanjoy Das // License. See LICENSE.TXT for details.
769fad079SSanjoy Das //
869fad079SSanjoy Das //===----------------------------------------------------------------------===//
969fad079SSanjoy Das //
1069fad079SSanjoy Das // This pass turns explicit null checks of the form
1169fad079SSanjoy Das //
1269fad079SSanjoy Das //   test %r10, %r10
1369fad079SSanjoy Das //   je throw_npe
1469fad079SSanjoy Das //   movl (%r10), %esi
1569fad079SSanjoy Das //   ...
1669fad079SSanjoy Das //
1769fad079SSanjoy Das // to
1869fad079SSanjoy Das //
1969fad079SSanjoy Das //   faulting_load_op("movl (%r10), %esi", throw_npe)
2069fad079SSanjoy Das //   ...
2169fad079SSanjoy Das //
2269fad079SSanjoy Das // With the help of a runtime that understands the .fault_maps section,
2369fad079SSanjoy Das // faulting_load_op branches to throw_npe if executing movl (%r10), %esi incurs
2469fad079SSanjoy Das // a page fault.
2569fad079SSanjoy Das //
2669fad079SSanjoy Das //===----------------------------------------------------------------------===//
2769fad079SSanjoy Das 
2869fad079SSanjoy Das #include "llvm/ADT/SmallVector.h"
29*8ee6a30bSSanjoy Das #include "llvm/ADT/Statistic.h"
3069fad079SSanjoy Das #include "llvm/CodeGen/Passes.h"
3169fad079SSanjoy Das #include "llvm/CodeGen/MachineFunction.h"
3269fad079SSanjoy Das #include "llvm/CodeGen/MachineOperand.h"
3369fad079SSanjoy Das #include "llvm/CodeGen/MachineFunctionPass.h"
3469fad079SSanjoy Das #include "llvm/CodeGen/MachineInstrBuilder.h"
3569fad079SSanjoy Das #include "llvm/CodeGen/MachineRegisterInfo.h"
3669fad079SSanjoy Das #include "llvm/CodeGen/MachineModuleInfo.h"
3769fad079SSanjoy Das #include "llvm/IR/BasicBlock.h"
3869fad079SSanjoy Das #include "llvm/IR/Instruction.h"
3969fad079SSanjoy Das #include "llvm/Support/CommandLine.h"
4069fad079SSanjoy Das #include "llvm/Support/Debug.h"
4169fad079SSanjoy Das #include "llvm/Target/TargetSubtargetInfo.h"
4269fad079SSanjoy Das #include "llvm/Target/TargetInstrInfo.h"
4369fad079SSanjoy Das 
4469fad079SSanjoy Das using namespace llvm;
4569fad079SSanjoy Das 
4669fad079SSanjoy Das static cl::opt<unsigned> PageSize("imp-null-check-page-size",
4769fad079SSanjoy Das                                   cl::desc("The page size of the target in "
4869fad079SSanjoy Das                                            "bytes"),
4969fad079SSanjoy Das                                   cl::init(4096));
5069fad079SSanjoy Das 
51*8ee6a30bSSanjoy Das #define DEBUG_TYPE "implicit-null-checks"
52*8ee6a30bSSanjoy Das 
53*8ee6a30bSSanjoy Das STATISTIC(NumImplicitNullChecks,
54*8ee6a30bSSanjoy Das           "Number of explicit null checks made implicit");
55*8ee6a30bSSanjoy Das 
5669fad079SSanjoy Das namespace {
5769fad079SSanjoy Das 
5869fad079SSanjoy Das class ImplicitNullChecks : public MachineFunctionPass {
5969fad079SSanjoy Das   /// Represents one null check that can be made implicit.
6069fad079SSanjoy Das   struct NullCheck {
6169fad079SSanjoy Das     // The memory operation the null check can be folded into.
6269fad079SSanjoy Das     MachineInstr *MemOperation;
6369fad079SSanjoy Das 
6469fad079SSanjoy Das     // The instruction actually doing the null check (Ptr != 0).
6569fad079SSanjoy Das     MachineInstr *CheckOperation;
6669fad079SSanjoy Das 
6769fad079SSanjoy Das     // The block the check resides in.
6869fad079SSanjoy Das     MachineBasicBlock *CheckBlock;
6969fad079SSanjoy Das 
70572e03a3SEric Christopher     // The block branched to if the pointer is non-null.
7169fad079SSanjoy Das     MachineBasicBlock *NotNullSucc;
7269fad079SSanjoy Das 
73572e03a3SEric Christopher     // The block branched to if the pointer is null.
7469fad079SSanjoy Das     MachineBasicBlock *NullSucc;
7569fad079SSanjoy Das 
7669fad079SSanjoy Das     NullCheck()
7769fad079SSanjoy Das         : MemOperation(), CheckOperation(), CheckBlock(), NotNullSucc(),
7869fad079SSanjoy Das           NullSucc() {}
7969fad079SSanjoy Das 
8069fad079SSanjoy Das     explicit NullCheck(MachineInstr *memOperation, MachineInstr *checkOperation,
8169fad079SSanjoy Das                        MachineBasicBlock *checkBlock,
8269fad079SSanjoy Das                        MachineBasicBlock *notNullSucc,
8369fad079SSanjoy Das                        MachineBasicBlock *nullSucc)
8469fad079SSanjoy Das         : MemOperation(memOperation), CheckOperation(checkOperation),
8569fad079SSanjoy Das           CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc) {
8669fad079SSanjoy Das     }
8769fad079SSanjoy Das   };
8869fad079SSanjoy Das 
8969fad079SSanjoy Das   const TargetInstrInfo *TII = nullptr;
9069fad079SSanjoy Das   const TargetRegisterInfo *TRI = nullptr;
9169fad079SSanjoy Das   MachineModuleInfo *MMI = nullptr;
9269fad079SSanjoy Das 
9369fad079SSanjoy Das   bool analyzeBlockForNullChecks(MachineBasicBlock &MBB,
9469fad079SSanjoy Das                                  SmallVectorImpl<NullCheck> &NullCheckList);
9569fad079SSanjoy Das   MachineInstr *insertFaultingLoad(MachineInstr *LoadMI, MachineBasicBlock *MBB,
9669fad079SSanjoy Das                                    MCSymbol *HandlerLabel);
9769fad079SSanjoy Das   void rewriteNullChecks(ArrayRef<NullCheck> NullCheckList);
9869fad079SSanjoy Das 
9969fad079SSanjoy Das public:
10069fad079SSanjoy Das   static char ID;
10169fad079SSanjoy Das 
10269fad079SSanjoy Das   ImplicitNullChecks() : MachineFunctionPass(ID) {
10369fad079SSanjoy Das     initializeImplicitNullChecksPass(*PassRegistry::getPassRegistry());
10469fad079SSanjoy Das   }
10569fad079SSanjoy Das 
10669fad079SSanjoy Das   bool runOnMachineFunction(MachineFunction &MF) override;
10769fad079SSanjoy Das };
108f00654e3SAlexander Kornienko }
10969fad079SSanjoy Das 
11069fad079SSanjoy Das bool ImplicitNullChecks::runOnMachineFunction(MachineFunction &MF) {
11169fad079SSanjoy Das   TII = MF.getSubtarget().getInstrInfo();
11269fad079SSanjoy Das   TRI = MF.getRegInfo().getTargetRegisterInfo();
11369fad079SSanjoy Das   MMI = &MF.getMMI();
11469fad079SSanjoy Das 
11569fad079SSanjoy Das   SmallVector<NullCheck, 16> NullCheckList;
11669fad079SSanjoy Das 
11769fad079SSanjoy Das   for (auto &MBB : MF)
11869fad079SSanjoy Das     analyzeBlockForNullChecks(MBB, NullCheckList);
11969fad079SSanjoy Das 
12069fad079SSanjoy Das   if (!NullCheckList.empty())
12169fad079SSanjoy Das     rewriteNullChecks(NullCheckList);
12269fad079SSanjoy Das 
12369fad079SSanjoy Das   return !NullCheckList.empty();
12469fad079SSanjoy Das }
12569fad079SSanjoy Das 
12669fad079SSanjoy Das /// Analyze MBB to check if its terminating branch can be turned into an
12769fad079SSanjoy Das /// implicit null check.  If yes, append a description of the said null check to
12869fad079SSanjoy Das /// NullCheckList and return true, else return false.
12969fad079SSanjoy Das bool ImplicitNullChecks::analyzeBlockForNullChecks(
13069fad079SSanjoy Das     MachineBasicBlock &MBB, SmallVectorImpl<NullCheck> &NullCheckList) {
13169fad079SSanjoy Das   typedef TargetInstrInfo::MachineBranchPredicate MachineBranchPredicate;
13269fad079SSanjoy Das 
1339c41a93eSSanjoy Das   MDNode *BranchMD =
1349c41a93eSSanjoy Das       MBB.getBasicBlock()
1359c41a93eSSanjoy Das           ? MBB.getBasicBlock()->getTerminator()->getMetadata("make.implicit")
1369c41a93eSSanjoy Das           : nullptr;
1379c41a93eSSanjoy Das   if (!BranchMD)
1389c41a93eSSanjoy Das     return false;
1399c41a93eSSanjoy Das 
14069fad079SSanjoy Das   MachineBranchPredicate MBP;
14169fad079SSanjoy Das 
14269fad079SSanjoy Das   if (TII->AnalyzeBranchPredicate(MBB, MBP, true))
14369fad079SSanjoy Das     return false;
14469fad079SSanjoy Das 
14569fad079SSanjoy Das   // Is the predicate comparing an integer to zero?
14669fad079SSanjoy Das   if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&
14769fad079SSanjoy Das         (MBP.Predicate == MachineBranchPredicate::PRED_NE ||
14869fad079SSanjoy Das          MBP.Predicate == MachineBranchPredicate::PRED_EQ)))
14969fad079SSanjoy Das     return false;
15069fad079SSanjoy Das 
15169fad079SSanjoy Das   // If we cannot erase the test instruction itself, then making the null check
15269fad079SSanjoy Das   // implicit does not buy us much.
15369fad079SSanjoy Das   if (!MBP.SingleUseCondition)
15469fad079SSanjoy Das     return false;
15569fad079SSanjoy Das 
15669fad079SSanjoy Das   MachineBasicBlock *NotNullSucc, *NullSucc;
15769fad079SSanjoy Das 
15869fad079SSanjoy Das   if (MBP.Predicate == MachineBranchPredicate::PRED_NE) {
15969fad079SSanjoy Das     NotNullSucc = MBP.TrueDest;
16069fad079SSanjoy Das     NullSucc = MBP.FalseDest;
16169fad079SSanjoy Das   } else {
16269fad079SSanjoy Das     NotNullSucc = MBP.FalseDest;
16369fad079SSanjoy Das     NullSucc = MBP.TrueDest;
16469fad079SSanjoy Das   }
16569fad079SSanjoy Das 
16669fad079SSanjoy Das   // We handle the simplest case for now.  We can potentially do better by using
16769fad079SSanjoy Das   // the machine dominator tree.
16869fad079SSanjoy Das   if (NotNullSucc->pred_size() != 1)
16969fad079SSanjoy Das     return false;
17069fad079SSanjoy Das 
17169fad079SSanjoy Das   // Starting with a code fragment like:
17269fad079SSanjoy Das   //
17369fad079SSanjoy Das   //   test %RAX, %RAX
17469fad079SSanjoy Das   //   jne LblNotNull
17569fad079SSanjoy Das   //
17669fad079SSanjoy Das   //  LblNull:
17769fad079SSanjoy Das   //   callq throw_NullPointerException
17869fad079SSanjoy Das   //
17969fad079SSanjoy Das   //  LblNotNull:
18069fad079SSanjoy Das   //   Def = Load (%RAX + <offset>)
18169fad079SSanjoy Das   //   ...
18269fad079SSanjoy Das   //
18369fad079SSanjoy Das   //
18469fad079SSanjoy Das   // we want to end up with
18569fad079SSanjoy Das   //
18669fad079SSanjoy Das   //   Def = TrappingLoad (%RAX + <offset>), LblNull
18769fad079SSanjoy Das   //   jmp LblNotNull ;; explicit or fallthrough
18869fad079SSanjoy Das   //
18969fad079SSanjoy Das   //  LblNotNull:
19069fad079SSanjoy Das   //   ...
19169fad079SSanjoy Das   //
19269fad079SSanjoy Das   //  LblNull:
19369fad079SSanjoy Das   //   callq throw_NullPointerException
19469fad079SSanjoy Das   //
19569fad079SSanjoy Das 
19669fad079SSanjoy Das   unsigned PointerReg = MBP.LHS.getReg();
19769fad079SSanjoy Das   MachineInstr *MemOp = &*NotNullSucc->begin();
19869fad079SSanjoy Das   unsigned BaseReg, Offset;
19969fad079SSanjoy Das   if (TII->getMemOpBaseRegImmOfs(MemOp, BaseReg, Offset, TRI))
20069fad079SSanjoy Das     if (MemOp->mayLoad() && !MemOp->isPredicable() && BaseReg == PointerReg &&
20169fad079SSanjoy Das         Offset < PageSize && MemOp->getDesc().getNumDefs() == 1) {
20269fad079SSanjoy Das       NullCheckList.emplace_back(MemOp, MBP.ConditionDef, &MBB, NotNullSucc,
20369fad079SSanjoy Das                                  NullSucc);
20469fad079SSanjoy Das       return true;
20569fad079SSanjoy Das     }
20669fad079SSanjoy Das 
20769fad079SSanjoy Das   return false;
20869fad079SSanjoy Das }
20969fad079SSanjoy Das 
21069fad079SSanjoy Das /// Wrap a machine load instruction, LoadMI, into a FAULTING_LOAD_OP machine
21169fad079SSanjoy Das /// instruction.  The FAULTING_LOAD_OP instruction does the same load as LoadMI
21269fad079SSanjoy Das /// (defining the same register), and branches to HandlerLabel if the load
21369fad079SSanjoy Das /// faults.  The FAULTING_LOAD_OP instruction is inserted at the end of MBB.
21469fad079SSanjoy Das MachineInstr *ImplicitNullChecks::insertFaultingLoad(MachineInstr *LoadMI,
21569fad079SSanjoy Das                                                      MachineBasicBlock *MBB,
21669fad079SSanjoy Das                                                      MCSymbol *HandlerLabel) {
21769fad079SSanjoy Das   DebugLoc DL;
21869fad079SSanjoy Das   unsigned NumDefs = LoadMI->getDesc().getNumDefs();
21969fad079SSanjoy Das   assert(NumDefs == 1 && "other cases unhandled!");
22069fad079SSanjoy Das   (void)NumDefs;
22169fad079SSanjoy Das 
22269fad079SSanjoy Das   unsigned DefReg = LoadMI->defs().begin()->getReg();
22369fad079SSanjoy Das   assert(std::distance(LoadMI->defs().begin(), LoadMI->defs().end()) == 1 &&
22469fad079SSanjoy Das          "expected exactly one def!");
22569fad079SSanjoy Das 
22669fad079SSanjoy Das   auto MIB = BuildMI(MBB, DL, TII->get(TargetOpcode::FAULTING_LOAD_OP), DefReg)
22769fad079SSanjoy Das                  .addSym(HandlerLabel)
22869fad079SSanjoy Das                  .addImm(LoadMI->getOpcode());
22969fad079SSanjoy Das 
23069fad079SSanjoy Das   for (auto &MO : LoadMI->uses())
23169fad079SSanjoy Das     MIB.addOperand(MO);
23269fad079SSanjoy Das 
23369fad079SSanjoy Das   MIB.setMemRefs(LoadMI->memoperands_begin(), LoadMI->memoperands_end());
23469fad079SSanjoy Das 
23569fad079SSanjoy Das   return MIB;
23669fad079SSanjoy Das }
23769fad079SSanjoy Das 
23869fad079SSanjoy Das /// Rewrite the null checks in NullCheckList into implicit null checks.
23969fad079SSanjoy Das void ImplicitNullChecks::rewriteNullChecks(
24069fad079SSanjoy Das     ArrayRef<ImplicitNullChecks::NullCheck> NullCheckList) {
24169fad079SSanjoy Das   DebugLoc DL;
24269fad079SSanjoy Das 
24369fad079SSanjoy Das   for (auto &NC : NullCheckList) {
24469fad079SSanjoy Das     MCSymbol *HandlerLabel = MMI->getContext().createTempSymbol();
24569fad079SSanjoy Das 
24669fad079SSanjoy Das     // Remove the conditional branch dependent on the null check.
24769fad079SSanjoy Das     unsigned BranchesRemoved = TII->RemoveBranch(*NC.CheckBlock);
24869fad079SSanjoy Das     (void)BranchesRemoved;
24969fad079SSanjoy Das     assert(BranchesRemoved > 0 && "expected at least one branch!");
25069fad079SSanjoy Das 
25169fad079SSanjoy Das     // Insert a faulting load where the conditional branch was originally.  We
25269fad079SSanjoy Das     // check earlier ensures that this bit of code motion is legal.  We do not
25369fad079SSanjoy Das     // touch the successors list for any basic block since we haven't changed
25469fad079SSanjoy Das     // control flow, we've just made it implicit.
25569fad079SSanjoy Das     insertFaultingLoad(NC.MemOperation, NC.CheckBlock, HandlerLabel);
25669fad079SSanjoy Das     NC.MemOperation->removeFromParent();
25769fad079SSanjoy Das     NC.CheckOperation->eraseFromParent();
25869fad079SSanjoy Das 
25969fad079SSanjoy Das     // Insert an *unconditional* branch to not-null successor.
26069fad079SSanjoy Das     TII->InsertBranch(*NC.CheckBlock, NC.NotNullSucc, nullptr, /*Cond=*/None,
26169fad079SSanjoy Das                       DL);
26269fad079SSanjoy Das 
26369fad079SSanjoy Das     // Emit the HandlerLabel as an EH_LABEL.
26469fad079SSanjoy Das     BuildMI(*NC.NullSucc, NC.NullSucc->begin(), DL,
26569fad079SSanjoy Das             TII->get(TargetOpcode::EH_LABEL)).addSym(HandlerLabel);
266*8ee6a30bSSanjoy Das 
267*8ee6a30bSSanjoy Das     NumImplicitNullChecks++;
26869fad079SSanjoy Das   }
26969fad079SSanjoy Das }
27069fad079SSanjoy Das 
27169fad079SSanjoy Das char ImplicitNullChecks::ID = 0;
27269fad079SSanjoy Das char &llvm::ImplicitNullChecksID = ImplicitNullChecks::ID;
27369fad079SSanjoy Das INITIALIZE_PASS_BEGIN(ImplicitNullChecks, "implicit-null-checks",
27469fad079SSanjoy Das                       "Implicit null checks", false, false)
27569fad079SSanjoy Das INITIALIZE_PASS_END(ImplicitNullChecks, "implicit-null-checks",
27669fad079SSanjoy Das                     "Implicit null checks", false, false)
277