51 cl::desc(
"The page size of the target in bytes"),
55 "imp-null-max-insts-to-consider",
56 cl::desc(
"The max number of instructions to consider hoisting loads over "
57 "(the algorithm is quadratic over this number)"),
60 #define DEBUG_TYPE "implicit-null-checks"
63 "Number of explicit null checks made implicit");
80 struct DependenceResult {
92 : CanReorder(CanReorder), PotentialDependence(PotentialDependence) {
93 assert((!PotentialDependence || CanReorder) &&
94 "!CanReorder && PotentialDependence.hasValue() not allowed!");
133 : MemOperation(memOperation), CheckOperation(checkOperation),
134 CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc),
135 OnlyDependency(onlyDependency) {}
137 MachineInstr *getMemOperation()
const {
return MemOperation; }
139 MachineInstr *getCheckOperation()
const {
return CheckOperation; }
147 MachineInstr *getOnlyDependency()
const {
return OnlyDependency; }
170 bool canHoistLoadInst(
MachineInstr *FaultingMI,
unsigned PointerReg,
198 auto IsRegMask = [](
const MachineOperand &MO) {
return MO.isRegMask(); };
202 "Calls were filtered out above!");
208 ImplicitNullChecks::DependenceResult
209 ImplicitNullChecks::computeDependence(
const MachineInstr *MI,
217 if (canReorder(*
I, MI))
225 return {
false,
None};
234 assert(canHandle(A) && canHandle(B) &&
"Precondition!");
241 if (!(MOA.isReg() && MOA.getReg()))
244 unsigned RegA = MOA.getReg();
246 if (!(MOB.isReg() && MOB.getReg()))
249 unsigned RegB = MOB.getReg();
251 if (TRI->regsOverlap(RegA, RegB))
263 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
268 analyzeBlockForNullChecks(
MBB, NullCheckList);
270 if (!NullCheckList.
empty())
271 rewriteNullChecks(NullCheckList);
273 return !NullCheckList.
empty();
286 bool ImplicitNullChecks::isSuitableMemoryOp(
292 BaseReg != PointerReg)
303 for (
auto *PrevMI : PrevInsts)
304 for (
auto &PrevMO : PrevMI->operands())
305 if (PrevMO.isReg() && PrevMO.getReg() &&
306 TRI->regsOverlap(PrevMO.getReg(), PointerReg))
312 bool ImplicitNullChecks::canHoistLoadInst(
316 auto DepResult = computeDependence(FaultingMI, InstsSeenSoFar);
317 if (!DepResult.CanReorder)
320 if (!DepResult.PotentialDependence) {
321 Dependence =
nullptr;
325 auto DependenceItr = *DepResult.PotentialDependence;
326 auto *DependenceMI = *DependenceItr;
331 assert(canHandle(DependenceMI) &&
"Should never have reached here!");
332 if (DependenceMI->mayLoad())
335 for (
auto &DependenceMO : DependenceMI->operands()) {
336 if (!(DependenceMO.isReg() && DependenceMO.getReg()))
362 assert(!TRI->regsOverlap(DependenceMO.getReg(), PointerReg) &&
363 "Should have been checked before!");
367 computeDependence(DependenceMI, {InstsSeenSoFar.
begin(), DependenceItr});
369 if (!DepDepResult.CanReorder || DepDepResult.PotentialDependence)
372 Dependence = DependenceMI;
379 bool ImplicitNullChecks::analyzeBlockForNullChecks(
383 MDNode *BranchMD =
nullptr;
390 MachineBranchPredicate MBP;
392 if (
TII->analyzeBranchPredicate(MBB, MBP,
true))
396 if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&
403 if (!MBP.SingleUseCondition)
409 NotNullSucc = MBP.TrueDest;
410 NullSucc = MBP.FalseDest;
412 NotNullSucc = MBP.FalseDest;
413 NullSucc = MBP.TrueDest;
475 const unsigned PointerReg = MBP.LHS.getReg();
479 for (
auto &MI : *NotNullSucc) {
484 if (isSuitableMemoryOp(MI, PointerReg, InstsSeenSoFar) &&
485 canHoistLoadInst(&MI, PointerReg, InstsSeenSoFar, NullSucc,
487 NullCheckList.
emplace_back(&MI, MBP.ConditionDef, &MBB, NotNullSucc,
488 NullSucc, Dependence);
503 ImplicitNullChecks::insertFaultingLoad(
MachineInstr *LoadMI,
506 const unsigned NoRegister = 0;
511 assert(NumDefs <= 1 &&
"other cases unhandled!");
513 unsigned DefReg = NoRegister;
515 DefReg = LoadMI->
defs().begin()->getReg();
516 assert(std::distance(LoadMI->
defs().begin(), LoadMI->
defs().end()) == 1 &&
517 "expected exactly one def!");
520 auto MIB =
BuildMI(MBB, DL,
TII->get(TargetOpcode::FAULTING_LOAD_OP), DefReg)
524 for (
auto &MO : LoadMI->
uses())
533 void ImplicitNullChecks::rewriteNullChecks(
537 for (
auto &
NC : NullCheckList) {
540 (void)BranchesRemoved;
541 assert(BranchesRemoved > 0 &&
"expected at least one branch!");
543 if (
auto *DepMI =
NC.getOnlyDependency()) {
544 DepMI->removeFromParent();
545 NC.getCheckBlock()->insert(
NC.getCheckBlock()->end(), DepMI);
553 NC.getMemOperation(),
NC.getCheckBlock(),
NC.getNullSucc());
560 if (!MO.isReg() || !MO.isDef())
562 unsigned Reg = MO.getReg();
563 if (!Reg || MBB->isLiveIn(Reg))
568 if (
auto *DepMI =
NC.getOnlyDependency()) {
569 for (
auto &MO : DepMI->operands()) {
570 if (!MO.isReg() || !MO.getReg() || !MO.isDef())
572 if (!
NC.getNotNullSucc()->isLiveIn(MO.getReg()))
573 NC.getNotNullSucc()->addLiveIn(MO.getReg());
577 NC.getMemOperation()->eraseFromParent();
578 NC.getCheckOperation()->eraseFromParent();
584 NumImplicitNullChecks++;
592 "Implicit null checks",
false,
false)
void push_back(const T &Elt)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
STATISTIC(NumFunctions,"Total number of functions")
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
INITIALIZE_PASS_BEGIN(ImplicitNullChecks,"implicit-null-checks","Implicit null checks", false, false) INITIALIZE_PASS_END(ImplicitNullChecks
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
bool isPredicable(QueryType Type=AllInBundle) const
Return true if this instruction has a predicate operand that controls execution.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly...
iterator_range< mmo_iterator > memoperands()
iterator_range< mop_iterator > operands()
Represents a predicate at the MachineFunction level.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
A description of a memory reference used in the backend.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
const TargetRegisterInfo * getTargetRegisterInfo() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
implicit null Implicit null false
Reg
All possible values of the reg field in the ModR/M byte.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
LLVM_NODISCARD bool empty() const
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096))
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
static cl::opt< unsigned > MaxInstsToConsider("imp-null-max-insts-to-consider", cl::desc("The max number of instructions to consider hoisting loads over ""(the algorithm is quadratic over this number)"), cl::init(8))
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
TargetInstrInfo - Interface to description of machine instruction set.
mmo_iterator memoperands_end() const
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
initializer< Ty > init(const Ty &Val)
const MachineInstrBuilder & setMemRefs(MachineInstr::mmo_iterator b, MachineInstr::mmo_iterator e) const
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
MCRegAliasIterator enumerates all registers aliasing Reg.
Represent the analysis usage information of a pass.
bool any_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly...
iterator_range< mop_iterator > defs()
Returns a range over all explicit operands that are register definitions.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by mayLoad / mayStore...
void initializeImplicitNullChecksPass(PassRegistry &)
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
char & ImplicitNullChecksID
ImplicitNullChecks - This pass folds null pointer checks into nearby memory operations.
MachineOperand class - Representation of each machine instruction operand.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef< MachineOperand > Cond, const DebugLoc &DL, int *BytesAdded=nullptr) const override
Insert branch code into the end of the specified MachineBasicBlock.
unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const override
Remove the branching code at the end of the specific MBB.
MachineFunctionProperties & set(Property P)
Representation of each machine instruction.
void emplace_back(ArgTypes &&...Args)
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
static bool AnyAliasLiveIn(const TargetRegisterInfo *TRI, MachineBasicBlock *MBB, unsigned Reg)
bool isCall(QueryType Type=AnyInBundle) const
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
bool isLiveIn(MCPhysReg Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
virtual const TargetInstrInfo * getInstrInfo() const
const MachineInstrBuilder & addOperand(const MachineOperand &MO) const
MachineModuleInfo & getMMI() const
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object...
bool getMemOpBaseRegImmOfs(MachineInstr &LdSt, unsigned &BaseReg, int64_t &Offset, const TargetRegisterInfo *TRI) const override
Get the base register and byte offset of a load/store instr.
Dependence - This class represents a dependence between two memory memory references in a function...
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")
unsigned pred_size() const
Properties which a MachineFunction may have at a given point in time.
This class contains meta information specific to a module.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.