1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[ObjC][ARC] Delete ARC runtime calls that take inert phi values

This improves on the following patch, which removed ARC runtime calls
taking inert global variables:

https://reviews.llvm.org/D62433

rdar://problem/59137105
This commit is contained in:
Akira Hatanaka 2020-02-07 16:24:18 -08:00
parent f21a88cbf6
commit 5bf34bef20
2 changed files with 65 additions and 12 deletions

View File

@ -877,23 +877,43 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
optimizeDelayedAutoreleaseRV();
}
/// This function returns true if the value is inert. An ObjC ARC runtime call
/// taking an inert operand can be safely deleted.
static bool isInertARCValue(Value *V) {
V = V->stripPointerCasts();
if (IsNullOrUndef(V))
return true;
// See if this is a global attribute annotated with an 'objc_arc_inert'.
if (auto *GV = dyn_cast<GlobalVariable>(V))
if (GV->hasAttribute("objc_arc_inert"))
return true;
if (auto PN = dyn_cast<PHINode>(V)) {
// Look through phis's operands.
for (Value *Opnd : PN->incoming_values())
if (!isInertARCValue(Opnd))
return false;
return true;
}
return false;
}
void ObjCARCOpt::OptimizeIndividualCallImpl(
Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
Instruction *Inst, ARCInstKind Class, const Value *Arg) {
LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n");
// Some of the ARC calls can be deleted if their arguments are global
// variables that are inert in ARC.
if (IsNoopOnGlobal(Class)) {
Value *Opnd = Inst->getOperand(0);
if (auto *GV = dyn_cast<GlobalVariable>(Opnd->stripPointerCasts()))
if (GV->hasAttribute("objc_arc_inert")) {
if (!Inst->getType()->isVoidTy())
Inst->replaceAllUsesWith(Opnd);
Inst->eraseFromParent();
return;
}
}
// We can delete this call if it takes an inert value.
if (IsNoopOnGlobal(Class))
if (isInertARCValue(Inst->getOperand(0))) {
if (!Inst->getType()->isVoidTy())
Inst->replaceAllUsesWith(Inst->getOperand(0));
Inst->eraseFromParent();
return;
}
switch (Class) {
default:

View File

@ -54,6 +54,39 @@ define internal void @__globalBlock_block_invoke(i8* nocapture readnone) {
ret void
}
; CHECK: define %[[V0:.*]]* @test_conditional0(
; CHECK: %[[PHI0:.*]] = phi %[[V0]]* [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %[[V0]]*), %{{.*}} ], [ null, %{{.*}} ]
; CHECK: %[[PHI1:.*]] = phi %[[V0]]* [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %[[V0]]*), %{{.*}} ], [ %[[PHI0]], %{{.*}} ]
; CHECK-NEXT: %[[PHI2:.*]] = phi %[[V0]]* [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %[[V0]]*), %{{.*}} ], [ %{{.*}}, %{{.*}} ]
; CHECK-NEXT: %[[V2:.*]] = bitcast %[[V0]]* %[[PHI1]] to i8*
; CHECK-NEXT: %[[V4:.*]] = bitcast %[[V0]]* %[[PHI2]] to i8*
; CHECK-NEXT: %[[V5:.*]] = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %[[V4]])
; CHECK-NEXT: ret %[[V0]]* %[[PHI2]]
define %0* @test_conditional0(i32 %i, %0* %b) {
entry:
%v0 = icmp eq i32 %i, 1
br i1 %v0, label %bb2, label %bb1
bb1:
%v1 = icmp eq i32 %i, 2
br i1 %v1, label %bb2, label %return
bb2:
%phi0 = phi %0* [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %0*), %entry ], [ null, %bb1 ]
br label %return
return:
%phi1 = phi %0* [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %0*), %bb1 ], [ %phi0, %bb2 ]
%phi2 = phi %0* [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to %0*), %bb1 ], [ %b, %bb2 ]
%v2 = bitcast %0* %phi1 to i8*
%v3 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %v2)
%v4 = bitcast %0* %phi2 to i8*
%v5 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %v4)
ret %0* %phi2
}
declare void @foo()
declare i8* @llvm.objc.retain(i8*) local_unnamed_addr