[ImplicitNullCheck] Fix an edge case where we were hoisting incorrectly

ImplicitNullCheck keeps track of one instruction that the memory
operation depends on that it also hoists with the memory operation.
When hoisting this dependency, it would sometimes clobber a live-in
value to the basic block we were hoisting the two things out of.  Fix
this by explicitly looking for such dependencies.

I also noticed two redundant checks on `MO.isDef()` in IsMIOperandSafe.
They're redundant since register MachineOperands are either Defs or Uses
-- there is no third kind.  I'll change the checks to asserts in a later
commit.

llvm-svn: 287213
This commit is contained in:
Sanjoy Das 2016-11-17 07:29:40 +00:00
parent f2e0d384e1
commit 4a8fe09040
2 changed files with 77 additions and 1 deletions

View File

@ -268,7 +268,25 @@ bool HazardDetector::isSafeToHoist(MachineInstr *MI,
return false;
assert((!MO.isDef() || RegDefs.count(MO.getReg())) &&
"All defs must be tracked in RegDefs by now!");
return !MO.isDef() || RegDefs.find(MO.getReg())->second == MI;
if (!MO.isDef()) {
// FIXME: This is unnecessary, we should be able to
// assert(MO.isDef()) here.
return true;
}
for (unsigned Reg : RegUses)
if (TRI.regsOverlap(Reg, MO.getReg()))
return false; // We found a write-after-read
for (auto &OtherDef : RegDefs) {
unsigned OtherReg = OtherDef.first;
MachineInstr *OtherMI = OtherDef.second;
if (OtherMI != MI && TRI.regsOverlap(OtherReg, MO.getReg()))
return false;
}
return true;
};
if (!all_of(MI->operands(), IsMIOperandSafe))

View File

@ -95,6 +95,26 @@
ret i32 0
}
define i32 @dependency_live_in_hazard(i32* %ptr, i32** %ptr2, i32* %ptr3) #0 {
entry:
%val = load i32*, i32** %ptr2
%ptr_is_null = icmp eq i32* %ptr, null
br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0
not_null: ; preds = %entry
%addend = load i32, i32* %val
%result = load i32, i32* %ptr
%result.shr = lshr i32 %result, 4
%result.and = and i32 %result.shr, 4095
%result.add = add i32 %addend, %result.and
ret i32 %result.add
is_null: ; preds = %entry
ret i32 0
}
attributes #0 = { "target-features"="+bmi,+bmi2" }
!0 = !{}
...
---
@ -312,3 +332,41 @@ body: |
RETQ %eax
...
---
name: dependency_live_in_hazard
# CHECK-LABEL: name: dependency_live_in_hazard
# CHECK: bb.0.entry:
# CHECK-NOT: FAULTING_LOAD_OP
# CHECK: bb.1.not_null:
# Make sure that the BEXTR32rm instruction below is not used to emit
# an implicit null check -- hoisting it will require hosting the move
# to %esi and we cannot do that without clobbering the use of %rsi in
# the first instruction in bb.1.not_null.
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '%rdi' }
- { reg: '%rsi' }
body: |
bb.0.entry:
successors: %bb.2.is_null, %bb.1.not_null
liveins: %rdi, %rsi
TEST64rr %rdi, %rdi, implicit-def %eflags
JE_1 %bb.2.is_null, implicit killed %eflags
bb.1.not_null:
liveins: %rdi, %rsi
%rcx = MOV64rm killed %rsi, 1, _, 0, _ :: (load 8 from %ir.ptr2)
%esi = MOV32ri 3076
%eax = BEXTR32rm killed %rdi, 1, _, 0, _, killed %esi, implicit-def dead %eflags :: (load 4 from %ir.ptr)
%eax = ADD32rm killed %eax, killed %rcx, 1, _, 0, _, implicit-def dead %eflags :: (load 4 from %ir.val)
RETQ %eax
bb.2.is_null:
%eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags
RETQ %eax
...