integer 0/1 for the operand of bundle "clang.arc.attachedcall" https://reviews.llvm.org/D102996 changes the operand of bundle "clang.arc.attachedcall". This patch makes changes to llvm that are needed to handle the new IR. This should make it easier to understand what the IR is doing and also simplify some of the passes as they no longer have to translate the integer values to the runtime functions. Differential Revision: https://reviews.llvm.org/D103000
140 lines
4.7 KiB
C++
140 lines
4.7 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() {
|
|
if (ContractPass) {
|
|
for (auto P : RVCalls) {
|
|
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);
|
|
|
|
// Remove the ARC intrinsic function operand from the operand bundle.
|
|
OperandBundleDef OB("clang.arc.attachedcall", None);
|
|
auto *NewCB = CallBase::Create(CB, OB, CB);
|
|
CB->replaceAllUsesWith(NewCB);
|
|
CB->eraseFromParent();
|
|
}
|
|
} else {
|
|
for (auto P : RVCalls)
|
|
EraseInstruction(P.first);
|
|
}
|
|
|
|
RVCalls.clear();
|
|
}
|