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
DependenceResult__anon6ef3ccad0111::ImplicitNullChecks::DependenceResult1010b57cec5SDimitry 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:
NullCheck(MachineInstr * memOperation,MachineInstr * checkOperation,MachineBasicBlock * checkBlock,MachineBasicBlock * notNullSucc,MachineBasicBlock * nullSucc,MachineInstr * onlyDependency)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
getMemOperation() const1490b57cec5SDimitry Andric MachineInstr *getMemOperation() const { return MemOperation; }
1500b57cec5SDimitry Andric
getCheckOperation() const1510b57cec5SDimitry Andric MachineInstr *getCheckOperation() const { return CheckOperation; }
1520b57cec5SDimitry Andric
getCheckBlock() const1530b57cec5SDimitry Andric MachineBasicBlock *getCheckBlock() const { return CheckBlock; }
1540b57cec5SDimitry Andric
getNotNullSucc() const1550b57cec5SDimitry Andric MachineBasicBlock *getNotNullSucc() const { return NotNullSucc; }
1560b57cec5SDimitry Andric
getNullSucc() const1570b57cec5SDimitry Andric MachineBasicBlock *getNullSucc() const { return NullSucc; }
1580b57cec5SDimitry Andric
getOnlyDependency() const1590b57cec5SDimitry 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
ImplicitNullChecks()2170b57cec5SDimitry Andric ImplicitNullChecks() : MachineFunctionPass(ID) {
2180b57cec5SDimitry Andric initializeImplicitNullChecksPass(*PassRegistry::getPassRegistry());
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
2220b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const2230b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
2240b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>();
2250b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric
getRequiredProperties() const2280b57cec5SDimitry 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
canHandle(const MachineInstr * MI)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
computeDependence(const MachineInstr * MI,ArrayRef<MachineInstr * > Block)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
canReorder(const MachineInstr * A,const MachineInstr * B)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
runOnMachineFunction(MachineFunction & MF)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.
AnyAliasLiveIn(const TargetRegisterInfo * TRI,MachineBasicBlock * MBB,unsigned Reg)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
areMemoryOpsAliased(const MachineInstr & MI,const MachineInstr * PrevMI) const3290b57cec5SDimitry 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
isSuitableMemoryOp(const MachineInstr & MI,unsigned PointerReg,ArrayRef<MachineInstr * > PrevInsts)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
canDependenceHoistingClobberLiveIns(MachineInstr * DependenceMI,MachineBasicBlock * NullSucc)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
canHoistInst(MachineInstr * FaultingMI,ArrayRef<MachineInstr * > InstsSeenSoFar,MachineBasicBlock * NullSucc,MachineInstr * & Dependence)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.
analyzeBlockForNullChecks(MachineBasicBlock & MBB,SmallVectorImpl<NullCheck> & NullCheckList)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.
insertFaultingInstr(MachineInstr * MI,MachineBasicBlock * MBB,MachineBasicBlock * HandlerMBB)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.
rewriteNullChecks(ArrayRef<ImplicitNullChecks::NullCheck> NullCheckList)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