forked from OSchip/llvm-project
[InstCombine] Teach the move free before null test opti how to deal with noop casts
InstCombine features an optimization that essentially replaces: if (a) free(a) into: free(a) Right now, this optimization is gated by the minsize attribute and therefore we only perform it if we can prove that we are going to be able to eliminate the branch and the destination block. However when casts are involved the optimization would fail to apply, because the optimization was not smart enough to realize that it is possible to also move the casts away from the destination block and that is harmless to the performance since they are just noops. E.g., foo(int *a) if (a) free((char*)a) Wouldn't be optimized by instcombine, because - We would refuse to hoist the `bitcast i32* %a to i8` in the source block - We would fail to see that `bitcast i32* %a to i8` and %a are the same value. This patch fixes both these problems: - It teaches the pattern matching of the comparison how to look through casts. - It checks that whether the additional instruction in the destination block can be hoisted and are harmless performance-wise. - It hoists all the code of the destination block in the source block. Differential Revision: D53356 llvm-svn: 345644
This commit is contained in:
parent
93a64efcd3
commit
900678227c
|
@ -2322,14 +2322,14 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
|
|||
/// The move is performed only if the block containing the call to free
|
||||
/// will be removed, i.e.:
|
||||
/// 1. it has only one predecessor P, and P has two successors
|
||||
/// 2. it contains the call and an unconditional branch
|
||||
/// 2. it contains the call, noops, and an unconditional branch
|
||||
/// 3. its successor is the same as its predecessor's successor
|
||||
///
|
||||
/// The profitability is out-of concern here and this function should
|
||||
/// be called only if the caller knows this transformation would be
|
||||
/// profitable (e.g., for code size).
|
||||
static Instruction *
|
||||
tryToMoveFreeBeforeNullTest(CallInst &FI) {
|
||||
static Instruction *tryToMoveFreeBeforeNullTest(CallInst &FI,
|
||||
const DataLayout &DL) {
|
||||
Value *Op = FI.getArgOperand(0);
|
||||
BasicBlock *FreeInstrBB = FI.getParent();
|
||||
BasicBlock *PredBB = FreeInstrBB->getSinglePredecessor();
|
||||
|
@ -2342,20 +2342,34 @@ tryToMoveFreeBeforeNullTest(CallInst &FI) {
|
|||
return nullptr;
|
||||
|
||||
// Validate constraint #2: Does this block contains only the call to
|
||||
// free and an unconditional branch?
|
||||
// FIXME: We could check if we can speculate everything in the
|
||||
// predecessor block
|
||||
if (FreeInstrBB->size() != 2)
|
||||
return nullptr;
|
||||
// free, noops, and an unconditional branch?
|
||||
BasicBlock *SuccBB;
|
||||
if (!match(FreeInstrBB->getTerminator(), m_UnconditionalBr(SuccBB)))
|
||||
Instruction *FreeInstrBBTerminator = FreeInstrBB->getTerminator();
|
||||
if (!match(FreeInstrBBTerminator, m_UnconditionalBr(SuccBB)))
|
||||
return nullptr;
|
||||
|
||||
// If there are only 2 instructions in the block, at this point,
|
||||
// this is the call to free and unconditional.
|
||||
// If there are more than 2 instructions, check that they are noops
|
||||
// i.e., they won't hurt the performance of the generated code.
|
||||
if (FreeInstrBB->size() != 2) {
|
||||
for (const Instruction &Inst : *FreeInstrBB) {
|
||||
if (&Inst == &FI || &Inst == FreeInstrBBTerminator)
|
||||
continue;
|
||||
auto *Cast = dyn_cast<CastInst>(&Inst);
|
||||
if (!Cast || !Cast->isNoopCast(DL))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Validate the rest of constraint #1 by matching on the pred branch.
|
||||
Instruction *TI = PredBB->getTerminator();
|
||||
BasicBlock *TrueBB, *FalseBB;
|
||||
ICmpInst::Predicate Pred;
|
||||
if (!match(TI, m_Br(m_ICmp(Pred, m_Specific(Op), m_Zero()), TrueBB, FalseBB)))
|
||||
if (!match(TI, m_Br(m_ICmp(Pred,
|
||||
m_CombineOr(m_Specific(Op),
|
||||
m_Specific(Op->stripPointerCasts())),
|
||||
m_Zero()),
|
||||
TrueBB, FalseBB)))
|
||||
return nullptr;
|
||||
if (Pred != ICmpInst::ICMP_EQ && Pred != ICmpInst::ICMP_NE)
|
||||
return nullptr;
|
||||
|
@ -2366,7 +2380,17 @@ tryToMoveFreeBeforeNullTest(CallInst &FI) {
|
|||
assert(FreeInstrBB == (Pred == ICmpInst::ICMP_EQ ? FalseBB : TrueBB) &&
|
||||
"Broken CFG: missing edge from predecessor to successor");
|
||||
|
||||
FI.moveBefore(TI);
|
||||
// At this point, we know that everything in FreeInstrBB can be moved
|
||||
// before TI.
|
||||
for (BasicBlock::iterator It = FreeInstrBB->begin(), End = FreeInstrBB->end();
|
||||
It != End;) {
|
||||
Instruction &Instr = *It++;
|
||||
if (&Instr == FreeInstrBBTerminator)
|
||||
break;
|
||||
Instr.moveBefore(TI);
|
||||
}
|
||||
assert(FreeInstrBB->size() == 1 &&
|
||||
"Only the branch instruction should remain");
|
||||
return &FI;
|
||||
}
|
||||
|
||||
|
@ -2393,7 +2417,7 @@ Instruction *InstCombiner::visitFree(CallInst &FI) {
|
|||
// into
|
||||
// free(foo);
|
||||
if (MinimizeSize)
|
||||
if (Instruction *I = tryToMoveFreeBeforeNullTest(FI))
|
||||
if (Instruction *I = tryToMoveFreeBeforeNullTest(FI, DL))
|
||||
return I;
|
||||
|
||||
return nullptr;
|
||||
|
|
|
@ -257,3 +257,32 @@ define void @test11() {
|
|||
call void @_ZdlPv(i8* %call)
|
||||
ret void
|
||||
}
|
||||
|
||||
;; Check that the optimization that moves a call to free in its predecessor
|
||||
;; block (see test6) also happens when noop casts are involved.
|
||||
; CHECK-LABEL: @test12(
|
||||
define void @test12(i32* %foo) minsize {
|
||||
; CHECK: %tobool = icmp eq i32* %foo, null
|
||||
;; Everything before the call to free should have been moved as well.
|
||||
; CHECK-NEXT: %bitcast = bitcast i32* %foo to i8*
|
||||
;; Call to free moved
|
||||
; CHECK-NEXT: tail call void @free(i8* %bitcast)
|
||||
; CHECK-NEXT: br i1 %tobool, label %if.end, label %if.then
|
||||
; CHECK: if.then:
|
||||
;; Block is now empty and may be simplified by simplifycfg
|
||||
; CHECK-NEXT: br label %if.end
|
||||
; CHECK: if.end:
|
||||
; CHECK-NEXT: ret void
|
||||
entry:
|
||||
%tobool = icmp eq i32* %foo, null
|
||||
br i1 %tobool, label %if.end, label %if.then
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%bitcast = bitcast i32* %foo to i8*
|
||||
tail call void @free(i8* %bitcast)
|
||||
br label %if.end
|
||||
|
||||
if.end: ; preds = %entry, %if.then
|
||||
ret void
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue