1//===-- ObjCARC.cpp -------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements common infrastructure for libLLVMObjCARCOpts.a, which
10// implements several scalar transformations over the LLVM intermediate
11// representation, including the C bindings for that library.
12//
13//===----------------------------------------------------------------------===//
14
15#include "ObjCARC.h"
16#include "llvm/Analysis/ObjCARCUtil.h"
17#include "llvm/IR/IRBuilder.h"
18#include "llvm/IR/Instructions.h"
19#include "llvm/Transforms/Utils/BasicBlockUtils.h"
20
21using namespace llvm;
22using namespace llvm::objcarc;
23
24CallInst *objcarc::createCallInstWithColors(
25 FunctionCallee Func, ArrayRef<Value *> Args, const Twine &NameStr,
26 BasicBlock::iterator InsertBefore,
27 const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
28 FunctionType *FTy = Func.getFunctionType();
29 Value *Callee = Func.getCallee();
30 SmallVector<OperandBundleDef, 1> OpBundles;
31
32 if (!BlockColors.empty()) {
33 const ColorVector &CV = BlockColors.find(Val: InsertBefore->getParent())->second;
34 assert(CV.size() == 1 && "non-unique color for block!");
35 BasicBlock::iterator EHPad = CV.front()->getFirstNonPHIIt();
36 if (EHPad->isEHPad())
37 OpBundles.emplace_back(Args: "funclet", Args: &*EHPad);
38 }
39
40 return CallInst::Create(Ty: FTy, Func: Callee, Args, Bundles: OpBundles, NameStr, InsertBefore);
41}
42
43std::pair<bool, bool>
44BundledRetainClaimRVs::insertAfterInvokes(Function &F, DominatorTree *DT) {
45 bool Changed = false, CFGChanged = false;
46
47 for (BasicBlock &BB : F) {
48 auto *I = dyn_cast<InvokeInst>(Val: BB.getTerminator());
49
50 if (!I)
51 continue;
52
53 if (!objcarc::hasAttachedCallOpBundle(CB: I))
54 continue;
55
56 BasicBlock *DestBB = I->getNormalDest();
57
58 if (!DestBB->getSinglePredecessor()) {
59 assert(I->getSuccessor(0) == DestBB &&
60 "the normal dest is expected to be the first successor");
61 DestBB = SplitCriticalEdge(TI: I, SuccNum: 0, Options: CriticalEdgeSplittingOptions(DT));
62 CFGChanged = true;
63 }
64
65 // We don't have to call insertRVCallWithColors since DestBB is the normal
66 // destination of the invoke.
67 insertRVCall(InsertPt: DestBB->getFirstInsertionPt(), AnnotatedCall: I);
68 Changed = true;
69 }
70
71 return std::make_pair(x&: Changed, y&: CFGChanged);
72}
73
74CallInst *BundledRetainClaimRVs::insertRVCall(BasicBlock::iterator InsertPt,
75 CallBase *AnnotatedCall) {
76 DenseMap<BasicBlock *, ColorVector> BlockColors;
77 return insertRVCallWithColors(InsertPt, AnnotatedCall, BlockColors);
78}
79
80CallInst *BundledRetainClaimRVs::insertRVCallWithColors(
81 BasicBlock::iterator InsertPt, CallBase *AnnotatedCall,
82 const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
83 IRBuilder<> Builder(InsertPt->getParent(), InsertPt);
84 Function *Func = *objcarc::getAttachedARCFunction(CB: AnnotatedCall);
85 assert(Func && "operand isn't a Function");
86 Type *ParamTy = Func->getArg(i: 0)->getType();
87 Value *CallArg = Builder.CreateBitCast(V: AnnotatedCall, DestTy: ParamTy);
88 auto *Call =
89 createCallInstWithColors(Func, Args: CallArg, NameStr: "", InsertBefore: InsertPt, BlockColors);
90 RVCalls[Call] = AnnotatedCall;
91 return Call;
92}
93
94BundledRetainClaimRVs::~BundledRetainClaimRVs() {
95 for (auto P : RVCalls) {
96 if (ContractPass) {
97 CallBase *CB = P.second;
98 // At this point, we know that the annotated calls can't be tail calls
99 // as they are followed by marker instructions and retainRV/claimRV
100 // calls. Mark them as notail so that the backend knows these calls
101 // can't be tail calls.
102 if (auto *CI = dyn_cast<CallInst>(Val: CB))
103 CI->setTailCallKind(CallInst::TCK_NoTail);
104
105 // We can also do one final optimization: modify the bundle in the
106 // annotated call, to change the bundle operand from
107 // objc_retainAutoreleasedReturnValue
108 // to:
109 // objc_claimAutoreleasedReturnValue
110 // allowing the marker to be omitted from the bundle expansion later.
111 //
112 // Note that, confusingly, ClaimRV is semantically equivalent to RetainRV,
113 // and only differs in that it doesn't require the marker.
114 // The bundle provides the guarantee that we're emitting the ClaimRV call
115 // adjacent to the original call, and providing that guarantee is the
116 // only difference between ClaimRV and RetainRV.
117 //
118 // UnsafeClaimRV has a different RC contract entirely.
119
120 // Find the clang.arc.attachedcall bundle, and rewrite its operand.
121 if (UseClaimRV) {
122 for (auto OBI : CB->bundle_op_infos()) {
123 auto OBU = CB->operandBundleFromBundleOpInfo(BOI: OBI);
124 if (OBU.getTagID() == LLVMContext::OB_clang_arc_attachedcall &&
125 OBU.Inputs[0] == EP.get(kind: ARCRuntimeEntryPointKind::RetainRV)) {
126 CB->setOperand(i_nocapture: OBI.Begin,
127 Val_nocapture: EP.get(kind: ARCRuntimeEntryPointKind::ClaimRV));
128 break;
129 }
130 }
131 }
132 }
133
134 // Erase the RV call we emitted earlier: it's already in the bundle.
135 EraseInstruction(CI: P.first);
136 }
137
138 RVCalls.clear();
139}
140