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();
 | 
						|
}
 |