aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/ImplicitNullChecks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/ImplicitNullChecks.cpp')
-rw-r--r--lib/CodeGen/ImplicitNullChecks.cpp39
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;