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 
28b7718454SSanjoy Das #include "llvm/ADT/DenseSet.h"
2969fad079SSanjoy Das #include "llvm/ADT/SmallVector.h"
308ee6a30bSSanjoy Das #include "llvm/ADT/Statistic.h"
3169fad079SSanjoy Das #include "llvm/CodeGen/Passes.h"
3269fad079SSanjoy Das #include "llvm/CodeGen/MachineFunction.h"
33b7718454SSanjoy Das #include "llvm/CodeGen/MachineMemOperand.h"
3469fad079SSanjoy Das #include "llvm/CodeGen/MachineOperand.h"
3569fad079SSanjoy Das #include "llvm/CodeGen/MachineFunctionPass.h"
3669fad079SSanjoy Das #include "llvm/CodeGen/MachineInstrBuilder.h"
3769fad079SSanjoy Das #include "llvm/CodeGen/MachineRegisterInfo.h"
3869fad079SSanjoy Das #include "llvm/CodeGen/MachineModuleInfo.h"
3969fad079SSanjoy Das #include "llvm/IR/BasicBlock.h"
4069fad079SSanjoy Das #include "llvm/IR/Instruction.h"
4169fad079SSanjoy Das #include "llvm/Support/CommandLine.h"
4269fad079SSanjoy Das #include "llvm/Support/Debug.h"
4369fad079SSanjoy Das #include "llvm/Target/TargetSubtargetInfo.h"
4469fad079SSanjoy Das #include "llvm/Target/TargetInstrInfo.h"
4569fad079SSanjoy Das 
4669fad079SSanjoy Das using namespace llvm;
4769fad079SSanjoy Das 
4869fad079SSanjoy Das static cl::opt<unsigned> PageSize("imp-null-check-page-size",
4969fad079SSanjoy Das                                   cl::desc("The page size of the target in "
5069fad079SSanjoy Das                                            "bytes"),
5169fad079SSanjoy Das                                   cl::init(4096));
5269fad079SSanjoy Das 
538ee6a30bSSanjoy Das #define DEBUG_TYPE "implicit-null-checks"
548ee6a30bSSanjoy Das 
558ee6a30bSSanjoy Das STATISTIC(NumImplicitNullChecks,
568ee6a30bSSanjoy Das           "Number of explicit null checks made implicit");
578ee6a30bSSanjoy Das 
5869fad079SSanjoy Das namespace {
5969fad079SSanjoy Das 
6069fad079SSanjoy Das class ImplicitNullChecks : public MachineFunctionPass {
6169fad079SSanjoy Das   /// Represents one null check that can be made implicit.
6269fad079SSanjoy Das   struct NullCheck {
6369fad079SSanjoy Das     // The memory operation the null check can be folded into.
6469fad079SSanjoy Das     MachineInstr *MemOperation;
6569fad079SSanjoy Das 
6669fad079SSanjoy Das     // The instruction actually doing the null check (Ptr != 0).
6769fad079SSanjoy Das     MachineInstr *CheckOperation;
6869fad079SSanjoy Das 
6969fad079SSanjoy Das     // The block the check resides in.
7069fad079SSanjoy Das     MachineBasicBlock *CheckBlock;
7169fad079SSanjoy Das 
72572e03a3SEric Christopher     // The block branched to if the pointer is non-null.
7369fad079SSanjoy Das     MachineBasicBlock *NotNullSucc;
7469fad079SSanjoy Das 
75572e03a3SEric Christopher     // The block branched to if the pointer is null.
7669fad079SSanjoy Das     MachineBasicBlock *NullSucc;
7769fad079SSanjoy Das 
7869fad079SSanjoy Das     NullCheck()
7969fad079SSanjoy Das         : MemOperation(), CheckOperation(), CheckBlock(), NotNullSucc(),
8069fad079SSanjoy Das           NullSucc() {}
8169fad079SSanjoy Das 
8269fad079SSanjoy Das     explicit NullCheck(MachineInstr *memOperation, MachineInstr *checkOperation,
8369fad079SSanjoy Das                        MachineBasicBlock *checkBlock,
8469fad079SSanjoy Das                        MachineBasicBlock *notNullSucc,
8569fad079SSanjoy Das                        MachineBasicBlock *nullSucc)
8669fad079SSanjoy Das         : MemOperation(memOperation), CheckOperation(checkOperation),
8769fad079SSanjoy Das           CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc) {
8869fad079SSanjoy Das     }
8969fad079SSanjoy Das   };
9069fad079SSanjoy Das 
9169fad079SSanjoy Das   const TargetInstrInfo *TII = nullptr;
9269fad079SSanjoy Das   const TargetRegisterInfo *TRI = nullptr;
9369fad079SSanjoy Das   MachineModuleInfo *MMI = nullptr;
9469fad079SSanjoy Das 
9569fad079SSanjoy Das   bool analyzeBlockForNullChecks(MachineBasicBlock &MBB,
9669fad079SSanjoy Das                                  SmallVectorImpl<NullCheck> &NullCheckList);
9769fad079SSanjoy Das   MachineInstr *insertFaultingLoad(MachineInstr *LoadMI, MachineBasicBlock *MBB,
9869fad079SSanjoy Das                                    MCSymbol *HandlerLabel);
9969fad079SSanjoy Das   void rewriteNullChecks(ArrayRef<NullCheck> NullCheckList);
10069fad079SSanjoy Das 
10169fad079SSanjoy Das public:
10269fad079SSanjoy Das   static char ID;
10369fad079SSanjoy Das 
10469fad079SSanjoy Das   ImplicitNullChecks() : MachineFunctionPass(ID) {
10569fad079SSanjoy Das     initializeImplicitNullChecksPass(*PassRegistry::getPassRegistry());
10669fad079SSanjoy Das   }
10769fad079SSanjoy Das 
10869fad079SSanjoy Das   bool runOnMachineFunction(MachineFunction &MF) override;
10969fad079SSanjoy Das };
110f00654e3SAlexander Kornienko }
11169fad079SSanjoy Das 
11269fad079SSanjoy Das bool ImplicitNullChecks::runOnMachineFunction(MachineFunction &MF) {
11369fad079SSanjoy Das   TII = MF.getSubtarget().getInstrInfo();
11469fad079SSanjoy Das   TRI = MF.getRegInfo().getTargetRegisterInfo();
11569fad079SSanjoy Das   MMI = &MF.getMMI();
11669fad079SSanjoy Das 
11769fad079SSanjoy Das   SmallVector<NullCheck, 16> NullCheckList;
11869fad079SSanjoy Das 
11969fad079SSanjoy Das   for (auto &MBB : MF)
12069fad079SSanjoy Das     analyzeBlockForNullChecks(MBB, NullCheckList);
12169fad079SSanjoy Das 
12269fad079SSanjoy Das   if (!NullCheckList.empty())
12369fad079SSanjoy Das     rewriteNullChecks(NullCheckList);
12469fad079SSanjoy Das 
12569fad079SSanjoy Das   return !NullCheckList.empty();
12669fad079SSanjoy Das }
12769fad079SSanjoy Das 
12869fad079SSanjoy Das /// Analyze MBB to check if its terminating branch can be turned into an
12969fad079SSanjoy Das /// implicit null check.  If yes, append a description of the said null check to
13069fad079SSanjoy Das /// NullCheckList and return true, else return false.
13169fad079SSanjoy Das bool ImplicitNullChecks::analyzeBlockForNullChecks(
13269fad079SSanjoy Das     MachineBasicBlock &MBB, SmallVectorImpl<NullCheck> &NullCheckList) {
13369fad079SSanjoy Das   typedef TargetInstrInfo::MachineBranchPredicate MachineBranchPredicate;
13469fad079SSanjoy Das 
1359c41a93eSSanjoy Das   MDNode *BranchMD =
1369c41a93eSSanjoy Das       MBB.getBasicBlock()
1379c41a93eSSanjoy Das           ? MBB.getBasicBlock()->getTerminator()->getMetadata("make.implicit")
1389c41a93eSSanjoy Das           : nullptr;
1399c41a93eSSanjoy Das   if (!BranchMD)
1409c41a93eSSanjoy Das     return false;
1419c41a93eSSanjoy Das 
14269fad079SSanjoy Das   MachineBranchPredicate MBP;
14369fad079SSanjoy Das 
14469fad079SSanjoy Das   if (TII->AnalyzeBranchPredicate(MBB, MBP, true))
14569fad079SSanjoy Das     return false;
14669fad079SSanjoy Das 
14769fad079SSanjoy Das   // Is the predicate comparing an integer to zero?
14869fad079SSanjoy Das   if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&
14969fad079SSanjoy Das         (MBP.Predicate == MachineBranchPredicate::PRED_NE ||
15069fad079SSanjoy Das          MBP.Predicate == MachineBranchPredicate::PRED_EQ)))
15169fad079SSanjoy Das     return false;
15269fad079SSanjoy Das 
15369fad079SSanjoy Das   // If we cannot erase the test instruction itself, then making the null check
15469fad079SSanjoy Das   // implicit does not buy us much.
15569fad079SSanjoy Das   if (!MBP.SingleUseCondition)
15669fad079SSanjoy Das     return false;
15769fad079SSanjoy Das 
15869fad079SSanjoy Das   MachineBasicBlock *NotNullSucc, *NullSucc;
15969fad079SSanjoy Das 
16069fad079SSanjoy Das   if (MBP.Predicate == MachineBranchPredicate::PRED_NE) {
16169fad079SSanjoy Das     NotNullSucc = MBP.TrueDest;
16269fad079SSanjoy Das     NullSucc = MBP.FalseDest;
16369fad079SSanjoy Das   } else {
16469fad079SSanjoy Das     NotNullSucc = MBP.FalseDest;
16569fad079SSanjoy Das     NullSucc = MBP.TrueDest;
16669fad079SSanjoy Das   }
16769fad079SSanjoy Das 
16869fad079SSanjoy Das   // We handle the simplest case for now.  We can potentially do better by using
16969fad079SSanjoy Das   // the machine dominator tree.
17069fad079SSanjoy Das   if (NotNullSucc->pred_size() != 1)
17169fad079SSanjoy Das     return false;
17269fad079SSanjoy Das 
17369fad079SSanjoy Das   // Starting with a code fragment like:
17469fad079SSanjoy Das   //
17569fad079SSanjoy Das   //   test %RAX, %RAX
17669fad079SSanjoy Das   //   jne LblNotNull
17769fad079SSanjoy Das   //
17869fad079SSanjoy Das   //  LblNull:
17969fad079SSanjoy Das   //   callq throw_NullPointerException
18069fad079SSanjoy Das   //
18169fad079SSanjoy Das   //  LblNotNull:
182b7718454SSanjoy Das   //   Inst0
183b7718454SSanjoy Das   //   Inst1
184b7718454SSanjoy Das   //   ...
18569fad079SSanjoy Das   //   Def = Load (%RAX + <offset>)
18669fad079SSanjoy Das   //   ...
18769fad079SSanjoy Das   //
18869fad079SSanjoy Das   //
18969fad079SSanjoy Das   // we want to end up with
19069fad079SSanjoy Das   //
19169fad079SSanjoy Das   //   Def = TrappingLoad (%RAX + <offset>), LblNull
19269fad079SSanjoy Das   //   jmp LblNotNull ;; explicit or fallthrough
19369fad079SSanjoy Das   //
19469fad079SSanjoy Das   //  LblNotNull:
195b7718454SSanjoy Das   //   Inst0
196b7718454SSanjoy Das   //   Inst1
19769fad079SSanjoy Das   //   ...
19869fad079SSanjoy Das   //
19969fad079SSanjoy Das   //  LblNull:
20069fad079SSanjoy Das   //   callq throw_NullPointerException
20169fad079SSanjoy Das   //
20269fad079SSanjoy Das 
20369fad079SSanjoy Das   unsigned PointerReg = MBP.LHS.getReg();
204b7718454SSanjoy Das 
205b7718454SSanjoy Das   // As we scan NotNullSucc for a suitable load instruction, we keep track of
206b7718454SSanjoy Das   // the registers defined and used by the instructions we scan past.  This bit
207b7718454SSanjoy Das   // of information lets us decide if it is legal to hoist the load instruction
208b7718454SSanjoy Das   // we find (if we do find such an instruction) to before NotNullSucc.
209b7718454SSanjoy Das   DenseSet<unsigned> RegDefs, RegUses;
210b7718454SSanjoy Das 
211b7718454SSanjoy Das   // Returns true if it is safe to reorder MI to before NotNullSucc.
212b7718454SSanjoy Das   auto IsSafeToHoist = [&](MachineInstr *MI) {
213b7718454SSanjoy Das     // Right now we don't want to worry about LLVM's memory model.  This can be
214b7718454SSanjoy Das     // made more precise later.
215b7718454SSanjoy Das     for (auto *MMO : MI->memoperands())
216b7718454SSanjoy Das       if (!MMO->isUnordered())
217b7718454SSanjoy Das         return false;
218b7718454SSanjoy Das 
219b7718454SSanjoy Das     for (auto &MO : MI->operands()) {
220b7718454SSanjoy Das       if (MO.isReg() && MO.getReg()) {
221b7718454SSanjoy Das         for (unsigned Reg : RegDefs)
222b7718454SSanjoy Das           if (TRI->regsOverlap(Reg, MO.getReg()))
223b7718454SSanjoy Das             return false;  // We found a write-after-write or read-after-write
224b7718454SSanjoy Das 
225b7718454SSanjoy Das         if (MO.isDef())
226b7718454SSanjoy Das           for (unsigned Reg : RegUses)
227b7718454SSanjoy Das             if (TRI->regsOverlap(Reg, MO.getReg()))
228b7718454SSanjoy Das               return false;  // We found a write-after-read
229b7718454SSanjoy Das       }
230b7718454SSanjoy Das     }
231b7718454SSanjoy Das 
232b7718454SSanjoy Das     return true;
233b7718454SSanjoy Das   };
234b7718454SSanjoy Das 
235b7718454SSanjoy Das   for (auto MII = NotNullSucc->begin(), MIE = NotNullSucc->end(); MII != MIE;
236b7718454SSanjoy Das        ++MII) {
237b7718454SSanjoy Das     MachineInstr *MI = &*MII;
23869fad079SSanjoy Das     unsigned BaseReg, Offset;
239b7718454SSanjoy Das     if (TII->getMemOpBaseRegImmOfs(MI, BaseReg, Offset, TRI))
240b7718454SSanjoy Das       if (MI->mayLoad() && !MI->isPredicable() && BaseReg == PointerReg &&
241b7718454SSanjoy Das           Offset < PageSize && MI->getDesc().getNumDefs() == 1 &&
242b7718454SSanjoy Das           IsSafeToHoist(MI)) {
243b7718454SSanjoy Das         NullCheckList.emplace_back(MI, MBP.ConditionDef, &MBB, NotNullSucc,
24469fad079SSanjoy Das                                    NullSucc);
24569fad079SSanjoy Das         return true;
24669fad079SSanjoy Das       }
24769fad079SSanjoy Das 
248b7718454SSanjoy Das     // MI did not match our criteria for conversion to a trapping load.  Check
249b7718454SSanjoy Das     // if we can continue looking.
250b7718454SSanjoy Das 
251b7718454SSanjoy Das     if (MI->mayStore() || MI->hasUnmodeledSideEffects())
252b7718454SSanjoy Das       return false;
253b7718454SSanjoy Das 
254b7718454SSanjoy Das     for (auto *MMO : MI->memoperands())
255b7718454SSanjoy Das       // Right now we don't want to worry about LLVM's memory model.
256b7718454SSanjoy Das       if (!MMO->isUnordered())
257b7718454SSanjoy Das         return false;
258b7718454SSanjoy Das 
259b7718454SSanjoy Das     // It _may_ be okay to reorder a later load instruction across MI.  Make a
260b7718454SSanjoy Das     // note of its operands so that we can make the legality check if we find a
261b7718454SSanjoy Das     // suitable load instruction:
262b7718454SSanjoy Das 
263b7718454SSanjoy Das     for (auto &MO : MI->operands()) {
264b7718454SSanjoy Das       if (!MO.isReg() || !MO.getReg())
265b7718454SSanjoy Das         continue;
266b7718454SSanjoy Das 
267b7718454SSanjoy Das       if (MO.isDef())
268b7718454SSanjoy Das         RegDefs.insert(MO.getReg());
269b7718454SSanjoy Das       else
270b7718454SSanjoy Das         RegUses.insert(MO.getReg());
271b7718454SSanjoy Das     }
272b7718454SSanjoy Das   }
273b7718454SSanjoy Das 
27469fad079SSanjoy Das   return false;
27569fad079SSanjoy Das }
27669fad079SSanjoy Das 
27769fad079SSanjoy Das /// Wrap a machine load instruction, LoadMI, into a FAULTING_LOAD_OP machine
27869fad079SSanjoy Das /// instruction.  The FAULTING_LOAD_OP instruction does the same load as LoadMI
27969fad079SSanjoy Das /// (defining the same register), and branches to HandlerLabel if the load
28069fad079SSanjoy Das /// faults.  The FAULTING_LOAD_OP instruction is inserted at the end of MBB.
28169fad079SSanjoy Das MachineInstr *ImplicitNullChecks::insertFaultingLoad(MachineInstr *LoadMI,
28269fad079SSanjoy Das                                                      MachineBasicBlock *MBB,
28369fad079SSanjoy Das                                                      MCSymbol *HandlerLabel) {
28469fad079SSanjoy Das   DebugLoc DL;
28569fad079SSanjoy Das   unsigned NumDefs = LoadMI->getDesc().getNumDefs();
28669fad079SSanjoy Das   assert(NumDefs == 1 && "other cases unhandled!");
28769fad079SSanjoy Das   (void)NumDefs;
28869fad079SSanjoy Das 
28969fad079SSanjoy Das   unsigned DefReg = LoadMI->defs().begin()->getReg();
29069fad079SSanjoy Das   assert(std::distance(LoadMI->defs().begin(), LoadMI->defs().end()) == 1 &&
29169fad079SSanjoy Das          "expected exactly one def!");
29269fad079SSanjoy Das 
29369fad079SSanjoy Das   auto MIB = BuildMI(MBB, DL, TII->get(TargetOpcode::FAULTING_LOAD_OP), DefReg)
29469fad079SSanjoy Das                  .addSym(HandlerLabel)
29569fad079SSanjoy Das                  .addImm(LoadMI->getOpcode());
29669fad079SSanjoy Das 
29769fad079SSanjoy Das   for (auto &MO : LoadMI->uses())
29869fad079SSanjoy Das     MIB.addOperand(MO);
29969fad079SSanjoy Das 
30069fad079SSanjoy Das   MIB.setMemRefs(LoadMI->memoperands_begin(), LoadMI->memoperands_end());
30169fad079SSanjoy Das 
30269fad079SSanjoy Das   return MIB;
30369fad079SSanjoy Das }
30469fad079SSanjoy Das 
30569fad079SSanjoy Das /// Rewrite the null checks in NullCheckList into implicit null checks.
30669fad079SSanjoy Das void ImplicitNullChecks::rewriteNullChecks(
30769fad079SSanjoy Das     ArrayRef<ImplicitNullChecks::NullCheck> NullCheckList) {
30869fad079SSanjoy Das   DebugLoc DL;
30969fad079SSanjoy Das 
31069fad079SSanjoy Das   for (auto &NC : NullCheckList) {
31169fad079SSanjoy Das     MCSymbol *HandlerLabel = MMI->getContext().createTempSymbol();
31269fad079SSanjoy Das 
31369fad079SSanjoy Das     // Remove the conditional branch dependent on the null check.
31469fad079SSanjoy Das     unsigned BranchesRemoved = TII->RemoveBranch(*NC.CheckBlock);
31569fad079SSanjoy Das     (void)BranchesRemoved;
31669fad079SSanjoy Das     assert(BranchesRemoved > 0 && "expected at least one branch!");
31769fad079SSanjoy Das 
31869fad079SSanjoy Das     // Insert a faulting load where the conditional branch was originally.  We
31969fad079SSanjoy Das     // check earlier ensures that this bit of code motion is legal.  We do not
32069fad079SSanjoy Das     // touch the successors list for any basic block since we haven't changed
32169fad079SSanjoy Das     // control flow, we've just made it implicit.
32269fad079SSanjoy Das     insertFaultingLoad(NC.MemOperation, NC.CheckBlock, HandlerLabel);
323*c3a8e398SSanjoy Das     NC.MemOperation->eraseFromParent();
32469fad079SSanjoy Das     NC.CheckOperation->eraseFromParent();
32569fad079SSanjoy Das 
32669fad079SSanjoy Das     // Insert an *unconditional* branch to not-null successor.
32769fad079SSanjoy Das     TII->InsertBranch(*NC.CheckBlock, NC.NotNullSucc, nullptr, /*Cond=*/None,
32869fad079SSanjoy Das                       DL);
32969fad079SSanjoy Das 
33069fad079SSanjoy Das     // Emit the HandlerLabel as an EH_LABEL.
33169fad079SSanjoy Das     BuildMI(*NC.NullSucc, NC.NullSucc->begin(), DL,
33269fad079SSanjoy Das             TII->get(TargetOpcode::EH_LABEL)).addSym(HandlerLabel);
3338ee6a30bSSanjoy Das 
3348ee6a30bSSanjoy Das     NumImplicitNullChecks++;
33569fad079SSanjoy Das   }
33669fad079SSanjoy Das }
33769fad079SSanjoy Das 
33869fad079SSanjoy Das char ImplicitNullChecks::ID = 0;
33969fad079SSanjoy Das char &llvm::ImplicitNullChecksID = ImplicitNullChecks::ID;
34069fad079SSanjoy Das INITIALIZE_PASS_BEGIN(ImplicitNullChecks, "implicit-null-checks",
34169fad079SSanjoy Das                       "Implicit null checks", false, false)
34269fad079SSanjoy Das INITIALIZE_PASS_END(ImplicitNullChecks, "implicit-null-checks",
34369fad079SSanjoy Das                     "Implicit null checks", false, false)
344