PGOMemOPSizeOpt.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. //===-- PGOMemOPSizeOpt.cpp - Optimizations based on value profiling ===//
  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 the transformation that optimizes memory intrinsics
  10. // such as memcpy using the size value profile. When memory intrinsic size
  11. // value profile metadata is available, a single memory intrinsic is expanded
  12. // to a sequence of guarded specialized versions that are called with the
  13. // hottest size(s), for later expansion into more optimal inline sequences.
  14. //
  15. //===----------------------------------------------------------------------===//
  16. #include "llvm/ADT/ArrayRef.h"
  17. #include "llvm/ADT/Statistic.h"
  18. #include "llvm/ADT/StringRef.h"
  19. #include "llvm/ADT/Twine.h"
  20. #include "llvm/Analysis/BlockFrequencyInfo.h"
  21. #include "llvm/Analysis/DomTreeUpdater.h"
  22. #include "llvm/Analysis/GlobalsModRef.h"
  23. #include "llvm/Analysis/OptimizationRemarkEmitter.h"
  24. #include "llvm/Analysis/TargetLibraryInfo.h"
  25. #include "llvm/IR/BasicBlock.h"
  26. #include "llvm/IR/DerivedTypes.h"
  27. #include "llvm/IR/Dominators.h"
  28. #include "llvm/IR/Function.h"
  29. #include "llvm/IR/IRBuilder.h"
  30. #include "llvm/IR/InstVisitor.h"
  31. #include "llvm/IR/InstrTypes.h"
  32. #include "llvm/IR/Instruction.h"
  33. #include "llvm/IR/Instructions.h"
  34. #include "llvm/IR/LLVMContext.h"
  35. #include "llvm/IR/PassManager.h"
  36. #include "llvm/IR/Type.h"
  37. #include "llvm/InitializePasses.h"
  38. #include "llvm/Pass.h"
  39. #include "llvm/PassRegistry.h"
  40. #include "llvm/ProfileData/InstrProf.h"
  41. #define INSTR_PROF_VALUE_PROF_MEMOP_API
  42. #include "llvm/ProfileData/InstrProfData.inc"
  43. #include "llvm/Support/Casting.h"
  44. #include "llvm/Support/CommandLine.h"
  45. #include "llvm/Support/Debug.h"
  46. #include "llvm/Support/ErrorHandling.h"
  47. #include "llvm/Support/MathExtras.h"
  48. #include "llvm/Support/WithColor.h"
  49. #include "llvm/Transforms/Instrumentation.h"
  50. #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h"
  51. #include "llvm/Transforms/Utils/BasicBlockUtils.h"
  52. #include <cassert>
  53. #include <cstdint>
  54. #include <vector>
  55. using namespace llvm;
  56. #define DEBUG_TYPE "pgo-memop-opt"
  57. STATISTIC(NumOfPGOMemOPOpt, "Number of memop intrinsics optimized.");
  58. STATISTIC(NumOfPGOMemOPAnnotate, "Number of memop intrinsics annotated.");
  59. // The minimum call count to optimize memory intrinsic calls.
  60. static cl::opt<unsigned>
  61. MemOPCountThreshold("pgo-memop-count-threshold", cl::Hidden, cl::ZeroOrMore,
  62. cl::init(1000),
  63. cl::desc("The minimum count to optimize memory "
  64. "intrinsic calls"));
  65. // Command line option to disable memory intrinsic optimization. The default is
  66. // false. This is for debug purpose.
  67. static cl::opt<bool> DisableMemOPOPT("disable-memop-opt", cl::init(false),
  68. cl::Hidden, cl::desc("Disable optimize"));
  69. // The percent threshold to optimize memory intrinsic calls.
  70. static cl::opt<unsigned>
  71. MemOPPercentThreshold("pgo-memop-percent-threshold", cl::init(40),
  72. cl::Hidden, cl::ZeroOrMore,
  73. cl::desc("The percentage threshold for the "
  74. "memory intrinsic calls optimization"));
  75. // Maximum number of versions for optimizing memory intrinsic call.
  76. static cl::opt<unsigned>
  77. MemOPMaxVersion("pgo-memop-max-version", cl::init(3), cl::Hidden,
  78. cl::ZeroOrMore,
  79. cl::desc("The max version for the optimized memory "
  80. " intrinsic calls"));
  81. // Scale the counts from the annotation using the BB count value.
  82. static cl::opt<bool>
  83. MemOPScaleCount("pgo-memop-scale-count", cl::init(true), cl::Hidden,
  84. cl::desc("Scale the memop size counts using the basic "
  85. " block count value"));
  86. cl::opt<bool>
  87. MemOPOptMemcmpBcmp("pgo-memop-optimize-memcmp-bcmp", cl::init(true),
  88. cl::Hidden,
  89. cl::desc("Size-specialize memcmp and bcmp calls"));
  90. static cl::opt<unsigned>
  91. MemOpMaxOptSize("memop-value-prof-max-opt-size", cl::Hidden, cl::init(128),
  92. cl::desc("Optimize the memop size <= this value"));
  93. namespace {
  94. class PGOMemOPSizeOptLegacyPass : public FunctionPass {
  95. public:
  96. static char ID;
  97. PGOMemOPSizeOptLegacyPass() : FunctionPass(ID) {
  98. initializePGOMemOPSizeOptLegacyPassPass(*PassRegistry::getPassRegistry());
  99. }
  100. StringRef getPassName() const override { return "PGOMemOPSize"; }
  101. private:
  102. bool runOnFunction(Function &F) override;
  103. void getAnalysisUsage(AnalysisUsage &AU) const override {
  104. AU.addRequired<BlockFrequencyInfoWrapperPass>();
  105. AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
  106. AU.addPreserved<GlobalsAAWrapperPass>();
  107. AU.addPreserved<DominatorTreeWrapperPass>();
  108. AU.addRequired<TargetLibraryInfoWrapperPass>();
  109. }
  110. };
  111. } // end anonymous namespace
  112. char PGOMemOPSizeOptLegacyPass::ID = 0;
  113. INITIALIZE_PASS_BEGIN(PGOMemOPSizeOptLegacyPass, "pgo-memop-opt",
  114. "Optimize memory intrinsic using its size value profile",
  115. false, false)
  116. INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
  117. INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
  118. INITIALIZE_PASS_END(PGOMemOPSizeOptLegacyPass, "pgo-memop-opt",
  119. "Optimize memory intrinsic using its size value profile",
  120. false, false)
  121. FunctionPass *llvm::createPGOMemOPSizeOptLegacyPass() {
  122. return new PGOMemOPSizeOptLegacyPass();
  123. }
  124. namespace {
  125. static const char *getMIName(const MemIntrinsic *MI) {
  126. switch (MI->getIntrinsicID()) {
  127. case Intrinsic::memcpy:
  128. return "memcpy";
  129. case Intrinsic::memmove:
  130. return "memmove";
  131. case Intrinsic::memset:
  132. return "memset";
  133. default:
  134. return "unknown";
  135. }
  136. }
  137. // A class that abstracts a memop (memcpy, memmove, memset, memcmp and bcmp).
  138. struct MemOp {
  139. Instruction *I;
  140. MemOp(MemIntrinsic *MI) : I(MI) {}
  141. MemOp(CallInst *CI) : I(CI) {}
  142. MemIntrinsic *asMI() { return dyn_cast<MemIntrinsic>(I); }
  143. CallInst *asCI() { return cast<CallInst>(I); }
  144. MemOp clone() {
  145. if (auto MI = asMI())
  146. return MemOp(cast<MemIntrinsic>(MI->clone()));
  147. return MemOp(cast<CallInst>(asCI()->clone()));
  148. }
  149. Value *getLength() {
  150. if (auto MI = asMI())
  151. return MI->getLength();
  152. return asCI()->getArgOperand(2);
  153. }
  154. void setLength(Value *Length) {
  155. if (auto MI = asMI())
  156. return MI->setLength(Length);
  157. asCI()->setArgOperand(2, Length);
  158. }
  159. StringRef getFuncName() {
  160. if (auto MI = asMI())
  161. return MI->getCalledFunction()->getName();
  162. return asCI()->getCalledFunction()->getName();
  163. }
  164. bool isMemmove() {
  165. if (auto MI = asMI())
  166. if (MI->getIntrinsicID() == Intrinsic::memmove)
  167. return true;
  168. return false;
  169. }
  170. bool isMemcmp(TargetLibraryInfo &TLI) {
  171. LibFunc Func;
  172. if (asMI() == nullptr && TLI.getLibFunc(*asCI(), Func) &&
  173. Func == LibFunc_memcmp) {
  174. return true;
  175. }
  176. return false;
  177. }
  178. bool isBcmp(TargetLibraryInfo &TLI) {
  179. LibFunc Func;
  180. if (asMI() == nullptr && TLI.getLibFunc(*asCI(), Func) &&
  181. Func == LibFunc_bcmp) {
  182. return true;
  183. }
  184. return false;
  185. }
  186. const char *getName(TargetLibraryInfo &TLI) {
  187. if (auto MI = asMI())
  188. return getMIName(MI);
  189. LibFunc Func;
  190. if (TLI.getLibFunc(*asCI(), Func)) {
  191. if (Func == LibFunc_memcmp)
  192. return "memcmp";
  193. if (Func == LibFunc_bcmp)
  194. return "bcmp";
  195. }
  196. llvm_unreachable("Must be MemIntrinsic or memcmp/bcmp CallInst");
  197. return nullptr;
  198. }
  199. };
  200. class MemOPSizeOpt : public InstVisitor<MemOPSizeOpt> {
  201. public:
  202. MemOPSizeOpt(Function &Func, BlockFrequencyInfo &BFI,
  203. OptimizationRemarkEmitter &ORE, DominatorTree *DT,
  204. TargetLibraryInfo &TLI)
  205. : Func(Func), BFI(BFI), ORE(ORE), DT(DT), TLI(TLI), Changed(false) {
  206. ValueDataArray =
  207. std::make_unique<InstrProfValueData[]>(INSTR_PROF_NUM_BUCKETS);
  208. }
  209. bool isChanged() const { return Changed; }
  210. void perform() {
  211. WorkList.clear();
  212. visit(Func);
  213. for (auto &MO : WorkList) {
  214. ++NumOfPGOMemOPAnnotate;
  215. if (perform(MO)) {
  216. Changed = true;
  217. ++NumOfPGOMemOPOpt;
  218. LLVM_DEBUG(dbgs() << "MemOP call: " << MO.getFuncName()
  219. << "is Transformed.\n");
  220. }
  221. }
  222. }
  223. void visitMemIntrinsic(MemIntrinsic &MI) {
  224. Value *Length = MI.getLength();
  225. // Not perform on constant length calls.
  226. if (isa<ConstantInt>(Length))
  227. return;
  228. WorkList.push_back(MemOp(&MI));
  229. }
  230. void visitCallInst(CallInst &CI) {
  231. LibFunc Func;
  232. if (TLI.getLibFunc(CI, Func) &&
  233. (Func == LibFunc_memcmp || Func == LibFunc_bcmp) &&
  234. !isa<ConstantInt>(CI.getArgOperand(2))) {
  235. WorkList.push_back(MemOp(&CI));
  236. }
  237. }
  238. private:
  239. Function &Func;
  240. BlockFrequencyInfo &BFI;
  241. OptimizationRemarkEmitter &ORE;
  242. DominatorTree *DT;
  243. TargetLibraryInfo &TLI;
  244. bool Changed;
  245. std::vector<MemOp> WorkList;
  246. // The space to read the profile annotation.
  247. std::unique_ptr<InstrProfValueData[]> ValueDataArray;
  248. bool perform(MemOp MO);
  249. };
  250. static bool isProfitable(uint64_t Count, uint64_t TotalCount) {
  251. assert(Count <= TotalCount);
  252. if (Count < MemOPCountThreshold)
  253. return false;
  254. if (Count < TotalCount * MemOPPercentThreshold / 100)
  255. return false;
  256. return true;
  257. }
  258. static inline uint64_t getScaledCount(uint64_t Count, uint64_t Num,
  259. uint64_t Denom) {
  260. if (!MemOPScaleCount)
  261. return Count;
  262. bool Overflowed;
  263. uint64_t ScaleCount = SaturatingMultiply(Count, Num, &Overflowed);
  264. return ScaleCount / Denom;
  265. }
  266. bool MemOPSizeOpt::perform(MemOp MO) {
  267. assert(MO.I);
  268. if (MO.isMemmove())
  269. return false;
  270. if (!MemOPOptMemcmpBcmp && (MO.isMemcmp(TLI) || MO.isBcmp(TLI)))
  271. return false;
  272. uint32_t NumVals, MaxNumVals = INSTR_PROF_NUM_BUCKETS;
  273. uint64_t TotalCount;
  274. if (!getValueProfDataFromInst(*MO.I, IPVK_MemOPSize, MaxNumVals,
  275. ValueDataArray.get(), NumVals, TotalCount))
  276. return false;
  277. uint64_t ActualCount = TotalCount;
  278. uint64_t SavedTotalCount = TotalCount;
  279. if (MemOPScaleCount) {
  280. auto BBEdgeCount = BFI.getBlockProfileCount(MO.I->getParent());
  281. if (!BBEdgeCount)
  282. return false;
  283. ActualCount = *BBEdgeCount;
  284. }
  285. ArrayRef<InstrProfValueData> VDs(ValueDataArray.get(), NumVals);
  286. LLVM_DEBUG(dbgs() << "Read one memory intrinsic profile with count "
  287. << ActualCount << "\n");
  288. LLVM_DEBUG(
  289. for (auto &VD
  290. : VDs) { dbgs() << " (" << VD.Value << "," << VD.Count << ")\n"; });
  291. if (ActualCount < MemOPCountThreshold)
  292. return false;
  293. // Skip if the total value profiled count is 0, in which case we can't
  294. // scale up the counts properly (and there is no profitable transformation).
  295. if (TotalCount == 0)
  296. return false;
  297. TotalCount = ActualCount;
  298. if (MemOPScaleCount)
  299. LLVM_DEBUG(dbgs() << "Scale counts: numerator = " << ActualCount
  300. << " denominator = " << SavedTotalCount << "\n");
  301. // Keeping track of the count of the default case:
  302. uint64_t RemainCount = TotalCount;
  303. uint64_t SavedRemainCount = SavedTotalCount;
  304. SmallVector<uint64_t, 16> SizeIds;
  305. SmallVector<uint64_t, 16> CaseCounts;
  306. uint64_t MaxCount = 0;
  307. unsigned Version = 0;
  308. int64_t LastV = -1;
  309. // Default case is in the front -- save the slot here.
  310. CaseCounts.push_back(0);
  311. SmallVector<InstrProfValueData, 24> RemainingVDs;
  312. for (auto I = VDs.begin(), E = VDs.end(); I != E; ++I) {
  313. auto &VD = *I;
  314. int64_t V = VD.Value;
  315. uint64_t C = VD.Count;
  316. if (MemOPScaleCount)
  317. C = getScaledCount(C, ActualCount, SavedTotalCount);
  318. if (!InstrProfIsSingleValRange(V) || V > MemOpMaxOptSize) {
  319. RemainingVDs.push_back(VD);
  320. continue;
  321. }
  322. // ValueCounts are sorted on the count. Break at the first un-profitable
  323. // value.
  324. if (!isProfitable(C, RemainCount)) {
  325. RemainingVDs.insert(RemainingVDs.end(), I, E);
  326. break;
  327. }
  328. if (V == LastV) {
  329. LLVM_DEBUG(dbgs() << "Invalid Profile Data in Function " << Func.getName()
  330. << ": Two consecutive, identical values in MemOp value"
  331. "counts.\n");
  332. return false;
  333. }
  334. LastV = V;
  335. SizeIds.push_back(V);
  336. CaseCounts.push_back(C);
  337. if (C > MaxCount)
  338. MaxCount = C;
  339. assert(RemainCount >= C);
  340. RemainCount -= C;
  341. assert(SavedRemainCount >= VD.Count);
  342. SavedRemainCount -= VD.Count;
  343. if (++Version >= MemOPMaxVersion && MemOPMaxVersion != 0) {
  344. RemainingVDs.insert(RemainingVDs.end(), I + 1, E);
  345. break;
  346. }
  347. }
  348. if (Version == 0)
  349. return false;
  350. CaseCounts[0] = RemainCount;
  351. if (RemainCount > MaxCount)
  352. MaxCount = RemainCount;
  353. uint64_t SumForOpt = TotalCount - RemainCount;
  354. LLVM_DEBUG(dbgs() << "Optimize one memory intrinsic call to " << Version
  355. << " Versions (covering " << SumForOpt << " out of "
  356. << TotalCount << ")\n");
  357. // mem_op(..., size)
  358. // ==>
  359. // switch (size) {
  360. // case s1:
  361. // mem_op(..., s1);
  362. // goto merge_bb;
  363. // case s2:
  364. // mem_op(..., s2);
  365. // goto merge_bb;
  366. // ...
  367. // default:
  368. // mem_op(..., size);
  369. // goto merge_bb;
  370. // }
  371. // merge_bb:
  372. BasicBlock *BB = MO.I->getParent();
  373. LLVM_DEBUG(dbgs() << "\n\n== Basic Block Before ==\n");
  374. LLVM_DEBUG(dbgs() << *BB << "\n");
  375. auto OrigBBFreq = BFI.getBlockFreq(BB);
  376. BasicBlock *DefaultBB = SplitBlock(BB, MO.I, DT);
  377. BasicBlock::iterator It(*MO.I);
  378. ++It;
  379. assert(It != DefaultBB->end());
  380. BasicBlock *MergeBB = SplitBlock(DefaultBB, &(*It), DT);
  381. MergeBB->setName("MemOP.Merge");
  382. BFI.setBlockFreq(MergeBB, OrigBBFreq.getFrequency());
  383. DefaultBB->setName("MemOP.Default");
  384. DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
  385. auto &Ctx = Func.getContext();
  386. IRBuilder<> IRB(BB);
  387. BB->getTerminator()->eraseFromParent();
  388. Value *SizeVar = MO.getLength();
  389. SwitchInst *SI = IRB.CreateSwitch(SizeVar, DefaultBB, SizeIds.size());
  390. Type *MemOpTy = MO.I->getType();
  391. PHINode *PHI = nullptr;
  392. if (!MemOpTy->isVoidTy()) {
  393. // Insert a phi for the return values at the merge block.
  394. IRBuilder<> IRBM(MergeBB->getFirstNonPHI());
  395. PHI = IRBM.CreatePHI(MemOpTy, SizeIds.size() + 1, "MemOP.RVMerge");
  396. MO.I->replaceAllUsesWith(PHI);
  397. PHI->addIncoming(MO.I, DefaultBB);
  398. }
  399. // Clear the value profile data.
  400. MO.I->setMetadata(LLVMContext::MD_prof, nullptr);
  401. // If all promoted, we don't need the MD.prof metadata.
  402. if (SavedRemainCount > 0 || Version != NumVals) {
  403. // Otherwise we need update with the un-promoted records back.
  404. ArrayRef<InstrProfValueData> RemVDs(RemainingVDs);
  405. annotateValueSite(*Func.getParent(), *MO.I, RemVDs, SavedRemainCount,
  406. IPVK_MemOPSize, NumVals);
  407. }
  408. LLVM_DEBUG(dbgs() << "\n\n== Basic Block After==\n");
  409. std::vector<DominatorTree::UpdateType> Updates;
  410. if (DT)
  411. Updates.reserve(2 * SizeIds.size());
  412. for (uint64_t SizeId : SizeIds) {
  413. BasicBlock *CaseBB = BasicBlock::Create(
  414. Ctx, Twine("MemOP.Case.") + Twine(SizeId), &Func, DefaultBB);
  415. MemOp NewMO = MO.clone();
  416. // Fix the argument.
  417. auto *SizeType = dyn_cast<IntegerType>(NewMO.getLength()->getType());
  418. assert(SizeType && "Expected integer type size argument.");
  419. ConstantInt *CaseSizeId = ConstantInt::get(SizeType, SizeId);
  420. NewMO.setLength(CaseSizeId);
  421. CaseBB->getInstList().push_back(NewMO.I);
  422. IRBuilder<> IRBCase(CaseBB);
  423. IRBCase.CreateBr(MergeBB);
  424. SI->addCase(CaseSizeId, CaseBB);
  425. if (!MemOpTy->isVoidTy())
  426. PHI->addIncoming(NewMO.I, CaseBB);
  427. if (DT) {
  428. Updates.push_back({DominatorTree::Insert, CaseBB, MergeBB});
  429. Updates.push_back({DominatorTree::Insert, BB, CaseBB});
  430. }
  431. LLVM_DEBUG(dbgs() << *CaseBB << "\n");
  432. }
  433. DTU.applyUpdates(Updates);
  434. Updates.clear();
  435. setProfMetadata(Func.getParent(), SI, CaseCounts, MaxCount);
  436. LLVM_DEBUG(dbgs() << *BB << "\n");
  437. LLVM_DEBUG(dbgs() << *DefaultBB << "\n");
  438. LLVM_DEBUG(dbgs() << *MergeBB << "\n");
  439. ORE.emit([&]() {
  440. using namespace ore;
  441. return OptimizationRemark(DEBUG_TYPE, "memopt-opt", MO.I)
  442. << "optimized " << NV("Memop", MO.getName(TLI)) << " with count "
  443. << NV("Count", SumForOpt) << " out of " << NV("Total", TotalCount)
  444. << " for " << NV("Versions", Version) << " versions";
  445. });
  446. return true;
  447. }
  448. } // namespace
  449. static bool PGOMemOPSizeOptImpl(Function &F, BlockFrequencyInfo &BFI,
  450. OptimizationRemarkEmitter &ORE,
  451. DominatorTree *DT, TargetLibraryInfo &TLI) {
  452. if (DisableMemOPOPT)
  453. return false;
  454. if (F.hasFnAttribute(Attribute::OptimizeForSize))
  455. return false;
  456. MemOPSizeOpt MemOPSizeOpt(F, BFI, ORE, DT, TLI);
  457. MemOPSizeOpt.perform();
  458. return MemOPSizeOpt.isChanged();
  459. }
  460. bool PGOMemOPSizeOptLegacyPass::runOnFunction(Function &F) {
  461. BlockFrequencyInfo &BFI =
  462. getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI();
  463. auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
  464. auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>();
  465. DominatorTree *DT = DTWP ? &DTWP->getDomTree() : nullptr;
  466. TargetLibraryInfo &TLI =
  467. getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
  468. return PGOMemOPSizeOptImpl(F, BFI, ORE, DT, TLI);
  469. }
  470. namespace llvm {
  471. char &PGOMemOPSizeOptID = PGOMemOPSizeOptLegacyPass::ID;
  472. PreservedAnalyses PGOMemOPSizeOpt::run(Function &F,
  473. FunctionAnalysisManager &FAM) {
  474. auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
  475. auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
  476. auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
  477. auto &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
  478. bool Changed = PGOMemOPSizeOptImpl(F, BFI, ORE, DT, TLI);
  479. if (!Changed)
  480. return PreservedAnalyses::all();
  481. auto PA = PreservedAnalyses();
  482. PA.preserve<DominatorTreeAnalysis>();
  483. return PA;
  484. }
  485. } // namespace llvm