diff options
Diffstat (limited to 'lib/CodeGen/ImplicitNullChecks.cpp')
-rw-r--r-- | lib/CodeGen/ImplicitNullChecks.cpp | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/lib/CodeGen/ImplicitNullChecks.cpp b/lib/CodeGen/ImplicitNullChecks.cpp index 308b6d293d3d..0a447bc613b1 100644 --- a/lib/CodeGen/ImplicitNullChecks.cpp +++ b/lib/CodeGen/ImplicitNullChecks.cpp @@ -115,7 +115,7 @@ class ImplicitNullChecks : public MachineFunctionPass { /// \c canHandle should return true for all instructions in \p /// Insts. DependenceResult computeDependence(const MachineInstr *MI, - ArrayRef<MachineInstr *> Insts); + ArrayRef<MachineInstr *> Block); /// Represents one null check that can be made implicit. class NullCheck { @@ -134,7 +134,7 @@ class ImplicitNullChecks : public MachineFunctionPass { // The block branched to if the pointer is null. MachineBasicBlock *NullSucc; - // If this is non-null, then MemOperation has a dependency on on this + // If this is non-null, then MemOperation has a dependency on this // instruction; and it needs to be hoisted to execute before MemOperation. MachineInstr *OnlyDependency; @@ -198,7 +198,7 @@ class ImplicitNullChecks : public MachineFunctionPass { SuitabilityResult isSuitableMemoryOp(MachineInstr &MI, unsigned PointerReg, ArrayRef<MachineInstr *> PrevInsts); - /// Return true if \p FaultingMI can be hoisted from after the the + /// Return true if \p FaultingMI can be hoisted from after the /// instructions in \p InstsSeenSoFar to before them. Set \p Dependence to a /// non-null value if we also need to (and legally can) hoist a depedency. bool canHoistInst(MachineInstr *FaultingMI, unsigned PointerReg, @@ -496,6 +496,32 @@ bool ImplicitNullChecks::analyzeBlockForNullChecks( if (NotNullSucc->pred_size() != 1) return false; + // To prevent the invalid transformation of the following code: + // + // mov %rax, %rcx + // test %rax, %rax + // %rax = ... + // je throw_npe + // mov(%rcx), %r9 + // mov(%rax), %r10 + // + // into: + // + // mov %rax, %rcx + // %rax = .... + // faulting_load_op("movl (%rax), %r10", throw_npe) + // mov(%rcx), %r9 + // + // we must ensure that there are no instructions between the 'test' and + // conditional jump that modify %rax. + const unsigned PointerReg = MBP.LHS.getReg(); + + assert(MBP.ConditionDef->getParent() == &MBB && "Should be in basic block"); + + for (auto I = MBB.rbegin(); MBP.ConditionDef != &*I; ++I) + if (I->modifiesRegister(PointerReg, TRI)) + return false; + // Starting with a code fragment like: // // test %rax, %rax @@ -550,8 +576,6 @@ bool ImplicitNullChecks::analyzeBlockForNullChecks( // ptr could be some non-null invalid reference that never gets loaded from // because some_cond is always true. - const unsigned PointerReg = MBP.LHS.getReg(); - SmallVector<MachineInstr *, 8> InstsSeenSoFar; for (auto &MI : *NotNullSucc) { @@ -596,9 +620,8 @@ MachineInstr *ImplicitNullChecks::insertFaultingInstr( unsigned DefReg = NoRegister; if (NumDefs != 0) { - DefReg = MI->defs().begin()->getReg(); - assert(std::distance(MI->defs().begin(), MI->defs().end()) == 1 && - "expected exactly one def!"); + DefReg = MI->getOperand(0).getReg(); + assert(NumDefs == 1 && "expected exactly one def!"); } FaultMaps::FaultKind FK; |