mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[MachineSink] Don't break ImplicitNulls
Summary: This teaches MachineSink to not sink instructions that might break the implicit null check optimization that runs later. This should not affect frontends that do not use implicit null checks. Reviewers: aadg, reames, hfinkel, atrick Subscribers: majnemer, llvm-commits Differential Revision: http://reviews.llvm.org/D14632 llvm-svn: 258254
This commit is contained in:
parent
85e195fefe
commit
d2d9b2b709
@ -27,6 +27,7 @@
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
#include "llvm/CodeGen/MachinePostDominators.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -673,6 +674,49 @@ MachineBasicBlock *MachineSinking::FindSuccToSinkTo(MachineInstr *MI,
|
||||
return SuccToSinkTo;
|
||||
}
|
||||
|
||||
/// \brief Return true if MI is likely to be usable as a memory operation by the
|
||||
/// implicit null check optimization.
|
||||
///
|
||||
/// This is a "best effort" heuristic, and should not be relied upon for
|
||||
/// correctness. This returning true does not guarantee that the implicit null
|
||||
/// check optimization is legal over MI, and this returning false does not
|
||||
/// guarantee MI cannot possibly be used to do a null check.
|
||||
static bool SinkingPreventsImplicitNullCheck(MachineInstr *MI,
|
||||
const TargetInstrInfo *TII,
|
||||
const TargetRegisterInfo *TRI) {
|
||||
typedef TargetInstrInfo::MachineBranchPredicate MachineBranchPredicate;
|
||||
|
||||
auto *MBB = MI->getParent();
|
||||
if (MBB->pred_size() != 1)
|
||||
return false;
|
||||
|
||||
auto *PredMBB = *MBB->pred_begin();
|
||||
auto *PredBB = PredMBB->getBasicBlock();
|
||||
|
||||
// Frontends that don't use implicit null checks have no reason to emit
|
||||
// branches with make.implicit metadata, and this function should always
|
||||
// return false for them.
|
||||
if (!PredBB ||
|
||||
!PredBB->getTerminator()->getMetadata(LLVMContext::MD_make_implicit))
|
||||
return false;
|
||||
|
||||
unsigned BaseReg, Offset;
|
||||
if (!TII->getMemOpBaseRegImmOfs(MI, BaseReg, Offset, TRI))
|
||||
return false;
|
||||
|
||||
if (!(MI->mayLoad() && !MI->isPredicable()))
|
||||
return false;
|
||||
|
||||
MachineBranchPredicate MBP;
|
||||
if (TII->AnalyzeBranchPredicate(*PredMBB, MBP, false))
|
||||
return false;
|
||||
|
||||
return MBP.LHS.isReg() && MBP.RHS.isImm() && MBP.RHS.getImm() == 0 &&
|
||||
(MBP.Predicate == MachineBranchPredicate::PRED_NE ||
|
||||
MBP.Predicate == MachineBranchPredicate::PRED_EQ) &&
|
||||
MBP.LHS.getReg() == BaseReg;
|
||||
}
|
||||
|
||||
/// SinkInstruction - Determine whether it is safe to sink the specified machine
|
||||
/// instruction out of its current block into a successor.
|
||||
bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore,
|
||||
@ -691,6 +735,11 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore,
|
||||
if (MI->isConvergent())
|
||||
return false;
|
||||
|
||||
// Don't break implicit null checks. This is a performance heuristic, and not
|
||||
// required for correctness.
|
||||
if (SinkingPreventsImplicitNullCheck(MI, TII, TRI))
|
||||
return false;
|
||||
|
||||
// FIXME: This should include support for sinking instructions within the
|
||||
// block they are currently in to shorten the live ranges. We often get
|
||||
// instructions sunk into the top of a large block, but it would be better to
|
||||
|
49
test/CodeGen/X86/machine-sink-and-implicit-null-checks.ll
Normal file
49
test/CodeGen/X86/machine-sink-and-implicit-null-checks.ll
Normal file
@ -0,0 +1,49 @@
|
||||
; RUN: llc -mtriple=x86_64-apple-macosx -O3 -enable-implicit-null-checks -o - < %s 2>&1 | FileCheck %s
|
||||
|
||||
declare void @throw0()
|
||||
declare void @throw1()
|
||||
|
||||
define i1 @f(i8* %p0, i8* %p1) {
|
||||
entry:
|
||||
%c0 = icmp eq i8* %p0, null
|
||||
br i1 %c0, label %throw0, label %continue0, !make.implicit !0
|
||||
|
||||
continue0:
|
||||
%v0 = load i8, i8* %p0
|
||||
%c1 = icmp eq i8* %p1, null
|
||||
br i1 %c1, label %throw1, label %continue1, !make.implicit !0
|
||||
|
||||
continue1:
|
||||
%v1 = load i8, i8* %p1
|
||||
%v = icmp eq i8 %v0, %v1
|
||||
ret i1 %v
|
||||
|
||||
throw0:
|
||||
call void @throw0()
|
||||
unreachable
|
||||
|
||||
throw1:
|
||||
call void @throw1()
|
||||
unreachable
|
||||
}
|
||||
|
||||
; Check that we have two implicit null checks in @f
|
||||
|
||||
; CHECK: __LLVM_FaultMaps:
|
||||
; CHECK-NEXT: .byte 1
|
||||
; CHECK-NEXT: .byte 0
|
||||
; CHECK-NEXT: .short 0
|
||||
; CHECK-NEXT: .long 1
|
||||
|
||||
; FunctionInfo[0] =
|
||||
|
||||
; FunctionAddress =
|
||||
; CHECK-NEXT: .quad _f
|
||||
|
||||
; NumFaultingPCs =
|
||||
; CHECK-NEXT: .long 2
|
||||
|
||||
; Reserved =
|
||||
; CHECK-NEXT: .long 0
|
||||
|
||||
!0 = !{}
|
Loading…
Reference in New Issue
Block a user