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 308b6d293d3df..0a447bc613b17 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;  | 
