forked from OSchip/llvm-project
[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:
parent
f2e0d384e1
commit
4a8fe09040
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
||||
...
|
||||
|
|
Loading…
Reference in New Issue