forked from OSchip/llvm-project
144 lines
4.9 KiB
C++
144 lines
4.9 KiB
C++
//===-- ObjCARC.cpp -------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements common infrastructure for libLLVMObjCARCOpts.a, which
|
|
// implements several scalar transformations over the LLVM intermediate
|
|
// representation, including the C bindings for that library.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ObjCARC.h"
|
|
#include "llvm-c/Initialization.h"
|
|
#include "llvm/Analysis/ObjCARCUtil.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/InlineAsm.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/InitializePasses.h"
|
|
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
|
|
|
namespace llvm {
|
|
class PassRegistry;
|
|
}
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::objcarc;
|
|
|
|
/// initializeObjCARCOptsPasses - Initialize all passes linked into the
|
|
/// ObjCARCOpts library.
|
|
void llvm::initializeObjCARCOpts(PassRegistry &Registry) {
|
|
initializeObjCARCAAWrapperPassPass(Registry);
|
|
initializeObjCARCAPElimPass(Registry);
|
|
initializeObjCARCExpandPass(Registry);
|
|
initializeObjCARCContractLegacyPassPass(Registry);
|
|
initializeObjCARCOptLegacyPassPass(Registry);
|
|
initializePAEvalPass(Registry);
|
|
}
|
|
|
|
void LLVMInitializeObjCARCOpts(LLVMPassRegistryRef R) {
|
|
initializeObjCARCOpts(*unwrap(R));
|
|
}
|
|
|
|
CallInst *objcarc::createCallInstWithColors(
|
|
FunctionCallee Func, ArrayRef<Value *> Args, const Twine &NameStr,
|
|
Instruction *InsertBefore,
|
|
const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
|
|
FunctionType *FTy = Func.getFunctionType();
|
|
Value *Callee = Func.getCallee();
|
|
SmallVector<OperandBundleDef, 1> OpBundles;
|
|
|
|
if (!BlockColors.empty()) {
|
|
const ColorVector &CV = BlockColors.find(InsertBefore->getParent())->second;
|
|
assert(CV.size() == 1 && "non-unique color for block!");
|
|
Instruction *EHPad = CV.front()->getFirstNonPHI();
|
|
if (EHPad->isEHPad())
|
|
OpBundles.emplace_back("funclet", EHPad);
|
|
}
|
|
|
|
return CallInst::Create(FTy, Callee, Args, OpBundles, NameStr, InsertBefore);
|
|
}
|
|
|
|
std::pair<bool, bool>
|
|
BundledRetainClaimRVs::insertAfterInvokes(Function &F, DominatorTree *DT) {
|
|
bool Changed = false, CFGChanged = false;
|
|
|
|
for (BasicBlock &BB : F) {
|
|
auto *I = dyn_cast<InvokeInst>(BB.getTerminator());
|
|
|
|
if (!I)
|
|
continue;
|
|
|
|
if (!objcarc::hasAttachedCallOpBundle(I))
|
|
continue;
|
|
|
|
BasicBlock *DestBB = I->getNormalDest();
|
|
|
|
if (!DestBB->getSinglePredecessor()) {
|
|
assert(I->getSuccessor(0) == DestBB &&
|
|
"the normal dest is expected to be the first successor");
|
|
DestBB = SplitCriticalEdge(I, 0, CriticalEdgeSplittingOptions(DT));
|
|
CFGChanged = true;
|
|
}
|
|
|
|
// We don't have to call insertRVCallWithColors since DestBB is the normal
|
|
// destination of the invoke.
|
|
insertRVCall(&*DestBB->getFirstInsertionPt(), I);
|
|
Changed = true;
|
|
}
|
|
|
|
return std::make_pair(Changed, CFGChanged);
|
|
}
|
|
|
|
CallInst *BundledRetainClaimRVs::insertRVCall(Instruction *InsertPt,
|
|
CallBase *AnnotatedCall) {
|
|
DenseMap<BasicBlock *, ColorVector> BlockColors;
|
|
return insertRVCallWithColors(InsertPt, AnnotatedCall, BlockColors);
|
|
}
|
|
|
|
CallInst *BundledRetainClaimRVs::insertRVCallWithColors(
|
|
Instruction *InsertPt, CallBase *AnnotatedCall,
|
|
const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
|
|
IRBuilder<> Builder(InsertPt);
|
|
Function *Func = *objcarc::getAttachedARCFunction(AnnotatedCall);
|
|
assert(Func && "operand isn't a Function");
|
|
Type *ParamTy = Func->getArg(0)->getType();
|
|
Value *CallArg = Builder.CreateBitCast(AnnotatedCall, ParamTy);
|
|
auto *Call =
|
|
createCallInstWithColors(Func, CallArg, "", InsertPt, BlockColors);
|
|
RVCalls[Call] = AnnotatedCall;
|
|
return Call;
|
|
}
|
|
|
|
BundledRetainClaimRVs::~BundledRetainClaimRVs() {
|
|
for (auto P : RVCalls) {
|
|
if (ContractPass) {
|
|
CallBase *CB = P.second;
|
|
// At this point, we know that the annotated calls can't be tail calls
|
|
// as they are followed by marker instructions and retainRV/claimRV
|
|
// calls. Mark them as notail so that the backend knows these calls
|
|
// can't be tail calls.
|
|
if (auto *CI = dyn_cast<CallInst>(CB))
|
|
CI->setTailCallKind(CallInst::TCK_NoTail);
|
|
|
|
if (UseMarker) {
|
|
// Remove the retainRV/claimRV function operand from the operand bundle
|
|
// to reflect the fact that the backend is responsible for emitting only
|
|
// the marker instruction, but not the retainRV/claimRV call.
|
|
OperandBundleDef OB("clang.arc.attachedcall", None);
|
|
auto *NewCB = CallBase::Create(CB, OB, CB);
|
|
CB->replaceAllUsesWith(NewCB);
|
|
CB->eraseFromParent();
|
|
}
|
|
}
|
|
|
|
if (!ContractPass || !UseMarker)
|
|
EraseInstruction(P.first);
|
|
}
|
|
|
|
RVCalls.clear();
|
|
}
|