@@ -150,17 +150,47 @@ llvm::InlineAsm *IRGenModule::getObjCRetainAutoreleasedReturnValueMarker() {
150
150
// / Reclaim an autoreleased return value.
151
151
llvm::Value *irgen::emitObjCRetainAutoreleasedReturnValue (IRGenFunction &IGF,
152
152
llvm::Value *value) {
153
+ auto &IGM = IGF.IGM ;
153
154
// Call the inline-assembly marker if we need one.
154
- if (auto marker = IGF. IGM .getObjCRetainAutoreleasedReturnValueMarker ()) {
155
+ if (auto marker = IGM.getObjCRetainAutoreleasedReturnValueMarker ()) {
155
156
IGF.Builder .CreateAsmCall (marker, {});
156
157
}
157
158
159
+ const auto &triple = IGF.IGM .Context .LangOpts .Target ;
160
+ const auto &arch = triple.getArch ();
161
+
162
+ // FIXME: Do this on all targets and at -O0 too. This can be enabled only if
163
+ // the target backend knows how to handle the operand bundle.
164
+ // Don't use clang.arc.attachedcall on non-darwin platforms for now. On these
165
+ // platforms we have a workaround in-place to deal with the un-availability of
166
+ // a arc runtime -- we have implemented objc_retainAutoreleasedReturnValue in
167
+ // a library (src/swift/DispatchStubs.cc) as swift_retain.
168
+ // Using clang.arc.attachedcall enables a LLVM optimization that can transform
169
+ // objc_retainAutoreleasedReturnValue into objc_retain in some circumstances.
170
+ // There is no objc_retain stub defined and we would run into missing symbol
171
+ // errors.
172
+ if (IGM.getOptions ().shouldOptimize () && triple.isOSDarwin () &&
173
+ (arch == llvm::Triple::aarch64 ||
174
+ arch == llvm::Triple::x86_64)) {
175
+ auto EP = llvm::Intrinsic::getDeclaration (&IGM.Module ,
176
+ (llvm::Intrinsic::ID)llvm::Intrinsic::objc_retainAutoreleasedReturnValue);
177
+ llvm::Value *bundleArgs[] = {EP};
178
+ llvm::OperandBundleDef OB (" clang.arc.attachedcall" , bundleArgs);
179
+ auto *oldCall = cast<llvm::CallBase>(value);
180
+ llvm::CallBase *newCall = llvm::CallBase::addOperandBundle (
181
+ oldCall, llvm::LLVMContext::OB_clang_arc_attachedcall, OB, oldCall);
182
+ newCall->copyMetadata (*oldCall);
183
+ oldCall->replaceAllUsesWith (newCall);
184
+ oldCall->eraseFromParent ();
185
+ auto noop = IGF.Builder .CreateIntrinsicCall (llvm::Intrinsic::objc_clang_arc_noop_use, newCall);
186
+ noop->addFnAttr (llvm::Attribute::NoUnwind);
187
+ return newCall;
188
+ }
158
189
CastToInt8PtrTy savedType (IGF, value);
159
190
160
191
auto call = IGF.Builder .CreateIntrinsicCall (
161
192
llvm::Intrinsic::objc_retainAutoreleasedReturnValue, value);
162
193
163
- const llvm::Triple &triple = IGF.IGM .Context .LangOpts .Target ;
164
194
if (triple.getArch () == llvm::Triple::x86_64) {
165
195
// Don't tail call objc_retainAutoreleasedReturnValue. This blocks the
166
196
// autoreleased return optimization.
0 commit comments