1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

[ObjC][ARC] Check the basic block size before calling

DominatorTree::dominate.

ARC contract pass has an optimization that replaces the uses of the
argument of an ObjC runtime function call with the call result.

For example:

; Before optimization
%1 = tail call i8* @foo1()
%2 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %1)
store i8* %1, i8** @g0, align 8

; After optimization
%1 = tail call i8* @foo1()
%2 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %1)
store i8* %2, i8** @g0, align 8 // %1 is replaced with %2

Before replacing the argument use, DominatorTree::dominate is called to
determine whether the user instruction is dominated by the ObjC runtime
function call instruction. The call to DominatorTree::dominate can be
expensive if the two instructions belong to the same basic block and the
size of the basic block is large. This patch checks the basic block size
and just bails out if the size exceeds the limit set by command line
option "arc-contract-max-bb-size".

rdar://problem/49477063

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

llvm-svn: 359027
This commit is contained in:
Akira Hatanaka 2019-04-23 19:49:03 +00:00
parent b70a597b41
commit cc2b8d0084
2 changed files with 51 additions and 1 deletions

View File

@ -45,6 +45,10 @@ using namespace llvm::objcarc;
STATISTIC(NumPeeps, "Number of calls peephole-optimized");
STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed");
static cl::opt<unsigned> MaxBBSize("arc-contract-max-bb-size", cl::Hidden,
cl::desc("Maximum basic block size to discover the dominance relation of "
"two instructions in the same basic block"), cl::init(65535));
//===----------------------------------------------------------------------===//
// Declarations
//===----------------------------------------------------------------------===//
@ -573,6 +577,24 @@ bool ObjCARCContract::runOnFunction(Function &F) {
// reduces register pressure.
SmallPtrSet<Instruction *, 4> DependingInstructions;
SmallPtrSet<const BasicBlock *, 4> Visited;
// Cache the basic block size.
DenseMap<const BasicBlock *, unsigned> BBSizeMap;
// A lambda that lazily computes the size of a basic block and determines
// whether the size exceeds MaxBBSize.
auto IsLargeBB = [&](const BasicBlock *BB) {
unsigned BBSize;
auto I = BBSizeMap.find(BB);
if (I != BBSizeMap.end())
BBSize = I->second;
else
BBSize = BBSizeMap[BB] = BB->size();
return BBSize > MaxBBSize;
};
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E;) {
Instruction *Inst = &*I++;
@ -590,7 +612,7 @@ bool ObjCARCContract::runOnFunction(Function &F) {
// and such; to do the replacement, the argument must have type i8*.
// Function for replacing uses of Arg dominated by Inst.
auto ReplaceArgUses = [Inst, this](Value *Arg) {
auto ReplaceArgUses = [Inst, IsLargeBB, this](Value *Arg) {
// If we're compiling bugpointed code, don't get in trouble.
if (!isa<Instruction>(Arg) && !isa<Argument>(Arg))
return;
@ -602,6 +624,17 @@ bool ObjCARCContract::runOnFunction(Function &F) {
Use &U = *UI++;
unsigned OperandNo = U.getOperandNo();
// Don't replace the uses if Inst and the user belong to the same basic
// block and the size of the basic block is large. We don't want to call
// DominatorTree::dominate in that case. We can remove this check if we
// can use OrderedBasicBlock to compute the dominance relation between
// two instructions, but that's not currently possible since it doesn't
// recompute the instruction ordering when new instructions are inserted
// to the basic block.
if (Inst->getParent() == cast<Instruction>(U.getUser())->getParent() &&
IsLargeBB(Inst->getParent()))
continue;
// If the call's return value dominates a use of the call's argument
// value, rewrite the use to use the return value. We check for
// reachability here because an unreachable call is considered to

View File

@ -0,0 +1,17 @@
; RUN: opt -objc-arc-contract -S < %s | FileCheck -check-prefix=ENABLE %s
; RUN: opt -objc-arc-contract -arc-contract-max-bb-size=3 -S < %s | FileCheck -check-prefix=DISABLE %s
@g0 = common global i8* null, align 8
; ENABLE: store i8* %2, i8** @g0
; DISABLE: store i8* %1, i8** @g0
define void @foo0() {
%1 = tail call i8* @foo1()
%2 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %1)
store i8* %1, i8** @g0, align 8
ret void
}
declare i8* @foo1()
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)