xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- PreISelIntrinsicLowering.cpp - Pre-ISel intrinsic lowering pass ----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
906c3fb27SDimitry Andric // This pass implements IR lowering for the llvm.memcpy, llvm.memmove,
1006c3fb27SDimitry Andric // llvm.memset, llvm.load.relative and llvm.objc.* intrinsics.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/CodeGen/PreISelIntrinsicLowering.h"
15480093f4SDimitry Andric #include "llvm/Analysis/ObjCARCInstKind.h"
16349cc55cSDimitry Andric #include "llvm/Analysis/ObjCARCUtil.h"
1706c3fb27SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
198a4dda33SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
208a4dda33SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
210b57cec5SDimitry Andric #include "llvm/IR/Function.h"
220b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
230b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
24972a253aSDimitry Andric #include "llvm/IR/IntrinsicInst.h"
250b57cec5SDimitry Andric #include "llvm/IR/Module.h"
260b57cec5SDimitry Andric #include "llvm/IR/Type.h"
27480093f4SDimitry Andric #include "llvm/InitializePasses.h"
280b57cec5SDimitry Andric #include "llvm/Pass.h"
290b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
308a4dda33SDimitry Andric #include "llvm/Target/TargetMachine.h"
3106c3fb27SDimitry Andric #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric using namespace llvm;
340b57cec5SDimitry Andric 
3506c3fb27SDimitry Andric /// Threshold to leave statically sized memory intrinsic calls. Calls of known
3606c3fb27SDimitry Andric /// size larger than this will be expanded by the pass. Calls of unknown or
3706c3fb27SDimitry Andric /// lower size will be left for expansion in codegen.
3806c3fb27SDimitry Andric static cl::opt<int64_t> MemIntrinsicExpandSizeThresholdOpt(
3906c3fb27SDimitry Andric     "mem-intrinsic-expand-size",
4006c3fb27SDimitry Andric     cl::desc("Set minimum mem intrinsic size to expand in IR"), cl::init(-1),
4106c3fb27SDimitry Andric     cl::Hidden);
4206c3fb27SDimitry Andric 
4306c3fb27SDimitry Andric namespace {
4406c3fb27SDimitry Andric 
4506c3fb27SDimitry Andric struct PreISelIntrinsicLowering {
468a4dda33SDimitry Andric   const TargetMachine &TM;
4706c3fb27SDimitry Andric   const function_ref<TargetTransformInfo &(Function &)> LookupTTI;
4806c3fb27SDimitry Andric 
4906c3fb27SDimitry Andric   /// If this is true, assume it's preferably to leave memory intrinsic calls
5006c3fb27SDimitry Andric   /// for replacement with a library call later. Otherwise this depends on
518a4dda33SDimitry Andric   /// TargetLoweringInfo availability of the corresponding function.
5206c3fb27SDimitry Andric   const bool UseMemIntrinsicLibFunc;
5306c3fb27SDimitry Andric 
5406c3fb27SDimitry Andric   explicit PreISelIntrinsicLowering(
558a4dda33SDimitry Andric       const TargetMachine &TM_,
5606c3fb27SDimitry Andric       function_ref<TargetTransformInfo &(Function &)> LookupTTI_,
5706c3fb27SDimitry Andric       bool UseMemIntrinsicLibFunc_ = true)
588a4dda33SDimitry Andric       : TM(TM_), LookupTTI(LookupTTI_),
5906c3fb27SDimitry Andric         UseMemIntrinsicLibFunc(UseMemIntrinsicLibFunc_) {}
6006c3fb27SDimitry Andric 
6106c3fb27SDimitry Andric   static bool shouldExpandMemIntrinsicWithSize(Value *Size,
6206c3fb27SDimitry Andric                                                const TargetTransformInfo &TTI);
6306c3fb27SDimitry Andric   bool expandMemIntrinsicUses(Function &F) const;
6406c3fb27SDimitry Andric   bool lowerIntrinsics(Module &M) const;
6506c3fb27SDimitry Andric };
6606c3fb27SDimitry Andric 
6706c3fb27SDimitry Andric } // namespace
6806c3fb27SDimitry Andric 
690b57cec5SDimitry Andric static bool lowerLoadRelative(Function &F) {
700b57cec5SDimitry Andric   if (F.use_empty())
710b57cec5SDimitry Andric     return false;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   bool Changed = false;
740b57cec5SDimitry Andric   Type *Int32Ty = Type::getInt32Ty(F.getContext());
750b57cec5SDimitry Andric 
76349cc55cSDimitry Andric   for (Use &U : llvm::make_early_inc_range(F.uses())) {
77349cc55cSDimitry Andric     auto CI = dyn_cast<CallInst>(U.getUser());
785ffd83dbSDimitry Andric     if (!CI || CI->getCalledOperand() != &F)
790b57cec5SDimitry Andric       continue;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric     IRBuilder<> B(CI);
820b57cec5SDimitry Andric     Value *OffsetPtr =
837a6dacacSDimitry Andric         B.CreatePtrAdd(CI->getArgOperand(0), CI->getArgOperand(1));
845f757f3fSDimitry Andric     Value *OffsetI32 = B.CreateAlignedLoad(Int32Ty, OffsetPtr, Align(4));
850b57cec5SDimitry Andric 
867a6dacacSDimitry Andric     Value *ResultPtr = B.CreatePtrAdd(CI->getArgOperand(0), OffsetI32);
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric     CI->replaceAllUsesWith(ResultPtr);
890b57cec5SDimitry Andric     CI->eraseFromParent();
900b57cec5SDimitry Andric     Changed = true;
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   return Changed;
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
96480093f4SDimitry Andric // ObjCARC has knowledge about whether an obj-c runtime function needs to be
97480093f4SDimitry Andric // always tail-called or never tail-called.
98480093f4SDimitry Andric static CallInst::TailCallKind getOverridingTailCallKind(const Function &F) {
99480093f4SDimitry Andric   objcarc::ARCInstKind Kind = objcarc::GetFunctionClass(&F);
100480093f4SDimitry Andric   if (objcarc::IsAlwaysTail(Kind))
101480093f4SDimitry Andric     return CallInst::TCK_Tail;
102480093f4SDimitry Andric   else if (objcarc::IsNeverTail(Kind))
103480093f4SDimitry Andric     return CallInst::TCK_NoTail;
104480093f4SDimitry Andric   return CallInst::TCK_None;
105480093f4SDimitry Andric }
106480093f4SDimitry Andric 
1070b57cec5SDimitry Andric static bool lowerObjCCall(Function &F, const char *NewFn,
1080b57cec5SDimitry Andric                           bool setNonLazyBind = false) {
109972a253aSDimitry Andric   assert(IntrinsicInst::mayLowerToFunctionCall(F.getIntrinsicID()) &&
110972a253aSDimitry Andric          "Pre-ISel intrinsics do lower into regular function calls");
1110b57cec5SDimitry Andric   if (F.use_empty())
1120b57cec5SDimitry Andric     return false;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   // If we haven't already looked up this function, check to see if the
1150b57cec5SDimitry Andric   // program already contains a function with this name.
1160b57cec5SDimitry Andric   Module *M = F.getParent();
1170b57cec5SDimitry Andric   FunctionCallee FCache = M->getOrInsertFunction(NewFn, F.getFunctionType());
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   if (Function *Fn = dyn_cast<Function>(FCache.getCallee())) {
1200b57cec5SDimitry Andric     Fn->setLinkage(F.getLinkage());
1210b57cec5SDimitry Andric     if (setNonLazyBind && !Fn->isWeakForLinker()) {
1220b57cec5SDimitry Andric       // If we have Native ARC, set nonlazybind attribute for these APIs for
1230b57cec5SDimitry Andric       // performance.
1240b57cec5SDimitry Andric       Fn->addFnAttr(Attribute::NonLazyBind);
1250b57cec5SDimitry Andric     }
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric 
128480093f4SDimitry Andric   CallInst::TailCallKind OverridingTCK = getOverridingTailCallKind(F);
129480093f4SDimitry Andric 
130349cc55cSDimitry Andric   for (Use &U : llvm::make_early_inc_range(F.uses())) {
131349cc55cSDimitry Andric     auto *CB = cast<CallBase>(U.getUser());
132349cc55cSDimitry Andric 
133349cc55cSDimitry Andric     if (CB->getCalledFunction() != &F) {
134349cc55cSDimitry Andric       objcarc::ARCInstKind Kind = objcarc::getAttachedARCFunctionKind(CB);
135349cc55cSDimitry Andric       (void)Kind;
136349cc55cSDimitry Andric       assert((Kind == objcarc::ARCInstKind::RetainRV ||
13704eeddc0SDimitry Andric               Kind == objcarc::ARCInstKind::UnsafeClaimRV) &&
138349cc55cSDimitry Andric              "use expected to be the argument of operand bundle "
139349cc55cSDimitry Andric              "\"clang.arc.attachedcall\"");
140349cc55cSDimitry Andric       U.set(FCache.getCallee());
141349cc55cSDimitry Andric       continue;
142349cc55cSDimitry Andric     }
143349cc55cSDimitry Andric 
144349cc55cSDimitry Andric     auto *CI = cast<CallInst>(CB);
1450b57cec5SDimitry Andric     assert(CI->getCalledFunction() && "Cannot lower an indirect call!");
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric     IRBuilder<> Builder(CI->getParent(), CI->getIterator());
148e8d8bef9SDimitry Andric     SmallVector<Value *, 8> Args(CI->args());
149972a253aSDimitry Andric     SmallVector<llvm::OperandBundleDef, 1> BundleList;
150972a253aSDimitry Andric     CI->getOperandBundlesAsDefs(BundleList);
151972a253aSDimitry Andric     CallInst *NewCI = Builder.CreateCall(FCache, Args, BundleList);
1520b57cec5SDimitry Andric     NewCI->setName(CI->getName());
153480093f4SDimitry Andric 
154480093f4SDimitry Andric     // Try to set the most appropriate TailCallKind based on both the current
155480093f4SDimitry Andric     // attributes and the ones that we could get from ObjCARC's special
156480093f4SDimitry Andric     // knowledge of the runtime functions.
157480093f4SDimitry Andric     //
158480093f4SDimitry Andric     // std::max respects both requirements of notail and tail here:
159480093f4SDimitry Andric     // * notail on either the call or from ObjCARC becomes notail
160480093f4SDimitry Andric     // * tail on either side is stronger than none, but not notail
161480093f4SDimitry Andric     CallInst::TailCallKind TCK = CI->getTailCallKind();
162480093f4SDimitry Andric     NewCI->setTailCallKind(std::max(TCK, OverridingTCK));
163480093f4SDimitry Andric 
1645f757f3fSDimitry Andric     // Transfer the 'returned' attribute from the intrinsic to the call site.
1655f757f3fSDimitry Andric     // By applying this only to intrinsic call sites, we avoid applying it to
1665f757f3fSDimitry Andric     // non-ARC explicit calls to things like objc_retain which have not been
1675f757f3fSDimitry Andric     // auto-upgraded to use the intrinsics.
1685f757f3fSDimitry Andric     unsigned Index;
1695f757f3fSDimitry Andric     if (F.getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) &&
1705f757f3fSDimitry Andric         Index)
1715f757f3fSDimitry Andric       NewCI->addParamAttr(Index - AttributeList::FirstArgIndex,
1725f757f3fSDimitry Andric                           Attribute::Returned);
1735f757f3fSDimitry Andric 
1740b57cec5SDimitry Andric     if (!CI->use_empty())
1750b57cec5SDimitry Andric       CI->replaceAllUsesWith(NewCI);
1760b57cec5SDimitry Andric     CI->eraseFromParent();
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric   return true;
1800b57cec5SDimitry Andric }
1810b57cec5SDimitry Andric 
18206c3fb27SDimitry Andric // TODO: Should refine based on estimated number of accesses (e.g. does it
18306c3fb27SDimitry Andric // require splitting based on alignment)
18406c3fb27SDimitry Andric bool PreISelIntrinsicLowering::shouldExpandMemIntrinsicWithSize(
18506c3fb27SDimitry Andric     Value *Size, const TargetTransformInfo &TTI) {
18606c3fb27SDimitry Andric   ConstantInt *CI = dyn_cast<ConstantInt>(Size);
18706c3fb27SDimitry Andric   if (!CI)
18806c3fb27SDimitry Andric     return true;
18906c3fb27SDimitry Andric   uint64_t Threshold = MemIntrinsicExpandSizeThresholdOpt.getNumOccurrences()
19006c3fb27SDimitry Andric                            ? MemIntrinsicExpandSizeThresholdOpt
19106c3fb27SDimitry Andric                            : TTI.getMaxMemIntrinsicInlineSizeThreshold();
19206c3fb27SDimitry Andric   uint64_t SizeVal = CI->getZExtValue();
19306c3fb27SDimitry Andric 
19406c3fb27SDimitry Andric   // Treat a threshold of 0 as a special case to force expansion of all
19506c3fb27SDimitry Andric   // intrinsics, including size 0.
19606c3fb27SDimitry Andric   return SizeVal > Threshold || Threshold == 0;
19706c3fb27SDimitry Andric }
19806c3fb27SDimitry Andric 
1998a4dda33SDimitry Andric static bool canEmitLibcall(const TargetMachine &TM, Function *F,
2008a4dda33SDimitry Andric                            RTLIB::Libcall LC) {
2018a4dda33SDimitry Andric   // TODO: Should this consider the address space of the memcpy?
2028a4dda33SDimitry Andric   const TargetLowering *TLI = TM.getSubtargetImpl(*F)->getTargetLowering();
2038a4dda33SDimitry Andric   return TLI->getLibcallName(LC) != nullptr;
2048a4dda33SDimitry Andric }
2058a4dda33SDimitry Andric 
20606c3fb27SDimitry Andric // TODO: Handle atomic memcpy and memcpy.inline
20706c3fb27SDimitry Andric // TODO: Pass ScalarEvolution
20806c3fb27SDimitry Andric bool PreISelIntrinsicLowering::expandMemIntrinsicUses(Function &F) const {
20906c3fb27SDimitry Andric   Intrinsic::ID ID = F.getIntrinsicID();
21006c3fb27SDimitry Andric   bool Changed = false;
21106c3fb27SDimitry Andric 
21206c3fb27SDimitry Andric   for (User *U : llvm::make_early_inc_range(F.users())) {
21306c3fb27SDimitry Andric     Instruction *Inst = cast<Instruction>(U);
21406c3fb27SDimitry Andric 
21506c3fb27SDimitry Andric     switch (ID) {
21606c3fb27SDimitry Andric     case Intrinsic::memcpy: {
21706c3fb27SDimitry Andric       auto *Memcpy = cast<MemCpyInst>(Inst);
21806c3fb27SDimitry Andric       Function *ParentFunc = Memcpy->getFunction();
21906c3fb27SDimitry Andric       const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
22006c3fb27SDimitry Andric       if (shouldExpandMemIntrinsicWithSize(Memcpy->getLength(), TTI)) {
22106c3fb27SDimitry Andric         if (UseMemIntrinsicLibFunc &&
2228a4dda33SDimitry Andric             canEmitLibcall(TM, ParentFunc, RTLIB::MEMCPY))
22306c3fb27SDimitry Andric           break;
22406c3fb27SDimitry Andric 
2258a4dda33SDimitry Andric         // TODO: For optsize, emit the loop into a separate function
22606c3fb27SDimitry Andric         expandMemCpyAsLoop(Memcpy, TTI);
22706c3fb27SDimitry Andric         Changed = true;
22806c3fb27SDimitry Andric         Memcpy->eraseFromParent();
22906c3fb27SDimitry Andric       }
23006c3fb27SDimitry Andric 
23106c3fb27SDimitry Andric       break;
23206c3fb27SDimitry Andric     }
233*0fca6ea1SDimitry Andric     case Intrinsic::memcpy_inline: {
234*0fca6ea1SDimitry Andric       // Only expand llvm.memcpy.inline with non-constant length in this
235*0fca6ea1SDimitry Andric       // codepath, leaving the current SelectionDAG expansion for constant
236*0fca6ea1SDimitry Andric       // length memcpy intrinsics undisturbed.
237*0fca6ea1SDimitry Andric       auto *Memcpy = cast<MemCpyInlineInst>(Inst);
238*0fca6ea1SDimitry Andric       if (isa<ConstantInt>(Memcpy->getLength()))
239*0fca6ea1SDimitry Andric         break;
240*0fca6ea1SDimitry Andric 
241*0fca6ea1SDimitry Andric       Function *ParentFunc = Memcpy->getFunction();
242*0fca6ea1SDimitry Andric       const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
243*0fca6ea1SDimitry Andric       expandMemCpyAsLoop(Memcpy, TTI);
244*0fca6ea1SDimitry Andric       Changed = true;
245*0fca6ea1SDimitry Andric       Memcpy->eraseFromParent();
246*0fca6ea1SDimitry Andric       break;
247*0fca6ea1SDimitry Andric     }
24806c3fb27SDimitry Andric     case Intrinsic::memmove: {
24906c3fb27SDimitry Andric       auto *Memmove = cast<MemMoveInst>(Inst);
25006c3fb27SDimitry Andric       Function *ParentFunc = Memmove->getFunction();
25106c3fb27SDimitry Andric       const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
25206c3fb27SDimitry Andric       if (shouldExpandMemIntrinsicWithSize(Memmove->getLength(), TTI)) {
25306c3fb27SDimitry Andric         if (UseMemIntrinsicLibFunc &&
2548a4dda33SDimitry Andric             canEmitLibcall(TM, ParentFunc, RTLIB::MEMMOVE))
25506c3fb27SDimitry Andric           break;
25606c3fb27SDimitry Andric 
25706c3fb27SDimitry Andric         if (expandMemMoveAsLoop(Memmove, TTI)) {
25806c3fb27SDimitry Andric           Changed = true;
25906c3fb27SDimitry Andric           Memmove->eraseFromParent();
26006c3fb27SDimitry Andric         }
26106c3fb27SDimitry Andric       }
26206c3fb27SDimitry Andric 
26306c3fb27SDimitry Andric       break;
26406c3fb27SDimitry Andric     }
26506c3fb27SDimitry Andric     case Intrinsic::memset: {
26606c3fb27SDimitry Andric       auto *Memset = cast<MemSetInst>(Inst);
26706c3fb27SDimitry Andric       Function *ParentFunc = Memset->getFunction();
26806c3fb27SDimitry Andric       const TargetTransformInfo &TTI = LookupTTI(*ParentFunc);
26906c3fb27SDimitry Andric       if (shouldExpandMemIntrinsicWithSize(Memset->getLength(), TTI)) {
27006c3fb27SDimitry Andric         if (UseMemIntrinsicLibFunc &&
2718a4dda33SDimitry Andric             canEmitLibcall(TM, ParentFunc, RTLIB::MEMSET))
27206c3fb27SDimitry Andric           break;
27306c3fb27SDimitry Andric 
27406c3fb27SDimitry Andric         expandMemSetAsLoop(Memset);
27506c3fb27SDimitry Andric         Changed = true;
27606c3fb27SDimitry Andric         Memset->eraseFromParent();
27706c3fb27SDimitry Andric       }
27806c3fb27SDimitry Andric 
27906c3fb27SDimitry Andric       break;
28006c3fb27SDimitry Andric     }
281*0fca6ea1SDimitry Andric     case Intrinsic::memset_inline: {
282*0fca6ea1SDimitry Andric       // Only expand llvm.memset.inline with non-constant length in this
283*0fca6ea1SDimitry Andric       // codepath, leaving the current SelectionDAG expansion for constant
284*0fca6ea1SDimitry Andric       // length memset intrinsics undisturbed.
285*0fca6ea1SDimitry Andric       auto *Memset = cast<MemSetInlineInst>(Inst);
286*0fca6ea1SDimitry Andric       if (isa<ConstantInt>(Memset->getLength()))
287*0fca6ea1SDimitry Andric         break;
288*0fca6ea1SDimitry Andric 
289*0fca6ea1SDimitry Andric       expandMemSetAsLoop(Memset);
290*0fca6ea1SDimitry Andric       Changed = true;
291*0fca6ea1SDimitry Andric       Memset->eraseFromParent();
292*0fca6ea1SDimitry Andric       break;
293*0fca6ea1SDimitry Andric     }
29406c3fb27SDimitry Andric     default:
29506c3fb27SDimitry Andric       llvm_unreachable("unhandled intrinsic");
29606c3fb27SDimitry Andric     }
29706c3fb27SDimitry Andric   }
29806c3fb27SDimitry Andric 
29906c3fb27SDimitry Andric   return Changed;
30006c3fb27SDimitry Andric }
30106c3fb27SDimitry Andric 
30206c3fb27SDimitry Andric bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const {
3030b57cec5SDimitry Andric   bool Changed = false;
3040b57cec5SDimitry Andric   for (Function &F : M) {
3050b57cec5SDimitry Andric     switch (F.getIntrinsicID()) {
3060b57cec5SDimitry Andric     default:
3070b57cec5SDimitry Andric       break;
30806c3fb27SDimitry Andric     case Intrinsic::memcpy:
309*0fca6ea1SDimitry Andric     case Intrinsic::memcpy_inline:
31006c3fb27SDimitry Andric     case Intrinsic::memmove:
31106c3fb27SDimitry Andric     case Intrinsic::memset:
312*0fca6ea1SDimitry Andric     case Intrinsic::memset_inline:
31306c3fb27SDimitry Andric       Changed |= expandMemIntrinsicUses(F);
31406c3fb27SDimitry Andric       break;
31506c3fb27SDimitry Andric     case Intrinsic::load_relative:
31606c3fb27SDimitry Andric       Changed |= lowerLoadRelative(F);
31706c3fb27SDimitry Andric       break;
3180b57cec5SDimitry Andric     case Intrinsic::objc_autorelease:
3190b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autorelease");
3200b57cec5SDimitry Andric       break;
3210b57cec5SDimitry Andric     case Intrinsic::objc_autoreleasePoolPop:
3220b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autoreleasePoolPop");
3230b57cec5SDimitry Andric       break;
3240b57cec5SDimitry Andric     case Intrinsic::objc_autoreleasePoolPush:
3250b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autoreleasePoolPush");
3260b57cec5SDimitry Andric       break;
3270b57cec5SDimitry Andric     case Intrinsic::objc_autoreleaseReturnValue:
3280b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_autoreleaseReturnValue");
3290b57cec5SDimitry Andric       break;
3300b57cec5SDimitry Andric     case Intrinsic::objc_copyWeak:
3310b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_copyWeak");
3320b57cec5SDimitry Andric       break;
3330b57cec5SDimitry Andric     case Intrinsic::objc_destroyWeak:
3340b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_destroyWeak");
3350b57cec5SDimitry Andric       break;
3360b57cec5SDimitry Andric     case Intrinsic::objc_initWeak:
3370b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_initWeak");
3380b57cec5SDimitry Andric       break;
3390b57cec5SDimitry Andric     case Intrinsic::objc_loadWeak:
3400b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_loadWeak");
3410b57cec5SDimitry Andric       break;
3420b57cec5SDimitry Andric     case Intrinsic::objc_loadWeakRetained:
3430b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_loadWeakRetained");
3440b57cec5SDimitry Andric       break;
3450b57cec5SDimitry Andric     case Intrinsic::objc_moveWeak:
3460b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_moveWeak");
3470b57cec5SDimitry Andric       break;
3480b57cec5SDimitry Andric     case Intrinsic::objc_release:
3490b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_release", true);
3500b57cec5SDimitry Andric       break;
3510b57cec5SDimitry Andric     case Intrinsic::objc_retain:
3520b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retain", true);
3530b57cec5SDimitry Andric       break;
3540b57cec5SDimitry Andric     case Intrinsic::objc_retainAutorelease:
3550b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainAutorelease");
3560b57cec5SDimitry Andric       break;
3570b57cec5SDimitry Andric     case Intrinsic::objc_retainAutoreleaseReturnValue:
3580b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainAutoreleaseReturnValue");
3590b57cec5SDimitry Andric       break;
3600b57cec5SDimitry Andric     case Intrinsic::objc_retainAutoreleasedReturnValue:
3610b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainAutoreleasedReturnValue");
3620b57cec5SDimitry Andric       break;
3630b57cec5SDimitry Andric     case Intrinsic::objc_retainBlock:
3640b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainBlock");
3650b57cec5SDimitry Andric       break;
3660b57cec5SDimitry Andric     case Intrinsic::objc_storeStrong:
3670b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_storeStrong");
3680b57cec5SDimitry Andric       break;
3690b57cec5SDimitry Andric     case Intrinsic::objc_storeWeak:
3700b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_storeWeak");
3710b57cec5SDimitry Andric       break;
3720b57cec5SDimitry Andric     case Intrinsic::objc_unsafeClaimAutoreleasedReturnValue:
3730b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_unsafeClaimAutoreleasedReturnValue");
3740b57cec5SDimitry Andric       break;
3750b57cec5SDimitry Andric     case Intrinsic::objc_retainedObject:
3760b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retainedObject");
3770b57cec5SDimitry Andric       break;
3780b57cec5SDimitry Andric     case Intrinsic::objc_unretainedObject:
3790b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_unretainedObject");
3800b57cec5SDimitry Andric       break;
3810b57cec5SDimitry Andric     case Intrinsic::objc_unretainedPointer:
3820b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_unretainedPointer");
3830b57cec5SDimitry Andric       break;
3840b57cec5SDimitry Andric     case Intrinsic::objc_retain_autorelease:
3850b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_retain_autorelease");
3860b57cec5SDimitry Andric       break;
3870b57cec5SDimitry Andric     case Intrinsic::objc_sync_enter:
3880b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_sync_enter");
3890b57cec5SDimitry Andric       break;
3900b57cec5SDimitry Andric     case Intrinsic::objc_sync_exit:
3910b57cec5SDimitry Andric       Changed |= lowerObjCCall(F, "objc_sync_exit");
3920b57cec5SDimitry Andric       break;
3930b57cec5SDimitry Andric     }
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric   return Changed;
3960b57cec5SDimitry Andric }
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric namespace {
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric class PreISelIntrinsicLoweringLegacyPass : public ModulePass {
4010b57cec5SDimitry Andric public:
4020b57cec5SDimitry Andric   static char ID;
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   PreISelIntrinsicLoweringLegacyPass() : ModulePass(ID) {}
4050b57cec5SDimitry Andric 
40606c3fb27SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
40706c3fb27SDimitry Andric     AU.addRequired<TargetTransformInfoWrapperPass>();
4088a4dda33SDimitry Andric     AU.addRequired<TargetPassConfig>();
40906c3fb27SDimitry Andric   }
41006c3fb27SDimitry Andric 
41106c3fb27SDimitry Andric   bool runOnModule(Module &M) override {
41206c3fb27SDimitry Andric     auto LookupTTI = [this](Function &F) -> TargetTransformInfo & {
41306c3fb27SDimitry Andric       return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
41406c3fb27SDimitry Andric     };
41506c3fb27SDimitry Andric 
4168a4dda33SDimitry Andric     const auto &TM = getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
4178a4dda33SDimitry Andric     PreISelIntrinsicLowering Lowering(TM, LookupTTI);
41806c3fb27SDimitry Andric     return Lowering.lowerIntrinsics(M);
41906c3fb27SDimitry Andric   }
4200b57cec5SDimitry Andric };
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric } // end anonymous namespace
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric char PreISelIntrinsicLoweringLegacyPass::ID;
4250b57cec5SDimitry Andric 
4268a4dda33SDimitry Andric INITIALIZE_PASS_BEGIN(PreISelIntrinsicLoweringLegacyPass,
4278a4dda33SDimitry Andric                       "pre-isel-intrinsic-lowering",
4288a4dda33SDimitry Andric                       "Pre-ISel Intrinsic Lowering", false, false)
4298a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
4308a4dda33SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
4318a4dda33SDimitry Andric INITIALIZE_PASS_END(PreISelIntrinsicLoweringLegacyPass,
4328a4dda33SDimitry Andric                     "pre-isel-intrinsic-lowering",
4338a4dda33SDimitry Andric                     "Pre-ISel Intrinsic Lowering", false, false)
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric ModulePass *llvm::createPreISelIntrinsicLoweringPass() {
4368a4dda33SDimitry Andric   return new PreISelIntrinsicLoweringLegacyPass();
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric PreservedAnalyses PreISelIntrinsicLoweringPass::run(Module &M,
4400b57cec5SDimitry Andric                                                     ModuleAnalysisManager &AM) {
44106c3fb27SDimitry Andric   auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
44206c3fb27SDimitry Andric 
44306c3fb27SDimitry Andric   auto LookupTTI = [&FAM](Function &F) -> TargetTransformInfo & {
44406c3fb27SDimitry Andric     return FAM.getResult<TargetIRAnalysis>(F);
44506c3fb27SDimitry Andric   };
44606c3fb27SDimitry Andric 
4478a4dda33SDimitry Andric   PreISelIntrinsicLowering Lowering(TM, LookupTTI);
44806c3fb27SDimitry Andric   if (!Lowering.lowerIntrinsics(M))
4490b57cec5SDimitry Andric     return PreservedAnalyses::all();
4500b57cec5SDimitry Andric   else
4510b57cec5SDimitry Andric     return PreservedAnalyses::none();
4520b57cec5SDimitry Andric }
453