[ImplicitNullCheck] Extend canReorder scope

Summary:
This change allows a re-order of two intructions if their uses
are overlapped.

Patch by Serguei Katkov!

Reviewers: reames, sanjoy

Reviewed By: sanjoy

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D29120

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293775 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjoy Das 2017-02-01 16:04:21 +00:00
parent ab1df8f850
commit 2e079eaf6b
3 changed files with 142 additions and 7 deletions

View File

@ -253,7 +253,7 @@ bool ImplicitNullChecks::canReorder(const MachineInstr *A,
unsigned RegB = MOB.getReg();
if (TRI->regsOverlap(RegA, RegB))
if (TRI->regsOverlap(RegA, RegB) && (MOA.isDef() || MOB.isDef()))
return false;
}
}
@ -310,7 +310,7 @@ ImplicitNullChecks::isSuitableMemoryOp(MachineInstr &MI, unsigned PointerReg,
// lookup due to this condition will fail for any further instruction.
for (auto *PrevMI : PrevInsts)
for (auto &PrevMO : PrevMI->operands())
if (PrevMO.isReg() && PrevMO.getReg() &&
if (PrevMO.isReg() && PrevMO.getReg() && PrevMO.isDef() &&
TRI->regsOverlap(PrevMO.getReg(), PointerReg))
return SR_Impossible;
@ -367,7 +367,8 @@ bool ImplicitNullChecks::canHoistLoadInst(
// The Dependency can't be re-defining the base register -- then we won't
// get the memory operation on the address we want. This is already
// checked in \c IsSuitableMemoryOp.
assert(!TRI->regsOverlap(DependenceMO.getReg(), PointerReg) &&
assert(!(DependenceMO.isDef() &&
TRI->regsOverlap(DependenceMO.getReg(), PointerReg)) &&
"Should have been checked before!");
}

View File

@ -135,6 +135,33 @@ define i32 @imp_null_check_via_mem_comparision(i32* %x, i32 %val) {
ret i32 200
}
define i32 @imp_null_check_gep_load_with_use_dep(i32* %x, i32 %a) {
; CHECK-LABEL: imp_null_check_gep_load_with_use_dep:
; CHECK: [[BB0_imp_null_check_gep_load_with_use_dep:L[^:]+]]:
; CHECK: movl (%rdi), %eax
; CHECK: addl %edi, %esi
; CHECK: leal 4(%rax,%rsi), %eax
; CHECK: retq
; CHECK: [[BB1_imp_null_check_gep_load_with_use_dep:LBB5_[0-9]+]]:
; CHECK: movl $42, %eax
; CHECK: retq
entry:
%c = icmp eq i32* %x, null
br i1 %c, label %is_null, label %not_null, !make.implicit !0
is_null:
ret i32 42
not_null:
%x.loc = getelementptr i32, i32* %x, i32 1
%y = ptrtoint i32* %x.loc to i32
%b = add i32 %a, %y
%t = load i32, i32* %x
%z = add i32 %t, %b
ret i32 %z
}
!0 = !{}
; CHECK-LABEL: __LLVM_FaultMaps:
@ -147,7 +174,7 @@ define i32 @imp_null_check_via_mem_comparision(i32* %x, i32 %val) {
; CHECK-NEXT: .short 0
; # functions:
; CHECK-NEXT: .long 5
; CHECK-NEXT: .long 6
; FunctionAddr:
; CHECK-NEXT: .quad _imp_null_check_add_result
@ -175,6 +202,19 @@ define i32 @imp_null_check_via_mem_comparision(i32* %x, i32 %val) {
; Fault[0].HandlerOffset:
; CHECK-NEXT: .long [[BB1_imp_null_check_gep_load]]-_imp_null_check_gep_load
; FunctionAddr:
; CHECK-NEXT: .quad _imp_null_check_gep_load_with_use_dep
; NumFaultingPCs
; CHECK-NEXT: .long 1
; Reserved:
; CHECK-NEXT: .long 0
; Fault[0].Type:
; CHECK-NEXT: .long 1
; Fault[0].FaultOffset:
; CHECK-NEXT: .long [[BB0_imp_null_check_gep_load_with_use_dep]]-_imp_null_check_gep_load_with_use_dep
; Fault[0].HandlerOffset:
; CHECK-NEXT: .long [[BB1_imp_null_check_gep_load_with_use_dep]]-_imp_null_check_gep_load_with_use_dep
; FunctionAddr:
; CHECK-NEXT: .quad _imp_null_check_hoist_over_unrelated_load
; NumFaultingPCs
@ -216,12 +256,14 @@ define i32 @imp_null_check_via_mem_comparision(i32* %x, i32 %val) {
; OBJDUMP: FaultMap table:
; OBJDUMP-NEXT: Version: 0x1
; OBJDUMP-NEXT: NumFunctions: 5
; OBJDUMP-NEXT: NumFunctions: 6
; OBJDUMP-NEXT: FunctionAddress: 0x000000, NumFaultingPCs: 1
; OBJDUMP-NEXT: Fault kind: FaultingLoad, faulting PC offset: 0, handling PC offset: 5
; OBJDUMP-NEXT: FunctionAddress: 0x000000, NumFaultingPCs: 1
; OBJDUMP-NEXT: Fault kind: FaultingLoad, faulting PC offset: 0, handling PC offset: 7
; OBJDUMP-NEXT: FunctionAddress: 0x000000, NumFaultingPCs: 1
; OBJDUMP-NEXT: Fault kind: FaultingLoad, faulting PC offset: 0, handling PC offset: 9
; OBJDUMP-NEXT: FunctionAddress: 0x000000, NumFaultingPCs: 1
; OBJDUMP-NEXT: Fault kind: FaultingLoad, faulting PC offset: 0, handling PC offset: 7
; OBJDUMP-NEXT: FunctionAddress: 0x000000, NumFaultingPCs: 1
; OBJDUMP-NEXT: Fault kind: FaultingLoad, faulting PC offset: 0, handling PC offset: 3

View File

@ -145,6 +145,35 @@
attributes #0 = { "target-features"="+bmi,+bmi2" }
define i32 @imp_null_check_gep_load_with_use_dep(i32* %x, i32 %a) {
entry:
%c = icmp eq i32* %x, null
br i1 %c, label %is_null, label %not_null, !make.implicit !0
is_null: ; preds = %entry
ret i32 42
not_null: ; preds = %entry
%x.loc = getelementptr i32, i32* %x, i32 1
%y = ptrtoint i32* %x.loc to i32
%b = add i32 %a, %y
%t = load i32, i32* %x
%z = add i32 %t, %b
ret i32 %z
}
define i32 @imp_null_check_load_with_base_sep(i32* %x, i32 %a) {
entry:
%c = icmp eq i32* %x, null
br i1 %c, label %is_null, label %not_null, !make.implicit !0
is_null: ; preds = %entry
ret i32 42
not_null: ; preds = %entry
ret i32 undef
}
!0 = !{}
...
---
@ -447,8 +476,8 @@ body: |
name: use_alternate_load_op
# CHECK-LABEL: use_alternate_load_op
# CHECK: bb.0.entry:
# CHECK: TEST64rr %rdi, %rdi, implicit-def %eflags
# CHECK-NEXT: JE_1 %bb.2.is_null, implicit killed %eflags
# CHECK: %r10 = FAULTING_LOAD_OP %bb.2.is_null, {{[0-9]+}}, killed %rdi, 1, _, 0, _
# CHECK-NEXT: JMP_1 %bb.1.not_null
# CHECK: bb.1.not_null
alignment: 4
@ -477,3 +506,66 @@ body: |
RETQ %eax
...
---
name: imp_null_check_gep_load_with_use_dep
# CHECK: bb.0.entry:
# CHECK: %eax = FAULTING_LOAD_OP %bb.2.is_null, {{[0-9]+}}, killed %rdi, 1, _, 0, _, implicit-def %rax :: (load 4 from %ir.x)
# CHECK-NEXT: JMP_1 %bb.1.not_null
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '%rdi' }
- { reg: '%rsi' }
body: |
bb.0.entry:
successors: %bb.1.is_null(0x30000000), %bb.2.not_null(0x50000000)
liveins: %rsi, %rdi
TEST64rr %rdi, %rdi, implicit-def %eflags
JE_1 %bb.1.is_null, implicit %eflags
bb.2.not_null:
liveins: %rdi, %rsi
%rsi = ADD64rr %rsi, %rdi, implicit-def dead %eflags
%eax = MOV32rm killed %rdi, 1, _, 0, _, implicit-def %rax :: (load 4 from %ir.x)
%eax = LEA64_32r killed %rax, 1, killed %rsi, 4, _
RETQ %eax
bb.1.is_null:
%eax = MOV32ri 42
RETQ %eax
...
---
name: imp_null_check_load_with_base_sep
# CHECK: bb.0.entry:
# CHECK: %rsi = ADD64rr %rsi, %rdi, implicit-def dead %eflags
# CHECK-NEXT: %esi = FAULTING_LOAD_OP %bb.2.is_null, {{[0-9]+}}, killed %esi, %rdi, 1, _, 0, _, implicit-def dead %eflags
# CHECK-NEXT: JMP_1 %bb.1.not_null
alignment: 4
tracksRegLiveness: true
liveins:
- { reg: '%rdi' }
- { reg: '%rsi' }
body: |
bb.0.entry:
successors: %bb.1.is_null(0x30000000), %bb.2.not_null(0x50000000)
liveins: %rsi, %rdi
TEST64rr %rdi, %rdi, implicit-def %eflags
JE_1 %bb.1.is_null, implicit %eflags
bb.2.not_null:
liveins: %rdi, %rsi
%rsi = ADD64rr %rsi, %rdi, implicit-def dead %eflags
%esi = AND32rm killed %esi, %rdi, 1, _, 0, _, implicit-def dead %eflags
%eax = MOV32rr %esi
RETQ %eax
bb.1.is_null:
%eax = MOV32ri 42
RETQ %eax
...