Index: lib/CodeGen/ImplicitNullChecks.cpp =================================================================== --- lib/CodeGen/ImplicitNullChecks.cpp +++ lib/CodeGen/ImplicitNullChecks.cpp @@ -170,6 +170,8 @@ /// \p PrevMI, AR_MayAlias if they may alias and AR_WillAliasEverything if /// they may alias and any further memory operation may alias with \p PrevMI. AliasResult areMemoryOpsAliased(MachineInstr &MI, MachineInstr *PrevMI); + AliasResult areMemoryOpsAliased(MachineInstr &MI, + ArrayRef Block); enum SuitabilityResult { SR_Suitable, @@ -307,6 +309,17 @@ ImplicitNullChecks::AliasResult ImplicitNullChecks::areMemoryOpsAliased(MachineInstr &MI, + ArrayRef Block) { + for (auto *PrevMI : Block) { + AliasResult AR = areMemoryOpsAliased(MI, PrevMI); + if (AR != AR_NoAlias) + return AR; + } + return AR_NoAlias; +} + +ImplicitNullChecks::AliasResult +ImplicitNullChecks::areMemoryOpsAliased(MachineInstr &MI, MachineInstr *PrevMI) { // If it is not memory access, skip the check. if (!(PrevMI->mayStore() || PrevMI->mayLoad())) @@ -322,15 +335,38 @@ return PrevMI->mayStore() ? AR_WillAliasEverything : AR_MayAlias; for (MachineMemOperand *MMO1 : MI.memoperands()) { - // MMO1 should have a value due it comes from operation we'd like to use - // as implicit null check. - assert(MMO1->getValue() && "MMO1 should have a Value!"); + // Remember whether MMO1 is a pseudo value. + const PseudoSourceValue *PSV1 = MMO1->getPseudoValue(); + for (MachineMemOperand *MMO2 : PrevMI->memoperands()) { - if (const PseudoSourceValue *PSV = MMO2->getPseudoValue()) { - if (PSV->mayAlias(MFI)) + if (const PseudoSourceValue *PSV2 = MMO2->getPseudoValue()) { + if (PSV1) { + // Special case, both are pseudo values. + // If they are of different kind they are not alias. + if (PSV1->kind() != PSV2->kind()) + continue; + // If both of them are Fixed stack slot then check whether it is the + // same index. + // Otherwise they may alias for simplification. + if (auto *FSPSV1 = + dyn_cast_or_null(PSV1)) + if (auto *FSPSV2 = dyn_cast(PSV2)) + if (FSPSV1->getFrameIndex() != FSPSV2->getFrameIndex()) + continue; + return AR_MayAlias; + } + // The MMO1 is not pseudo while MMO2 is pseudo. + if (PSV2->mayAlias(MFI)) return AR_MayAlias; continue; } + // MMO2 is not a pseudo source value. If MMO1 is then check it. + if (PSV1) { + if (PSV1->mayAlias(MFI)) + return AR_MayAlias; + continue; + } + // Both MMO1 and MMO2 has value represented by LLVM IR. llvm::AliasResult AAResult = AA->alias( MemoryLocation(MMO1->getValue(), MemoryLocation::UnknownSize, MMO1->getAAInfo()), @@ -360,13 +396,11 @@ return SR_Unsuitable; // Finally, check whether the current memory access aliases with previous one. - for (auto *PrevMI : PrevInsts) { - AliasResult AR = areMemoryOpsAliased(MI, PrevMI); - if (AR == AR_WillAliasEverything) - return SR_Impossible; - if (AR == AR_MayAlias) - return SR_Unsuitable; - } + AliasResult AR = areMemoryOpsAliased(MI, PrevInsts); + if (AR == AR_WillAliasEverything) + return SR_Impossible; + if (AR == AR_MayAlias) + return SR_Unsuitable; return SR_Suitable; } @@ -432,6 +466,12 @@ if (!DepDepResult.CanReorder || DepDepResult.PotentialDependence) return false; + // Verify that DependenceMI does not alias with any instructions seen so far. + if (DependenceMI->mayLoadOrStore()) + if (areMemoryOpsAliased(*DependenceMI, { InstsSeenSoFar.begin(), + DependenceItr }) != AR_NoAlias) + return false; + Dependence = DependenceMI; return true; } Index: test/CodeGen/X86/implicit-null-checks.mir =================================================================== --- test/CodeGen/X86/implicit-null-checks.mir +++ test/CodeGen/X86/implicit-null-checks.mir @@ -365,6 +365,30 @@ ret i32 undef } + define i32 @inc_spill_dep(i32* %ptr, i32 %val) { + entry: + %ptr_is_null = icmp eq i32* %ptr, null + br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0 + + not_null: + ret i32 undef + + is_null: + ret i32 undef + } + + define i32 @inc_spill_dep_good(i32* %ptr, i32 %val) { + entry: + %ptr_is_null = icmp eq i32* %ptr, null + br i1 %ptr_is_null, label %is_null, label %not_null, !make.implicit !0 + + not_null: + ret i32 undef + + is_null: + ret i32 undef + } + attributes #0 = { "target-features"="+bmi,+bmi2" } !0 = !{} @@ -1265,3 +1289,80 @@ RETQ %eax ... +--- +name: inc_spill_dep +# CHECK-LABEL: inc_spill_dep +# CHECK: bb.0.entry: +# CHECK: TEST64rr %rdi, %rdi, implicit-def %eflags +# CHECK-NEXT: JE_1 %bb.2.is_null, implicit killed %eflags +# CHECK: bb.1.not_null + +alignment: 4 +tracksRegLiveness: true +stack: + - { id: 0, type: spill-slot, offset: -8, size: 8, alignment: 8} +liveins: + - { reg: '%rdi' } + - { reg: '%rsi' } +body: | + bb.0.entry: + liveins: %rdi, %rsi + + %rsp = frame-setup SUB64ri8 %rsp, 8, implicit-def dead %eflags + MOV32mr %rsp, 1, %noreg, 0, %noreg, %esi :: (store 4 into %stack.0) + TEST64rr %rdi, %rdi, implicit-def %eflags + JE_1 %bb.2.is_null, implicit killed %eflags + + bb.1.not_null: + liveins: %rdi, %rsi + + %r14d = MOV32rm %rsp, 1, %noreg, 0, %noreg :: (load 4 from %stack.0) + MOV64mr %rsp, 1, %noreg, 0, %noreg, %rdi :: (store 8 into %stack.0) + %edi = MOV32rm %rdi, 1, %noreg, 8, %noreg :: (load 4 from %ir.ptr) + %eax = MOV32rr %edi + RETQ %eax + + bb.2.is_null: + %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags + RETQ %eax + +... +--- +name: inc_spill_dep_good +# CHECK-LABEL: inc_spill_dep_good +# CHECK: bb.0.entry: +# CHECK: %edi = FAULTING_OP 1, %bb.2.is_null, {{[0-9]+}}, %rdi, 1, _, 8, _ :: (load 4 from %ir.ptr) +# CHECK-NEXT: JMP_1 %bb.1.not_null +# CHECK: bb.1.not_null + +alignment: 4 +tracksRegLiveness: true +stack: + - { id: 0, type: spill-slot, offset: -8, size: 8, alignment: 8} + - { id: 1, type: spill-slot, offset: -16, size: 8, alignment: 8} +liveins: + - { reg: '%rdi' } + - { reg: '%rsi' } +body: | + bb.0.entry: + liveins: %rdi, %rsi + + %rsp = frame-setup SUB64ri8 %rsp, 8, implicit-def dead %eflags + MOV32mr %rsp, 1, %noreg, 0, %noreg, %esi :: (store 4 into %stack.1) + TEST64rr %rdi, %rdi, implicit-def %eflags + JE_1 %bb.2.is_null, implicit killed %eflags + + bb.1.not_null: + liveins: %rdi, %rsi + + %r14d = MOV32rm %rsp, 1, %noreg, 0, %noreg :: (load 4 from %stack.1) + MOV64mr %rsp, 1, %noreg, 0, %noreg, %rdi :: (store 8 into %stack.0) + %edi = MOV32rm %rdi, 1, %noreg, 8, %noreg :: (load 4 from %ir.ptr) + %eax = MOV32rr %edi + RETQ %eax + + bb.2.is_null: + %eax = XOR32rr undef %eax, undef %eax, implicit-def dead %eflags + RETQ %eax + +...