65 cl::desc(
"The page size of the target in bytes"),
69 "imp-null-max-insts-to-consider",
70 cl::desc(
"The max number of instructions to consider hoisting loads over " 71 "(the algorithm is quadratic over this number)"),
74 #define DEBUG_TYPE "implicit-null-checks" 77 "Number of explicit null checks made implicit");
94 struct DependenceResult {
106 : CanReorder(CanReorder), PotentialDependence(PotentialDependence) {
107 assert((!PotentialDependence || CanReorder) &&
108 "!CanReorder && PotentialDependence.hasValue() not allowed!");
147 : MemOperation(memOperation), CheckOperation(checkOperation),
148 CheckBlock(checkBlock), NotNullSucc(notNullSucc), NullSucc(nullSucc),
149 OnlyDependency(onlyDependency) {}
151 MachineInstr *getMemOperation()
const {
return MemOperation; }
153 MachineInstr *getCheckOperation()
const {
return CheckOperation; }
161 MachineInstr *getOnlyDependency()
const {
return OnlyDependency; }
178 AR_WillAliasEverything
186 enum SuitabilityResult {
198 SuitabilityResult isSuitableMemoryOp(
MachineInstr &
MI,
unsigned PointerReg,
204 bool canHoistInst(
MachineInstr *FaultingMI,
unsigned PointerReg,
233 auto IsRegMask = [](
const MachineOperand &MO) {
return MO.isRegMask(); };
237 "Calls were filtered out above!");
243 ImplicitNullChecks::DependenceResult
244 ImplicitNullChecks::computeDependence(
const MachineInstr *MI,
252 if (canReorder(*
I, MI))
260 return {
false,
None};
267 bool ImplicitNullChecks::canReorder(
const MachineInstr *A,
269 assert(canHandle(A) && canHandle(B) &&
"Precondition!");
276 if (!(MOA.isReg() && MOA.getReg()))
279 unsigned RegA = MOA.getReg();
281 if (!(MOB.isReg() && MOB.getReg()))
284 unsigned RegB = MOB.getReg();
286 if (TRI->
regsOverlap(RegA, RegB) && (MOA.isDef() || MOB.isDef()))
298 AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
303 analyzeBlockForNullChecks(MBB, NullCheckList);
305 if (!NullCheckList.
empty())
306 rewriteNullChecks(NullCheckList);
308 return !NullCheckList.
empty();
321 ImplicitNullChecks::AliasResult
322 ImplicitNullChecks::areMemoryOpsAliased(
MachineInstr &MI,
333 return MI.
mayStore() ? AR_WillAliasEverything : AR_MayAlias;
335 return PrevMI->
mayStore() ? AR_WillAliasEverything : AR_MayAlias;
340 assert(MMO1->getValue() &&
"MMO1 should have a Value!");
343 if (PSV->mayAlias(MFI))
359 ImplicitNullChecks::SuitabilityResult
360 ImplicitNullChecks::isSuitableMemoryOp(
MachineInstr &MI,
unsigned PointerReg,
366 !BaseOp->
isReg() || BaseOp->
getReg() != PointerReg)
367 return SR_Unsuitable;
373 return SR_Unsuitable;
376 for (
auto *PrevMI : PrevInsts) {
378 if (AR == AR_WillAliasEverything)
379 return SR_Impossible;
380 if (AR == AR_MayAlias)
381 return SR_Unsuitable;
386 bool ImplicitNullChecks::canHoistInst(
MachineInstr *FaultingMI,
391 auto DepResult = computeDependence(FaultingMI, InstsSeenSoFar);
392 if (!DepResult.CanReorder)
395 if (!DepResult.PotentialDependence) {
396 Dependence =
nullptr;
400 auto DependenceItr = *DepResult.PotentialDependence;
401 auto *DependenceMI = *DependenceItr;
408 assert(canHandle(DependenceMI) &&
"Should never have reached here!");
409 if (DependenceMI->mayLoadOrStore())
412 for (
auto &DependenceMO : DependenceMI->operands()) {
413 if (!(DependenceMO.isReg() && DependenceMO.getReg()))
439 assert(!(DependenceMO.isDef() &&
440 TRI->
regsOverlap(DependenceMO.getReg(), PointerReg)) &&
441 "Should have been checked before!");
445 computeDependence(DependenceMI, {InstsSeenSoFar.
begin(), DependenceItr});
447 if (!DepDepResult.CanReorder || DepDepResult.PotentialDependence)
450 Dependence = DependenceMI;
457 bool ImplicitNullChecks::analyzeBlockForNullChecks(
461 MDNode *BranchMD =
nullptr;
468 MachineBranchPredicate MBP;
474 if (!(MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&
481 if (!MBP.SingleUseCondition)
487 NotNullSucc = MBP.TrueDest;
488 NullSucc = MBP.FalseDest;
490 NotNullSucc = MBP.FalseDest;
491 NullSucc = MBP.TrueDest;
517 const unsigned PointerReg = MBP.LHS.getReg();
519 assert(MBP.ConditionDef->getParent() == &MBB &&
"Should be in basic block");
521 for (
auto I = MBB.
rbegin(); MBP.ConditionDef != &*
I; ++
I)
522 if (
I->modifiesRegister(PointerReg, TRI))
581 for (
auto &MI : *NotNullSucc) {
586 SuitabilityResult SR = isSuitableMemoryOp(MI, PointerReg, InstsSeenSoFar);
587 if (SR == SR_Impossible)
589 if (SR == SR_Suitable &&
590 canHoistInst(&MI, PointerReg, InstsSeenSoFar, NullSucc, Dependence)) {
591 NullCheckList.
emplace_back(&MI, MBP.ConditionDef, &MBB, NotNullSucc,
592 NullSucc, Dependence);
598 return MO.isReg() && MO.getReg() && MO.isDef() &&
614 const unsigned NoRegister = 0;
619 assert(NumDefs <= 1 &&
"other cases unhandled!");
621 unsigned DefReg = NoRegister;
624 assert(NumDefs == 1 &&
"expected exactly one def!");
634 auto MIB =
BuildMI(MBB, DL, TII->
get(TargetOpcode::FAULTING_OP), DefReg)
639 for (
auto &MO : MI->
uses()) {
645 assert(MO.isDef() &&
"Expected def or use");
660 void ImplicitNullChecks::rewriteNullChecks(
664 for (
auto &
NC : NullCheckList) {
666 unsigned BranchesRemoved = TII->
removeBranch(*
NC.getCheckBlock());
667 (void)BranchesRemoved;
668 assert(BranchesRemoved > 0 &&
"expected at least one branch!");
670 if (
auto *DepMI =
NC.getOnlyDependency()) {
671 DepMI->removeFromParent();
672 NC.getCheckBlock()->insert(
NC.getCheckBlock()->end(), DepMI);
680 NC.getMemOperation(),
NC.getCheckBlock(),
NC.getNullSucc());
687 if (!MO.isReg() || !MO.isDef())
689 unsigned Reg = MO.getReg();
690 if (!Reg || MBB->isLiveIn(Reg))
695 if (
auto *DepMI =
NC.getOnlyDependency()) {
696 for (
auto &MO : DepMI->operands()) {
697 if (!MO.isReg() || !MO.getReg() || !MO.isDef())
699 if (!
NC.getNotNullSucc()->isLiveIn(MO.getReg()))
700 NC.getNotNullSucc()->addLiveIn(MO.getReg());
704 NC.getMemOperation()->eraseFromParent();
705 NC.getCheckOperation()->eraseFromParent();
711 NumImplicitNullChecks++;
720 "Implicit null checks",
false,
false)
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
bool isCall(QueryType Type=AnyInBundle) const
This class represents lattice values for constants.
iterator_range< mop_iterator > uses()
Returns a range that includes all operands that are register uses.
static constexpr LocationSize unknown()
void push_back(const T &Elt)
unsigned getReg() const
getReg - Returns the register number.
bool isPredicable(QueryType Type=AllInBundle) const
Return true if this instruction has a predicate operand that controls execution.
The two locations do not alias at all.
virtual unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef< MachineOperand > Cond, const DebugLoc &DL, int *BytesAdded=nullptr) const
Insert branch code into the end of the specified MachineBasicBlock.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly...
STATISTIC(NumFunctions, "Total number of functions")
unsigned const TargetRegisterInfo * TRI
void setIsDead(bool Val=true)
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::Hidden, cl::init(8))
iterator_range< mop_iterator > operands()
virtual unsigned removeBranch(MachineBasicBlock &MBB, int *BytesRemoved=nullptr) const
Remove the branching code at the end of the specific MBB.
Represents a predicate at the MachineFunction level.
virtual bool getMemOperandWithOffset(MachineInstr &MI, MachineOperand *&BaseOp, int64_t &Offset, const TargetRegisterInfo *TRI) const
Get the base operand and byte offset of an instruction that reads/writes memory.
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
The main low level interface to the alias analysis implementation.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
A description of a memory reference used in the backend.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
The MachineFrameInfo class represents an abstract stack frame until prolog/epilog code is inserted...
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
virtual const TargetInstrInfo * getInstrInfo() const
reverse_iterator rbegin()
TargetInstrInfo - Interface to description of machine instruction set.
AliasResult
The possible results of an alias query.
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool mayStore(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly modify memory.
initializer< Ty > init(const Ty &Val)
const TargetRegisterInfo * getTargetRegisterInfo() const
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
ArrayRef< MachineMemOperand * > memoperands() const
Access to memory operands of the instruction.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
INITIALIZE_PASS_BEGIN(ImplicitNullChecks, DEBUG_TYPE, "Implicit null checks", false, false) INITIALIZE_PASS_END(ImplicitNullChecks
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...
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.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
void setIsKill(bool Val=true)
Representation for a specific memory location.
bool regsOverlap(unsigned regA, unsigned regB) const
Returns true if the two registers are equal or alias each other.
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 getNumDefs() const
Return the number of MachineOperands that are register definitions.
unsigned pred_size() const
bool isLiveIn(MCPhysReg Reg, LaneBitmask LaneMask=LaneBitmask::getAll()) const
Return true if the specified register is in the live in set.
Special value supplied for machine level alias analysis.
MachineFunctionProperties & set(Property P)
Representation of each machine instruction.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
void emplace_back(ArgTypes &&... Args)
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
virtual bool analyzeBranchPredicate(MachineBasicBlock &MBB, MachineBranchPredicate &MBP, bool AllowModify=false) const
Analyze the branching code at the end of MBB and parse it into the MachineBranchPredicate structure i...
LLVM_NODISCARD bool empty() const
This file provides utility analysis objects describing memory locations.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode...
static bool AnyAliasLiveIn(const TargetRegisterInfo *TRI, MachineBasicBlock *MBB, unsigned Reg)
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool mayLoad(QueryType Type=AnyInBundle) const
Return true if this instruction could possibly read memory.
bool memoperands_empty() const
Return true if we don't have any memory operands which described the memory access done by this instr...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by mayLoad / mayStore...
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object...
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned char TargetFlags=0) const
Dependence - This class represents a dependence between two memory memory references in a function...
const MachineOperand & getOperand(unsigned i) const
Properties which a MachineFunction may have at a given point in time.
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.