[g-arc-opts] Teach the arc optimizer how to recognize more trap BBs in the stdlib.

This reduces the number of retain, release operations in the dylib from 38512 to
16041. That is a reduction of 60%. Most of the code paths affected by this were
in the cocoa part of the stdlib so when I measured the perf test suite I did not
see a huge boost in perf.

rdar://18327670

Swift SVN r21934
This commit is contained in:
Michael Gottesman
2014-09-13 01:42:24 +00:00
parent 8eb7bf2c31
commit 1bfdd9e3bf
2 changed files with 70 additions and 18 deletions

View File

@@ -19,6 +19,7 @@
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILSuccessor.h"
#include "swift/SIL/CFG.h"
#include "swift/SIL/SILModule.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringSwitch.h"
@@ -792,27 +793,35 @@ bool swift::arc::ARCSequenceDataflowEvaluator::run() {
return NestingDetected;
}
/// Match a call to int_trap.
static bool matchTrappingUnreachableBB(SILBasicBlock *BB) {
auto II = BB->begin();
auto *BFRI = dyn_cast<BuiltinFunctionRefInst>(&*II);
if (!BFRI || !BFRI->getName().str().equals("int_trap"))
return false;
++II;
static bool ignoreableApplyInstInUnreachableBlock(ApplyInst *AI) {
if (auto *BFRI = dyn_cast<BuiltinFunctionRefInst>(AI->getCallee())) {
const BuiltinInfo &BInfo = BFRI->getBuiltinInfo();
if (BInfo.ID == BuiltinValueKind::CondUnreachable)
return true;
auto *AI = dyn_cast<ApplyInst>(&*II);
if (!AI || AI->getCallee() != SILValue(BFRI))
const IntrinsicInfo &IInfo = BFRI->getIntrinsicInfo();
if (IInfo.ID == llvm::Intrinsic::trap)
return true;
}
const char *fatalName =
"_TFSs18_fatalErrorMessageFTVSs12StaticStringS_S_Su_T_";
auto *FRI = dyn_cast<FunctionRefInst>(AI->getCallee());
if (!FRI || !FRI->getReferencedFunction()->getName().equals(fatalName))
return false;
++II;
return true;
}
/// Match a call to a BB with no ARC relevant side effects.
static bool matchNoSideEffectUnreachableBB(SILBasicBlock *BB) {
auto II = BB->begin();
while (true) {
// Ignore any literal insts.
if (isa<LiteralInst>(II)) {
auto II = BB->begin(), IE = BB->end();
while (II != IE) {
if (isa<UnreachableInst>(&*II))
return true;
// Ignore any instructions without side effects.
if (!II->mayHaveSideEffects()) {
++II;
continue;
}
@@ -823,11 +832,20 @@ static bool matchNoSideEffectUnreachableBB(SILBasicBlock *BB) {
continue;
}
return isa<UnreachableInst>(&*II);
// Check for apply insts that we can ignore.
if (auto *AI = dyn_cast<ApplyInst>(&*II)) {
if (ignoreableApplyInstInUnreachableBlock(AI)) {
++II;
continue;
}
}
void swift::arc::ARCBBState::initializeTrapStatus() {
IsTrapBB = matchTrappingUnreachableBB(BB) ||
matchNoSideEffectUnreachableBB(BB);
return false;
}
return false;
}
void swift::arc::ARCBBState::initializeTrapStatus() {
IsTrapBB = matchNoSideEffectUnreachableBB(BB);
}

View File

@@ -1460,3 +1460,37 @@ bb0(%0 : $Builtin.NativeObject):
%2 = tuple()
return %2 : $()
}
sil @_TFSs18_fatalErrorMessageFTVSs12StaticStringS_S_Su_T_ : $@thin @noreturn (StaticString, StaticString, StaticString) -> () // user: %43
// CHECK-LABEL: sil @ignore_fatalErrorMsgBB : $@thin (Builtin.NativeObject) -> () {
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @ignore_fatalErrorMsgBB : $@thin (Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $Builtin.NativeObject
cond_br undef, bb4, bb5
bb2:
strong_retain %0 : $Builtin.NativeObject
cond_br undef, bb3, bb4
bb3:
br bb4
bb4:
strong_release %0 : $Builtin.NativeObject
%1 = tuple()
return %1 : $()
bb5:
%39 = function_ref @_TFSs18_fatalErrorMessageFTVSs12StaticStringS_S_Su_T_ : $@thin @noreturn (StaticString, StaticString, StaticString) -> () // user: %43
%40 = string_literal utf8 "fatal error" // user: %42
%41 = integer_literal $Builtin.Word, 11 // user: %42
%42 = struct $StaticString (%40 : $Builtin.RawPointer, %41 : $Builtin.Word, %41 : $Builtin.Word) // user: %43
%43 = apply %39(%42, %42, %42) : $@thin @noreturn (StaticString, StaticString, StaticString) -> ()
unreachable // id: %44
}