llvm.org GIT mirror llvm / 742c524
[CodeExtractor] Factor out and reuse shrinkwrap analysis Factor out CodeExtractor's analysis of allocas (for shrinkwrapping purposes), and allow the analysis to be reused. This resolves a quadratic compile-time bug observed when compiling AMDGPUDisassembler.cpp.o. Pre-patch (Release + LTO clang): ``` ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name --- 176.5278 ( 57.8%) 0.4915 ( 18.5%) 177.0192 ( 57.4%) 177.4112 ( 57.3%) Hot Cold Splitting ``` Post-patch (ReleaseAsserts clang): ``` ---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name --- 1.4051 ( 3.3%) 0.0079 ( 0.3%) 1.4129 ( 3.2%) 1.4129 ( 3.2%) Hot Cold Splitting ``` Testing: check-llvm, and comparing the AMDGPUDisassembler.cpp.o binary pre- vs. post-patch. An alternate approach is to hide CodeExtractorAnalysisCache from clients of CodeExtractor, and to recompute the analysis from scratch inside of CodeExtractor::extractCodeRegion(). This eliminates some redundant work in the shrinkwrapping legality check. However, some clients continue to exhibit O(n^2) compile time behavior as computing the analysis is O(n). rdar://55912966 Differential Revision: https://reviews.llvm.org/D68616 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374089 91177308-0d34-0410-b5e6-96231b3b80d8 Vedant Kumar 1 year, 1 month ago
8 changed file(s) with 215 addition(s) and 127 deletion(s). Raw diff Collapse all Expand all
2222 class OptimizationRemarkEmitter;
2323 class AssumptionCache;
2424 class DominatorTree;
25 class CodeExtractorAnalysisCache;
2526
2627 /// A sequence of basic blocks.
2728 ///
4243 bool isFunctionCold(const Function &F) const;
4344 bool shouldOutlineFrom(const Function &F) const;
4445 bool outlineColdRegions(Function &F, bool HasProfileSummary);
45 Function *extractColdRegion(const BlockSequence &Region, DominatorTree &DT,
46 BlockFrequencyInfo *BFI, TargetTransformInfo &TTI,
46 Function *extractColdRegion(const BlockSequence &Region,
47 const CodeExtractorAnalysisCache &CEAC,
48 DominatorTree &DT, BlockFrequencyInfo *BFI,
49 TargetTransformInfo &TTI,
4750 OptimizationRemarkEmitter &ORE,
4851 AssumptionCache *AC, unsigned Count);
4952 ProfileSummaryInfo *PSI;
2121
2222 namespace llvm {
2323
24 class AllocaInst;
2425 class BasicBlock;
2526 class BlockFrequency;
2627 class BlockFrequencyInfo;
3435 class Module;
3536 class Type;
3637 class Value;
38
39 /// A cache for the CodeExtractor analysis. The operation \ref
40 /// CodeExtractor::extractCodeRegion is guaranteed not to invalidate this
41 /// object. This object should conservatively be considered invalid if any
42 /// other mutating operations on the IR occur.
43 ///
44 /// Constructing this object is O(n) in the size of the function.
45 class CodeExtractorAnalysisCache {
46 /// The allocas in the function.
47 SmallVector Allocas;
48
49 /// Base memory addresses of load/store instructions, grouped by block.
50 DenseMap> BaseMemAddrs;
51
52 /// Blocks which contain instructions which may have unknown side-effects
53 /// on memory.
54 DenseSet SideEffectingBlocks;
55
56 void findSideEffectInfoForBlock(BasicBlock &BB);
57
58 public:
59 CodeExtractorAnalysisCache(Function &F);
60
61 /// Get the allocas in the function at the time the analysis was created.
62 /// Note that some of these allocas may no longer be present in the function,
63 /// due to \ref CodeExtractor::extractCodeRegion.
64 ArrayRef getAllocas() const { return Allocas; }
65
66 /// Check whether \p BB contains an instruction thought to load from, store
67 /// to, or otherwise clobber the alloca \p Addr.
68 bool doesBlockContainClobberOfAddr(BasicBlock &BB, AllocaInst *Addr) const;
69 };
3770
3871 /// Utility class for extracting code into a new function.
3972 ///
103136 ///
104137 /// Returns zero when called on a CodeExtractor instance where isEligible
105138 /// returns false.
106 Function *extractCodeRegion();
139 Function *extractCodeRegion(const CodeExtractorAnalysisCache &CEAC);
107140
108141 /// Verify that assumption cache isn't stale after a region is extracted.
109142 /// Returns false when verifier finds errors. AssumptionCache is passed as
134167 /// region.
135168 ///
136169 /// Returns true if it is safe to do the code motion.
137 bool isLegalToShrinkwrapLifetimeMarkers(Instruction *AllocaAddr) const;
170 bool
171 isLegalToShrinkwrapLifetimeMarkers(const CodeExtractorAnalysisCache &CEAC,
172 Instruction *AllocaAddr) const;
138173
139174 /// Find the set of allocas whose life ranges are contained within the
140175 /// outlined region.
144179 /// are used by the lifetime markers are also candidates for shrink-
145180 /// wrapping. The instructions that need to be sunk are collected in
146181 /// 'Allocas'.
147 void findAllocas(ValueSet &SinkCands, ValueSet &HoistCands,
182 void findAllocas(const CodeExtractorAnalysisCache &CEAC,
183 ValueSet &SinkCands, ValueSet &HoistCands,
148184 BasicBlock *&ExitBlock) const;
149185
150186 /// Find or create a block within the outline region for placing hoisted
165201 Instruction *LifeEnd = nullptr;
166202 };
167203
168 LifetimeMarkerInfo getLifetimeMarkers(Instruction *Addr,
169 BasicBlock *ExitBlock) const;
204 LifetimeMarkerInfo
205 getLifetimeMarkers(const CodeExtractorAnalysisCache &CEAC,
206 Instruction *Addr, BasicBlock *ExitBlock) const;
170207
171208 void severSplitPHINodesOfEntry(BasicBlock *&Header);
172209 void severSplitPHINodesOfExits(const SmallPtrSetImpl &Exits);
205205 ++NumExtracted;
206206 Changed = true;
207207 }
208 Function *F = CodeExtractor(BlocksToExtractVec).extractCodeRegion();
208 CodeExtractorAnalysisCache CEAC(*BBs[0]->getParent());
209 Function *F = CodeExtractor(BlocksToExtractVec).extractCodeRegion(CEAC);
209210 if (F)
210211 LLVM_DEBUG(dbgs() << "Extracted group '" << (*BBs.begin())->getName()
211212 << "' in: " << F->getName() << '\n');
289289 return Penalty;
290290 }
291291
292 Function *HotColdSplitting::extractColdRegion(const BlockSequence &Region,
293 DominatorTree &DT,
294 BlockFrequencyInfo *BFI,
295 TargetTransformInfo &TTI,
296 OptimizationRemarkEmitter &ORE,
297 AssumptionCache *AC,
298 unsigned Count) {
292 Function *HotColdSplitting::extractColdRegion(
293 const BlockSequence &Region, const CodeExtractorAnalysisCache &CEAC,
294 DominatorTree &DT, BlockFrequencyInfo *BFI, TargetTransformInfo &TTI,
295 OptimizationRemarkEmitter &ORE, AssumptionCache *AC, unsigned Count) {
299296 assert(!Region.empty());
300297
301298 // TODO: Pass BFI and BPI to update profile information.
317314 return nullptr;
318315
319316 Function *OrigF = Region[0]->getParent();
320 if (Function *OutF = CE.extractCodeRegion()) {
317 if (Function *OutF = CE.extractCodeRegion(CEAC)) {
321318 User *U = *OutF->user_begin();
322319 CallInst *CI = cast(U);
323320 CallSite CS(CI);
605602 }
606603 }
607604
605 if (OutliningWorklist.empty())
606 return Changed;
607
608608 // Outline single-entry cold regions, splitting up larger regions as needed.
609609 unsigned OutlinedFunctionID = 1;
610 while (!OutliningWorklist.empty()) {
610 // Cache and recycle the CodeExtractor analysis to avoid O(n^2) compile-time.
611 CodeExtractorAnalysisCache CEAC(F);
612 do {
611613 OutliningRegion Region = OutliningWorklist.pop_back_val();
612614 assert(!Region.empty() && "Empty outlining region in worklist");
613615 do {
618620 BB->dump();
619621 });
620622
621 Function *Outlined = extractColdRegion(SubRegion, *DT, BFI, TTI, ORE, AC,
622 OutlinedFunctionID);
623 Function *Outlined = extractColdRegion(SubRegion, CEAC, *DT, BFI, TTI,
624 ORE, AC, OutlinedFunctionID);
623625 if (Outlined) {
624626 ++OutlinedFunctionID;
625627 Changed = true;
626628 }
627629 } while (!Region.empty());
628 }
630 } while (!OutliningWorklist.empty());
629631
630632 return Changed;
631633 }
140140 if (NumLoops == 0) return Changed;
141141 --NumLoops;
142142 AssumptionCache *AC = nullptr;
143 Function &Func = *L->getHeader()->getParent();
143144 if (auto *ACT = getAnalysisIfAvailable())
144 AC = ACT->lookupAssumptionCache(*L->getHeader()->getParent());
145 AC = ACT->lookupAssumptionCache(Func);
146 CodeExtractorAnalysisCache CEAC(Func);
145147 CodeExtractor Extractor(DT, *L, false, nullptr, nullptr, AC);
146 if (Extractor.extractCodeRegion() != nullptr) {
148 if (Extractor.extractCodeRegion(CEAC) != nullptr) {
147149 Changed = true;
148150 // After extraction, the loop is replaced by a function call, so
149151 // we shouldn't try to run any more loop passes on it.
11211121 BranchProbabilityInfo BPI(*ClonedFunc, LI);
11221122 ClonedFuncBFI.reset(new BlockFrequencyInfo(*ClonedFunc, BPI, LI));
11231123
1124 // Cache and recycle the CodeExtractor analysis to avoid O(n^2) compile-time.
1125 CodeExtractorAnalysisCache CEAC(*ClonedFunc);
1126
11241127 SetVector Inputs, Outputs, Sinks;
11251128 for (FunctionOutliningMultiRegionInfo::OutlineRegionInfo RegionInfo :
11261129 ClonedOMRI->ORI) {
11471150 if (Outputs.size() > 0 && !ForceLiveExit)
11481151 continue;
11491152
1150 Function *OutlinedFunc = CE.extractCodeRegion();
1153 Function *OutlinedFunc = CE.extractCodeRegion(CEAC);
11511154
11521155 if (OutlinedFunc) {
11531156 CallSite OCS = PartialInlinerImpl::getOneCallSiteTo(OutlinedFunc);
12091212 }
12101213
12111214 // Extract the body of the if.
1215 CodeExtractorAnalysisCache CEAC(*ClonedFunc);
12121216 Function *OutlinedFunc =
12131217 CodeExtractor(ToExtract, &DT, /*AggregateArgs*/ false,
12141218 ClonedFuncBFI.get(), &BPI, LookupAC(*ClonedFunc),
12151219 /* AllowVarargs */ true)
1216 .extractCodeRegion();
1220 .extractCodeRegion(CEAC);
12171221
12181222 if (OutlinedFunc) {
12191223 BasicBlock *OutliningCallBB =
304304 return CommonExitBlock;
305305 }
306306
307 CodeExtractorAnalysisCache::CodeExtractorAnalysisCache(Function &F) {
308 for (BasicBlock &BB : F) {
309 for (Instruction &II : BB.instructionsWithoutDebug())
310 if (auto *AI = dyn_cast(&II))
311 Allocas.push_back(AI);
312
313 findSideEffectInfoForBlock(BB);
314 }
315 }
316
317 void CodeExtractorAnalysisCache::findSideEffectInfoForBlock(BasicBlock &BB) {
318 for (Instruction &II : BB.instructionsWithoutDebug()) {
319 unsigned Opcode = II.getOpcode();
320 Value *MemAddr = nullptr;
321 switch (Opcode) {
322 case Instruction::Store:
323 case Instruction::Load: {
324 if (Opcode == Instruction::Store) {
325 StoreInst *SI = cast(&II);
326 MemAddr = SI->getPointerOperand();
327 } else {
328 LoadInst *LI = cast(&II);
329 MemAddr = LI->getPointerOperand();
330 }
331 // Global variable can not be aliased with locals.
332 if (dyn_cast(MemAddr))
333 break;
334 Value *Base = MemAddr->stripInBoundsConstantOffsets();
335 if (!isa(Base)) {
336 SideEffectingBlocks.insert(&BB);
337 return;
338 }
339 BaseMemAddrs[&BB].insert(Base);
340 break;
341 }
342 default: {
343 IntrinsicInst *IntrInst = dyn_cast(&II);
344 if (IntrInst) {
345 if (IntrInst->isLifetimeStartOrEnd())
346 break;
347 SideEffectingBlocks.insert(&BB);
348 return;
349 }
350 // Treat all the other cases conservatively if it has side effects.
351 if (II.mayHaveSideEffects()) {
352 SideEffectingBlocks.insert(&BB);
353 return;
354 }
355 }
356 }
357 }
358 }
359
360 bool CodeExtractorAnalysisCache::doesBlockContainClobberOfAddr(
361 BasicBlock &BB, AllocaInst *Addr) const {
362 if (SideEffectingBlocks.count(&BB))
363 return true;
364 auto It = BaseMemAddrs.find(&BB);
365 if (It != BaseMemAddrs.end())
366 return It->second.count(Addr);
367 return false;
368 }
369
307370 bool CodeExtractor::isLegalToShrinkwrapLifetimeMarkers(
308 Instruction *Addr) const {
371 const CodeExtractorAnalysisCache &CEAC, Instruction *Addr) const {
309372 AllocaInst *AI = cast(Addr->stripInBoundsConstantOffsets());
310373 Function *Func = (*Blocks.begin())->getParent();
311374 for (BasicBlock &BB : *Func) {
312375 if (Blocks.count(&BB))
313376 continue;
314 for (Instruction &II : BB) {
315 if (isa(II))
316 continue;
317
318 unsigned Opcode = II.getOpcode();
319 Value *MemAddr = nullptr;
320 switch (Opcode) {
321 case Instruction::Store:
322 case Instruction::Load: {
323 if (Opcode == Instruction::Store) {
324 StoreInst *SI = cast(&II);
325 MemAddr = SI->getPointerOperand();
326 } else {
327 LoadInst *LI = cast(&II);
328 MemAddr = LI->getPointerOperand();
329 }
330 // Global variable can not be aliased with locals.
331 if (dyn_cast(MemAddr))
332 break;
333 Value *Base = MemAddr->stripInBoundsConstantOffsets();
334 if (!isa(Base) || Base == AI)
335 return false;
336 break;
337 }
338 default: {
339 IntrinsicInst *IntrInst = dyn_cast(&II);
340 if (IntrInst) {
341 if (IntrInst->isLifetimeStartOrEnd())
342 break;
343 return false;
344 }
345 // Treat all the other cases conservatively if it has side effects.
346 if (II.mayHaveSideEffects())
347 return false;
348 }
349 }
350 }
351 }
352
377 if (CEAC.doesBlockContainClobberOfAddr(BB, AI))
378 return false;
379 }
353380 return true;
354381 }
355382
412439 // outline region. If there are not other untracked uses of the address, return
413440 // the pair of markers if found; otherwise return a pair of nullptr.
414441 CodeExtractor::LifetimeMarkerInfo
415 CodeExtractor::getLifetimeMarkers(Instruction *Addr,
442 CodeExtractor::getLifetimeMarkers(const CodeExtractorAnalysisCache &CEAC,
443 Instruction *Addr,
416444 BasicBlock *ExitBlock) const {
417445 LifetimeMarkerInfo Info;
418446
444472 Info.HoistLifeEnd = !definedInRegion(Blocks, Info.LifeEnd);
445473 // Do legality check.
446474 if ((Info.SinkLifeStart || Info.HoistLifeEnd) &&
447 !isLegalToShrinkwrapLifetimeMarkers(Addr))
475 !isLegalToShrinkwrapLifetimeMarkers(CEAC, Addr))
448476 return {};
449477
450478 // Check to see if we have a place to do hoisting, if not, bail.
454482 return Info;
455483 }
456484
457 void CodeExtractor::findAllocas(ValueSet &SinkCands, ValueSet &HoistCands,
485 void CodeExtractor::findAllocas(const CodeExtractorAnalysisCache &CEAC,
486 ValueSet &SinkCands, ValueSet &HoistCands,
458487 BasicBlock *&ExitBlock) const {
459488 Function *Func = (*Blocks.begin())->getParent();
460489 ExitBlock = getCommonExitBlock(Blocks);
475504 return true;
476505 };
477506
478 for (BasicBlock &BB : *Func) {
479 if (Blocks.count(&BB))
480 continue;
481 for (Instruction &II : BB) {
482 auto *AI = dyn_cast(&II);
483 if (!AI)
484 continue;
485
486 LifetimeMarkerInfo MarkerInfo = getLifetimeMarkers(AI, ExitBlock);
487 bool Moved = moveOrIgnoreLifetimeMarkers(MarkerInfo);
488 if (Moved) {
489 LLVM_DEBUG(dbgs() << "Sinking alloca: " << *AI << "\n");
490 SinkCands.insert(AI);
491 continue;
492 }
493
494 // Follow any bitcasts.
495 SmallVector Bitcasts;
496 SmallVector BitcastLifetimeInfo;
497 for (User *U : AI->users()) {
498 if (U->stripInBoundsConstantOffsets() == AI) {
499 Instruction *Bitcast = cast(U);
500 LifetimeMarkerInfo LMI = getLifetimeMarkers(Bitcast, ExitBlock);
501 if (LMI.LifeStart) {
502 Bitcasts.push_back(Bitcast);
503 BitcastLifetimeInfo.push_back(LMI);
504 continue;
505 }
507 // Look up allocas in the original function in CodeExtractorAnalysisCache, as
508 // this is much faster than walking all the instructions.
509 for (AllocaInst *AI : CEAC.getAllocas()) {
510 BasicBlock *BB = AI->getParent();
511 if (Blocks.count(BB))
512 continue;
513
514 // As a prior call to extractCodeRegion() may have shrinkwrapped the alloca,
515 // check whether it is actually still in the original function.
516 Function *AIFunc = BB->getParent();
517 if (AIFunc != Func)
518 continue;
519
520 LifetimeMarkerInfo MarkerInfo = getLifetimeMarkers(CEAC, AI, ExitBlock);
521 bool Moved = moveOrIgnoreLifetimeMarkers(MarkerInfo);
522 if (Moved) {
523 LLVM_DEBUG(dbgs() << "Sinking alloca: " << *AI << "\n");
524 SinkCands.insert(AI);
525 continue;
526 }
527
528 // Follow any bitcasts.
529 SmallVector Bitcasts;
530 SmallVector BitcastLifetimeInfo;
531 for (User *U : AI->users()) {
532 if (U->stripInBoundsConstantOffsets() == AI) {
533 Instruction *Bitcast = cast(U);
534 LifetimeMarkerInfo LMI = getLifetimeMarkers(CEAC, Bitcast, ExitBlock);
535 if (LMI.LifeStart) {
536 Bitcasts.push_back(Bitcast);
537 BitcastLifetimeInfo.push_back(LMI);
538 continue;
506539 }
507
508 // Found unknown use of AI.
509 if (!definedInRegion(Blocks, U)) {
510 Bitcasts.clear();
511 break;
512 }
513 }
514
515 // Either no bitcasts reference the alloca or there are unknown uses.
516 if (Bitcasts.empty())
517 continue;
518
519 LLVM_DEBUG(dbgs() << "Sinking alloca (via bitcast): " << *AI << "\n");
520 SinkCands.insert(AI);
521 for (unsigned I = 0, E = Bitcasts.size(); I != E; ++I) {
522 Instruction *BitcastAddr = Bitcasts[I];
523 const LifetimeMarkerInfo &LMI = BitcastLifetimeInfo[I];
524 assert(LMI.LifeStart &&
525 "Unsafe to sink bitcast without lifetime markers");
526 moveOrIgnoreLifetimeMarkers(LMI);
527 if (!definedInRegion(Blocks, BitcastAddr)) {
528 LLVM_DEBUG(dbgs() << "Sinking bitcast-of-alloca: " << *BitcastAddr
529 << "\n");
530 SinkCands.insert(BitcastAddr);
531 }
540 }
541
542 // Found unknown use of AI.
543 if (!definedInRegion(Blocks, U)) {
544 Bitcasts.clear();
545 break;
546 }
547 }
548
549 // Either no bitcasts reference the alloca or there are unknown uses.
550 if (Bitcasts.empty())
551 continue;
552
553 LLVM_DEBUG(dbgs() << "Sinking alloca (via bitcast): " << *AI << "\n");
554 SinkCands.insert(AI);
555 for (unsigned I = 0, E = Bitcasts.size(); I != E; ++I) {
556 Instruction *BitcastAddr = Bitcasts[I];
557 const LifetimeMarkerInfo &LMI = BitcastLifetimeInfo[I];
558 assert(LMI.LifeStart &&
559 "Unsafe to sink bitcast without lifetime markers");
560 moveOrIgnoreLifetimeMarkers(LMI);
561 if (!definedInRegion(Blocks, BitcastAddr)) {
562 LLVM_DEBUG(dbgs() << "Sinking bitcast-of-alloca: " << *BitcastAddr
563 << "\n");
564 SinkCands.insert(BitcastAddr);
532565 }
533566 }
534567 }
13481381 MDBuilder(TI->getContext()).createBranchWeights(BranchWeights));
13491382 }
13501383
1351 Function *CodeExtractor::extractCodeRegion() {
1384 Function *
1385 CodeExtractor::extractCodeRegion(const CodeExtractorAnalysisCache &CEAC) {
13521386 if (!isEligible())
13531387 return nullptr;
13541388
14341468
14351469 ValueSet inputs, outputs, SinkingCands, HoistingCands;
14361470 BasicBlock *CommonExit = nullptr;
1437 findAllocas(SinkingCands, HoistingCands, CommonExit);
1471 findAllocas(CEAC, SinkingCands, HoistingCands, CommonExit);
14381472 assert(HoistingCands.empty() || CommonExit);
14391473
14401474 // Find inputs to, outputs from the code region.
6161 CodeExtractor CE(Candidates);
6262 EXPECT_TRUE(CE.isEligible());
6363
64 Function *Outlined = CE.extractCodeRegion();
64 CodeExtractorAnalysisCache CEAC(*Func);
65 Function *Outlined = CE.extractCodeRegion(CEAC);
6566 EXPECT_TRUE(Outlined);
6667 BasicBlock *Exit = getBlockByName(Func, "notExtracted");
6768 BasicBlock *ExitSplit = getBlockByName(Outlined, "notExtracted.split");
111112 CodeExtractor CE(ExtractedBlocks);
112113 EXPECT_TRUE(CE.isEligible());
113114
114 Function *Outlined = CE.extractCodeRegion();
115 CodeExtractorAnalysisCache CEAC(*Func);
116 Function *Outlined = CE.extractCodeRegion(CEAC);
115117 EXPECT_TRUE(Outlined);
116118 BasicBlock *Exit1 = getBlockByName(Func, "exit1");
117119 BasicBlock *Exit2 = getBlockByName(Func, "exit2");
185187 CodeExtractor CE(ExtractedBlocks);
186188 EXPECT_TRUE(CE.isEligible());
187189
188 Function *Outlined = CE.extractCodeRegion();
190 CodeExtractorAnalysisCache CEAC(*Func);
191 Function *Outlined = CE.extractCodeRegion(CEAC);
189192 EXPECT_TRUE(Outlined);
190193 EXPECT_FALSE(verifyFunction(*Outlined, &errs()));
191194 EXPECT_FALSE(verifyFunction(*Func, &errs()));
219222 CodeExtractor CE(Blocks);
220223 EXPECT_TRUE(CE.isEligible());
221224
222 Function *Outlined = CE.extractCodeRegion();
225 CodeExtractorAnalysisCache CEAC(*Func);
226 Function *Outlined = CE.extractCodeRegion(CEAC);
223227 EXPECT_TRUE(Outlined);
224228 EXPECT_FALSE(verifyFunction(*Outlined));
225229 EXPECT_FALSE(verifyFunction(*Func));
270274 CodeExtractor CE(Blocks, nullptr, false, nullptr, nullptr, &AC);
271275 EXPECT_TRUE(CE.isEligible());
272276
273 Function *Outlined = CE.extractCodeRegion();
277 CodeExtractorAnalysisCache CEAC(*Func);
278 Function *Outlined = CE.extractCodeRegion(CEAC);
274279 EXPECT_TRUE(Outlined);
275280 EXPECT_FALSE(verifyFunction(*Outlined));
276281 EXPECT_FALSE(verifyFunction(*Func));