LLVM  15.0.0git
ObjCARCContract.cpp
Go to the documentation of this file.
1 //===- ObjCARCContract.cpp - ObjC ARC Optimization ------------------------===//
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 /// \file
9 /// This file defines late ObjC ARC optimizations. ARC stands for Automatic
10 /// Reference Counting and is a system for managing reference counts for objects
11 /// in Objective C.
12 ///
13 /// This specific file mainly deals with ``contracting'' multiple lower level
14 /// operations into singular higher level operations through pattern matching.
15 ///
16 /// WARNING: This file knows about certain library functions. It recognizes them
17 /// by name, and hardwires knowledge of their semantics.
18 ///
19 /// WARNING: This file knows about how certain Objective-C library functions are
20 /// used. Naive LLVM IR transformations which would otherwise be
21 /// behavior-preserving may break these assumptions.
22 ///
23 //===----------------------------------------------------------------------===//
24 
25 // TODO: ObjCARCContract could insert PHI nodes when uses aren't
26 // dominated by single calls.
27 
28 #include "ARCRuntimeEntryPoints.h"
29 #include "DependencyAnalysis.h"
30 #include "ObjCARC.h"
31 #include "ProvenanceAnalysis.h"
32 #include "llvm/ADT/Statistic.h"
36 #include "llvm/IR/Dominators.h"
37 #include "llvm/IR/InlineAsm.h"
38 #include "llvm/IR/InstIterator.h"
39 #include "llvm/IR/Operator.h"
40 #include "llvm/IR/PassManager.h"
41 #include "llvm/InitializePasses.h"
43 #include "llvm/Support/Debug.h"
46 
47 using namespace llvm;
48 using namespace llvm::objcarc;
49 
50 #define DEBUG_TYPE "objc-arc-contract"
51 
52 STATISTIC(NumPeeps, "Number of calls peephole-optimized");
53 STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed");
54 
55 //===----------------------------------------------------------------------===//
56 // Declarations
57 //===----------------------------------------------------------------------===//
58 
59 namespace {
60 /// Late ARC optimizations
61 ///
62 /// These change the IR in a way that makes it difficult to be analyzed by
63 /// ObjCARCOpt, so it's run late.
64 
65 class ObjCARCContract {
66  bool Changed;
67  bool CFGChanged;
68  AAResults *AA;
69  DominatorTree *DT;
72  BundledRetainClaimRVs *BundledInsts = nullptr;
73 
74  /// The inline asm string to insert between calls and RetainRV calls to make
75  /// the optimization work on targets which need it.
76  const MDString *RVInstMarker;
77 
78  /// The set of inserted objc_storeStrong calls. If at the end of walking the
79  /// function we have found no alloca instructions, these calls can be marked
80  /// "tail".
81  SmallPtrSet<CallInst *, 8> StoreStrongCalls;
82 
83  /// Returns true if we eliminated Inst.
84  bool tryToPeepholeInstruction(
85  Function &F, Instruction *Inst, inst_iterator &Iter,
86  bool &TailOkForStoreStrong,
87  const DenseMap<BasicBlock *, ColorVector> &BlockColors);
88 
89  bool optimizeRetainCall(Function &F, Instruction *Retain);
90 
91  bool contractAutorelease(Function &F, Instruction *Autorelease,
92  ARCInstKind Class);
93 
94  void tryToContractReleaseIntoStoreStrong(
95  Instruction *Release, inst_iterator &Iter,
96  const DenseMap<BasicBlock *, ColorVector> &BlockColors);
97 
98 public:
99  bool init(Module &M);
100  bool run(Function &F, AAResults *AA, DominatorTree *DT);
101  bool hasCFGChanged() const { return CFGChanged; }
102 };
103 
104 class ObjCARCContractLegacyPass : public FunctionPass {
105 public:
106  void getAnalysisUsage(AnalysisUsage &AU) const override;
107  bool runOnFunction(Function &F) override;
108 
109  static char ID;
110  ObjCARCContractLegacyPass() : FunctionPass(ID) {
112  }
113 };
114 }
115 
116 //===----------------------------------------------------------------------===//
117 // Implementation
118 //===----------------------------------------------------------------------===//
119 
120 /// Turn objc_retain into objc_retainAutoreleasedReturnValue if the operand is a
121 /// return value. We do this late so we do not disrupt the dataflow analysis in
122 /// ObjCARCOpt.
123 bool ObjCARCContract::optimizeRetainCall(Function &F, Instruction *Retain) {
124  const auto *Call = dyn_cast<CallBase>(GetArgRCIdentityRoot(Retain));
125  if (!Call)
126  return false;
127  if (Call->getParent() != Retain->getParent())
128  return false;
129 
130  // Check that the call is next to the retain.
131  BasicBlock::const_iterator I = ++Call->getIterator();
132  while (IsNoopInstruction(&*I))
133  ++I;
134  if (&*I != Retain)
135  return false;
136 
137  // Turn it to an objc_retainAutoreleasedReturnValue.
138  Changed = true;
139  ++NumPeeps;
140 
141  LLVM_DEBUG(
142  dbgs() << "Transforming objc_retain => "
143  "objc_retainAutoreleasedReturnValue since the operand is a "
144  "return value.\nOld: "
145  << *Retain << "\n");
146 
147  // We do not have to worry about tail calls/does not throw since
148  // retain/retainRV have the same properties.
150  cast<CallInst>(Retain)->setCalledFunction(Decl);
151 
152  LLVM_DEBUG(dbgs() << "New: " << *Retain << "\n");
153  return true;
154 }
155 
156 /// Merge an autorelease with a retain into a fused call.
157 bool ObjCARCContract::contractAutorelease(Function &F, Instruction *Autorelease,
158  ARCInstKind Class) {
159  const Value *Arg = GetArgRCIdentityRoot(Autorelease);
160 
161  // Check that there are no instructions between the retain and the autorelease
162  // (such as an autorelease_pop) which may change the count.
166  auto *Retain = dyn_cast_or_null<CallInst>(
167  findSingleDependency(DK, Arg, Autorelease->getParent(), Autorelease, PA));
168 
169  if (!Retain || GetBasicARCInstKind(Retain) != ARCInstKind::Retain ||
170  GetArgRCIdentityRoot(Retain) != Arg)
171  return false;
172 
173  Changed = true;
174  ++NumPeeps;
175 
176  LLVM_DEBUG(dbgs() << " Fusing retain/autorelease!\n"
177  " Autorelease:"
178  << *Autorelease
179  << "\n"
180  " Retain: "
181  << *Retain << "\n");
182 
183  Function *Decl = EP.get(Class == ARCInstKind::AutoreleaseRV
186  Retain->setCalledFunction(Decl);
187 
188  LLVM_DEBUG(dbgs() << " New RetainAutorelease: " << *Retain << "\n");
189 
190  EraseInstruction(Autorelease);
191  return true;
192 }
193 
195  Instruction *Release,
196  ProvenanceAnalysis &PA,
197  AAResults *AA) {
198  StoreInst *Store = nullptr;
199  bool SawRelease = false;
200 
201  // Get the location associated with Load.
203  auto *LocPtr = Loc.Ptr->stripPointerCasts();
204 
205  // Walk down to find the store and the release, which may be in either order.
206  for (auto I = std::next(BasicBlock::iterator(Load)),
207  E = Load->getParent()->end();
208  I != E; ++I) {
209  // If we found the store we were looking for and saw the release,
210  // break. There is no more work to be done.
211  if (Store && SawRelease)
212  break;
213 
214  // Now we know that we have not seen either the store or the release. If I
215  // is the release, mark that we saw the release and continue.
216  Instruction *Inst = &*I;
217  if (Inst == Release) {
218  SawRelease = true;
219  continue;
220  }
221 
222  // Otherwise, we check if Inst is a "good" store. Grab the instruction class
223  // of Inst.
224  ARCInstKind Class = GetBasicARCInstKind(Inst);
225 
226  // If we have seen the store, but not the release...
227  if (Store) {
228  // We need to make sure that it is safe to move the release from its
229  // current position to the store. This implies proving that any
230  // instruction in between Store and the Release conservatively can not use
231  // the RCIdentityRoot of Release. If we can prove we can ignore Inst, so
232  // continue...
233  if (!CanUse(Inst, Load, PA, Class)) {
234  continue;
235  }
236 
237  // Otherwise, be conservative and return nullptr.
238  return nullptr;
239  }
240 
241  // Ok, now we know we have not seen a store yet.
242 
243  // If Inst is a retain, we don't care about it as it doesn't prevent moving
244  // the load to the store.
245  //
246  // TODO: This is one area where the optimization could be made more
247  // aggressive.
248  if (IsRetain(Class))
249  continue;
250 
251  // See if Inst can write to our load location, if it can not, just ignore
252  // the instruction.
253  if (!isModSet(AA->getModRefInfo(Inst, Loc)))
254  continue;
255 
256  Store = dyn_cast<StoreInst>(Inst);
257 
258  // If Inst can, then check if Inst is a simple store. If Inst is not a
259  // store or a store that is not simple, then we have some we do not
260  // understand writing to this memory implying we can not move the load
261  // over the write to any subsequent store that we may find.
262  if (!Store || !Store->isSimple())
263  return nullptr;
264 
265  // Then make sure that the pointer we are storing to is Ptr. If so, we
266  // found our Store!
267  if (Store->getPointerOperand()->stripPointerCasts() == LocPtr)
268  continue;
269 
270  // Otherwise, we have an unknown store to some other ptr that clobbers
271  // Loc.Ptr. Bail!
272  return nullptr;
273  }
274 
275  // If we did not find the store or did not see the release, fail.
276  if (!Store || !SawRelease)
277  return nullptr;
278 
279  // We succeeded!
280  return Store;
281 }
282 
283 static Instruction *
285  Instruction *Release,
286  ProvenanceAnalysis &PA) {
287  // Walk up from the Store to find the retain.
288  BasicBlock::iterator I = Store->getIterator();
289  BasicBlock::iterator Begin = Store->getParent()->begin();
290  while (I != Begin && GetBasicARCInstKind(&*I) != ARCInstKind::Retain) {
291  Instruction *Inst = &*I;
292 
293  // It is only safe to move the retain to the store if we can prove
294  // conservatively that nothing besides the release can decrement reference
295  // counts in between the retain and the store.
296  if (CanDecrementRefCount(Inst, New, PA) && Inst != Release)
297  return nullptr;
298  --I;
299  }
300  Instruction *Retain = &*I;
302  return nullptr;
303  if (GetArgRCIdentityRoot(Retain) != New)
304  return nullptr;
305  return Retain;
306 }
307 
308 /// Attempt to merge an objc_release with a store, load, and objc_retain to form
309 /// an objc_storeStrong. An objc_storeStrong:
310 ///
311 /// objc_storeStrong(i8** %old_ptr, i8* new_value)
312 ///
313 /// is equivalent to the following IR sequence:
314 ///
315 /// ; Load old value.
316 /// %old_value = load i8** %old_ptr (1)
317 ///
318 /// ; Increment the new value and then release the old value. This must occur
319 /// ; in order in case old_value releases new_value in its destructor causing
320 /// ; us to potentially have a dangling ptr.
321 /// tail call i8* @objc_retain(i8* %new_value) (2)
322 /// tail call void @objc_release(i8* %old_value) (3)
323 ///
324 /// ; Store the new_value into old_ptr
325 /// store i8* %new_value, i8** %old_ptr (4)
326 ///
327 /// The safety of this optimization is based around the following
328 /// considerations:
329 ///
330 /// 1. We are forming the store strong at the store. Thus to perform this
331 /// optimization it must be safe to move the retain, load, and release to
332 /// (4).
333 /// 2. We need to make sure that any re-orderings of (1), (2), (3), (4) are
334 /// safe.
335 void ObjCARCContract::tryToContractReleaseIntoStoreStrong(
336  Instruction *Release, inst_iterator &Iter,
337  const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
338  // See if we are releasing something that we just loaded.
339  auto *Load = dyn_cast<LoadInst>(GetArgRCIdentityRoot(Release));
340  if (!Load || !Load->isSimple())
341  return;
342 
343  // For now, require everything to be in one basic block.
344  BasicBlock *BB = Release->getParent();
345  if (Load->getParent() != BB)
346  return;
347 
348  // First scan down the BB from Load, looking for a store of the RCIdentityRoot
349  // of Load's
350  StoreInst *Store =
352  // If we fail, bail.
353  if (!Store)
354  return;
355 
356  // Then find what new_value's RCIdentity Root is.
357  Value *New = GetRCIdentityRoot(Store->getValueOperand());
358 
359  // Then walk up the BB and look for a retain on New without any intervening
360  // instructions which conservatively might decrement ref counts.
362  findRetainForStoreStrongContraction(New, Store, Release, PA);
363 
364  // If we fail, bail.
365  if (!Retain)
366  return;
367 
368  Changed = true;
369  ++NumStoreStrongs;
370 
371  LLVM_DEBUG(
372  llvm::dbgs() << " Contracting retain, release into objc_storeStrong.\n"
373  << " Old:\n"
374  << " Store: " << *Store << "\n"
375  << " Release: " << *Release << "\n"
376  << " Retain: " << *Retain << "\n"
377  << " Load: " << *Load << "\n");
378 
379  LLVMContext &C = Release->getContext();
381  Type *I8XX = PointerType::getUnqual(I8X);
382 
383  Value *Args[] = { Load->getPointerOperand(), New };
384  if (Args[0]->getType() != I8XX)
385  Args[0] = new BitCastInst(Args[0], I8XX, "", Store);
386  if (Args[1]->getType() != I8X)
387  Args[1] = new BitCastInst(Args[1], I8X, "", Store);
390  objcarc::createCallInstWithColors(Decl, Args, "", Store, BlockColors);
391  StoreStrong->setDoesNotThrow();
392  StoreStrong->setDebugLoc(Store->getDebugLoc());
393 
394  // We can't set the tail flag yet, because we haven't yet determined
395  // whether there are any escaping allocas. Remember this call, so that
396  // we can set the tail flag once we know it's safe.
397  StoreStrongCalls.insert(StoreStrong);
398 
399  LLVM_DEBUG(llvm::dbgs() << " New Store Strong: " << *StoreStrong
400  << "\n");
401 
402  if (&*Iter == Retain) ++Iter;
403  if (&*Iter == Store) ++Iter;
404  Store->eraseFromParent();
405  Release->eraseFromParent();
406  EraseInstruction(Retain);
407  if (Load->use_empty())
408  Load->eraseFromParent();
409 }
410 
411 bool ObjCARCContract::tryToPeepholeInstruction(
412  Function &F, Instruction *Inst, inst_iterator &Iter,
413  bool &TailOkForStoreStrongs,
414  const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
415  // Only these library routines return their argument. In particular,
416  // objc_retainBlock does not necessarily return its argument.
418  switch (Class) {
421  return false;
424  return contractAutorelease(F, Inst, Class);
425  case ARCInstKind::Retain:
426  // Attempt to convert retains to retainrvs if they are next to function
427  // calls.
428  if (!optimizeRetainCall(F, Inst))
429  return false;
430  // If we succeed in our optimization, fall through.
434  // Return true if this is a bundled retainRV/claimRV call, which is always
435  // redundant with the attachedcall in the bundle, and is going to be erased
436  // at the end of this pass. This avoids undoing objc-arc-expand and
437  // replacing uses of the retainRV/claimRV call's argument with its result.
438  if (BundledInsts->contains(Inst))
439  return true;
440 
441  // If this isn't a bundled call, and the target doesn't need a special
442  // inline-asm marker, we're done: return now, and undo objc-arc-expand.
443  if (!RVInstMarker)
444  return false;
445 
446  // The target needs a special inline-asm marker. Insert it.
447 
448  BasicBlock::iterator BBI = Inst->getIterator();
449  BasicBlock *InstParent = Inst->getParent();
450 
451  // Step up to see if the call immediately precedes the RV call.
452  // If it's an invoke, we have to cross a block boundary. And we have
453  // to carefully dodge no-op instructions.
454  do {
455  if (BBI == InstParent->begin()) {
456  BasicBlock *Pred = InstParent->getSinglePredecessor();
457  if (!Pred)
458  goto decline_rv_optimization;
459  BBI = Pred->getTerminator()->getIterator();
460  break;
461  }
462  --BBI;
463  } while (IsNoopInstruction(&*BBI));
464 
465  if (GetRCIdentityRoot(&*BBI) == GetArgRCIdentityRoot(Inst)) {
466  LLVM_DEBUG(dbgs() << "Adding inline asm marker for the return value "
467  "optimization.\n");
468  Changed = true;
469  InlineAsm *IA =
471  /*isVarArg=*/false),
472  RVInstMarker->getString(),
473  /*Constraints=*/"", /*hasSideEffects=*/true);
474 
475  objcarc::createCallInstWithColors(IA, None, "", Inst, BlockColors);
476  }
477  decline_rv_optimization:
478  return false;
479  }
480  case ARCInstKind::InitWeak: {
481  // objc_initWeak(p, null) => *p = null
482  CallInst *CI = cast<CallInst>(Inst);
483  if (IsNullOrUndef(CI->getArgOperand(1))) {
484  Value *Null = ConstantPointerNull::get(cast<PointerType>(CI->getType()));
485  Changed = true;
486  new StoreInst(Null, CI->getArgOperand(0), CI);
487 
488  LLVM_DEBUG(dbgs() << "OBJCARCContract: Old = " << *CI << "\n"
489  << " New = " << *Null << "\n");
490 
491  CI->replaceAllUsesWith(Null);
492  CI->eraseFromParent();
493  }
494  return true;
495  }
497  // Try to form an objc store strong from our release. If we fail, there is
498  // nothing further to do below, so continue.
499  tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors);
500  return true;
501  case ARCInstKind::User:
502  // Be conservative if the function has any alloca instructions.
503  // Technically we only care about escaping alloca instructions,
504  // but this is sufficient to handle some interesting cases.
505  if (isa<AllocaInst>(Inst))
506  TailOkForStoreStrongs = false;
507  return true;
509  // Remove calls to @llvm.objc.clang.arc.use(...).
510  Changed = true;
511  Inst->eraseFromParent();
512  return true;
513  default:
514  if (auto *CI = dyn_cast<CallInst>(Inst))
515  if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use) {
516  // Remove calls to @llvm.objc.clang.arc.noop.use(...).
517  Changed = true;
518  CI->eraseFromParent();
519  }
520  return true;
521  }
522 }
523 
524 //===----------------------------------------------------------------------===//
525 // Top Level Driver
526 //===----------------------------------------------------------------------===//
527 
528 bool ObjCARCContract::init(Module &M) {
529  EP.init(&M);
530 
531  // Initialize RVInstMarker.
532  RVInstMarker = getRVInstMarker(M);
533 
534  return false;
535 }
536 
538  if (!EnableARCOpts)
539  return false;
540 
541  Changed = CFGChanged = false;
542  AA = A;
543  DT = D;
544  PA.setAA(A);
545  BundledRetainClaimRVs BRV(/*ContractPass=*/true);
546  BundledInsts = &BRV;
547 
548  std::pair<bool, bool> R = BundledInsts->insertAfterInvokes(F, DT);
549  Changed |= R.first;
550  CFGChanged |= R.second;
551 
553  if (F.hasPersonalityFn() &&
554  isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
555  BlockColors = colorEHFunclets(F);
556 
557  LLVM_DEBUG(llvm::dbgs() << "**** ObjCARC Contract ****\n");
558 
559  // Track whether it's ok to mark objc_storeStrong calls with the "tail"
560  // keyword. Be conservative if the function has variadic arguments.
561  // It seems that functions which "return twice" are also unsafe for the
562  // "tail" argument, because they are setjmp, which could need to
563  // return to an earlier stack state.
564  bool TailOkForStoreStrongs =
565  !F.isVarArg() && !F.callsFunctionThatReturnsTwice();
566 
567  // For ObjC library calls which return their argument, replace uses of the
568  // argument with uses of the call return value, if it dominates the use. This
569  // reduces register pressure.
570  for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E;) {
571  Instruction *Inst = &*I++;
572 
573  LLVM_DEBUG(dbgs() << "Visiting: " << *Inst << "\n");
574 
575  if (auto *CI = dyn_cast<CallInst>(Inst))
577  BundledInsts->insertRVCallWithColors(&*I, CI, BlockColors);
578  --I;
579  Changed = true;
580  }
581 
582  // First try to peephole Inst. If there is nothing further we can do in
583  // terms of undoing objc-arc-expand, process the next inst.
584  if (tryToPeepholeInstruction(F, Inst, I, TailOkForStoreStrongs,
585  BlockColors))
586  continue;
587 
588  // Otherwise, try to undo objc-arc-expand.
589 
590  // Don't use GetArgRCIdentityRoot because we don't want to look through bitcasts
591  // and such; to do the replacement, the argument must have type i8*.
592 
593  // Function for replacing uses of Arg dominated by Inst.
594  auto ReplaceArgUses = [Inst, this](Value *Arg) {
595  // If we're compiling bugpointed code, don't get in trouble.
596  if (!isa<Instruction>(Arg) && !isa<Argument>(Arg))
597  return;
598 
599  // Look through the uses of the pointer.
600  for (Value::use_iterator UI = Arg->use_begin(), UE = Arg->use_end();
601  UI != UE; ) {
602  // Increment UI now, because we may unlink its element.
603  Use &U = *UI++;
604  unsigned OperandNo = U.getOperandNo();
605 
606  // If the call's return value dominates a use of the call's argument
607  // value, rewrite the use to use the return value. We check for
608  // reachability here because an unreachable call is considered to
609  // trivially dominate itself, which would lead us to rewriting its
610  // argument in terms of its return value, which would lead to
611  // infinite loops in GetArgRCIdentityRoot.
612  if (!DT->isReachableFromEntry(U) || !DT->dominates(Inst, U))
613  continue;
614 
615  Changed = true;
616  Instruction *Replacement = Inst;
617  Type *UseTy = U.get()->getType();
618  if (PHINode *PHI = dyn_cast<PHINode>(U.getUser())) {
619  // For PHI nodes, insert the bitcast in the predecessor block.
620  unsigned ValNo = PHINode::getIncomingValueNumForOperand(OperandNo);
621  BasicBlock *IncomingBB = PHI->getIncomingBlock(ValNo);
622  if (Replacement->getType() != UseTy) {
623  // A catchswitch is both a pad and a terminator, meaning a basic
624  // block with a catchswitch has no insertion point. Keep going up
625  // the dominator tree until we find a non-catchswitch.
626  BasicBlock *InsertBB = IncomingBB;
627  while (isa<CatchSwitchInst>(InsertBB->getFirstNonPHI())) {
628  InsertBB = DT->getNode(InsertBB)->getIDom()->getBlock();
629  }
630 
631  assert(DT->dominates(Inst, &InsertBB->back()) &&
632  "Invalid insertion point for bitcast");
633  Replacement =
634  new BitCastInst(Replacement, UseTy, "", &InsertBB->back());
635  }
636 
637  // While we're here, rewrite all edges for this PHI, rather
638  // than just one use at a time, to minimize the number of
639  // bitcasts we emit.
640  for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i)
641  if (PHI->getIncomingBlock(i) == IncomingBB) {
642  // Keep the UI iterator valid.
643  if (UI != UE &&
644  &PHI->getOperandUse(
646  ++UI;
647  PHI->setIncomingValue(i, Replacement);
648  }
649  } else {
650  if (Replacement->getType() != UseTy)
651  Replacement = new BitCastInst(Replacement, UseTy, "",
652  cast<Instruction>(U.getUser()));
653  U.set(Replacement);
654  }
655  }
656  };
657 
658  Value *Arg = cast<CallInst>(Inst)->getArgOperand(0);
659  Value *OrigArg = Arg;
660 
661  // TODO: Change this to a do-while.
662  for (;;) {
663  ReplaceArgUses(Arg);
664 
665  // If Arg is a no-op casted pointer, strip one level of casts and iterate.
666  if (const BitCastInst *BI = dyn_cast<BitCastInst>(Arg))
667  Arg = BI->getOperand(0);
668  else if (isa<GEPOperator>(Arg) &&
669  cast<GEPOperator>(Arg)->hasAllZeroIndices())
670  Arg = cast<GEPOperator>(Arg)->getPointerOperand();
671  else if (isa<GlobalAlias>(Arg) &&
672  !cast<GlobalAlias>(Arg)->isInterposable())
673  Arg = cast<GlobalAlias>(Arg)->getAliasee();
674  else {
675  // If Arg is a PHI node, get PHIs that are equivalent to it and replace
676  // their uses.
677  if (PHINode *PN = dyn_cast<PHINode>(Arg)) {
678  SmallVector<Value *, 1> PHIList;
679  getEquivalentPHIs(*PN, PHIList);
680  for (Value *PHI : PHIList)
681  ReplaceArgUses(PHI);
682  }
683  break;
684  }
685  }
686 
687  // Replace bitcast users of Arg that are dominated by Inst.
688  SmallVector<BitCastInst *, 2> BitCastUsers;
689 
690  // Add all bitcast users of the function argument first.
691  for (User *U : OrigArg->users())
692  if (auto *BC = dyn_cast<BitCastInst>(U))
693  BitCastUsers.push_back(BC);
694 
695  // Replace the bitcasts with the call return. Iterate until list is empty.
696  while (!BitCastUsers.empty()) {
697  auto *BC = BitCastUsers.pop_back_val();
698  for (User *U : BC->users())
699  if (auto *B = dyn_cast<BitCastInst>(U))
700  BitCastUsers.push_back(B);
701 
702  ReplaceArgUses(BC);
703  }
704  }
705 
706  // If this function has no escaping allocas or suspicious vararg usage,
707  // objc_storeStrong calls can be marked with the "tail" keyword.
708  if (TailOkForStoreStrongs)
709  for (CallInst *CI : StoreStrongCalls)
710  CI->setTailCall();
711  StoreStrongCalls.clear();
712 
713  return Changed;
714 }
715 
716 //===----------------------------------------------------------------------===//
717 // Misc Pass Manager
718 //===----------------------------------------------------------------------===//
719 
721 INITIALIZE_PASS_BEGIN(ObjCARCContractLegacyPass, "objc-arc-contract",
722  "ObjC ARC contraction", false, false)
725 INITIALIZE_PASS_END(ObjCARCContractLegacyPass, "objc-arc-contract",
726  "ObjC ARC contraction", false, false)
727 
728 void ObjCARCContractLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
729  AU.addRequired<AAResultsWrapperPass>();
730  AU.addRequired<DominatorTreeWrapperPass>();
731 }
732 
734  return new ObjCARCContractLegacyPass();
735 }
736 
738  ObjCARCContract OCARCC;
739  OCARCC.init(*F.getParent());
740  auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
741  auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
742  return OCARCC.run(F, AA, DT);
743 }
744 
747  ObjCARCContract OCAC;
748  OCAC.init(*F.getParent());
749 
750  bool Changed = OCAC.run(F, &AM.getResult<AAManager>(F),
752  bool CFGChanged = OCAC.hasCFGChanged();
753  if (Changed) {
755  if (!CFGChanged)
756  PA.preserveSet<CFGAnalyses>();
757  return PA;
758  }
759  return PreservedAnalyses::all();
760 }
llvm::objcarc::BundledRetainClaimRVs
Definition: ObjCARC.h:105
llvm::objcarc::GetBasicARCInstKind
ARCInstKind GetBasicARCInstKind(const Value *V)
Determine which objc runtime call instruction class V belongs to.
Definition: ObjCARCInstKind.h:104
i
i
Definition: README.txt:29
llvm::PreservedAnalyses
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
llvm::objcarc::ARCInstKind::User
@ User
could "use" a pointer
llvm::AAManager
A manager for alias analyses.
Definition: AliasAnalysis.h:1299
llvm::objcarc::CanUse
bool CanUse(const Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Test whether the given instruction can "use" the given pointer's object in a way that requires the re...
Definition: DependencyAnalysis.cpp:80
llvm::MemoryLocation::get
static MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
Definition: MemoryLocation.cpp:35
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::objcarc::hasAttachedCallOpBundle
bool hasAttachedCallOpBundle(const CallBase *CB)
Definition: ObjCARCUtil.h:29
llvm::objcarc::ARCRuntimeEntryPointKind::RetainAutoreleaseRV
@ RetainAutoreleaseRV
llvm::objcarc::ARCRuntimeEntryPointKind::StoreStrong
@ StoreStrong
llvm::CallInst::setTailCall
void setTailCall(bool IsTc=true)
Definition: Instructions.h:1681
contract
objc arc contract
Definition: ObjCARCContract.cpp:725
llvm::BasicBlock::iterator
InstListType::iterator iterator
Instruction iterators...
Definition: BasicBlock.h:87
llvm::AnalysisManager::getResult
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:780
llvm::MemoryLocation::Ptr
const Value * Ptr
The address of the start of the location.
Definition: MemoryLocation.h:218
InstIterator.h
llvm::Function
Definition: Function.h:60
arc
objc arc
Definition: ObjCARCOpts.cpp:610
llvm::BitCastInst
This class represents a no-op cast from one type to another.
Definition: Instructions.h:5225
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
Statistic.h
InlineAsm.h
llvm::PHINode::getOperandNumForIncomingValue
static unsigned getOperandNumForIncomingValue(unsigned i)
Definition: Instructions.h:2770
llvm::Use::get
Value * get() const
Definition: Use.h:66
llvm::objcarc::RetainAutoreleaseDep
@ RetainAutoreleaseDep
Blocks objc_retainAutorelease.
Definition: DependencyAnalysis.h:48
llvm::FunctionType::get
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:361
llvm::DominatorTree
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition: Dominators.h:166
llvm::objcarc::ARCRuntimeEntryPointKind::RetainRV
@ RetainRV
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
EHPersonalities.h
llvm::Use::getOperandNo
unsigned getOperandNo() const
Return the operand # of this use in its User.
Definition: Use.cpp:31
llvm::SPII::Load
@ Load
Definition: SparcInstrInfo.h:32
llvm::SmallPtrSet
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:450
Operator.h
llvm::BasicBlock::getSinglePredecessor
const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
Definition: BasicBlock.cpp:261
llvm::objcarc::ProvenanceAnalysis
This is similar to BasicAliasAnalysis, and it uses many of the same techniques, except it uses specia...
Definition: ProvenanceAnalysis.h:50
llvm::SmallVectorImpl::pop_back_val
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:654
findSafeStoreForStoreStrongContraction
static StoreInst * findSafeStoreForStoreStrongContraction(LoadInst *Load, Instruction *Release, ProvenanceAnalysis &PA, AAResults *AA)
Definition: ObjCARCContract.cpp:194
llvm::Type::getInt8Ty
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:237
llvm::objcarc::ARCInstKind::Autorelease
@ Autorelease
objc_autorelease
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
F
#define F(x, y, z)
Definition: MD5.cpp:55
llvm::RISCVFenceField::R
@ R
Definition: RISCVBaseInfo.h:240
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:55
AliasAnalysis.h
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
llvm::classifyEHPersonality
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
Definition: EHPersonalities.cpp:21
Arg
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
Definition: AMDGPULibCalls.cpp:186
CommandLine.h
llvm::Intrinsic::getType
FunctionType * getType(LLVMContext &Context, ID id, ArrayRef< Type * > Tys=None)
Return the function type for an intrinsic.
Definition: Function.cpp:1366
llvm::pdb::PDB_LocType::Null
@ Null
llvm::PassRegistry::getPassRegistry
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Definition: PassRegistry.cpp:31
llvm::initializeObjCARCContractLegacyPassPass
void initializeObjCARCContractLegacyPassPass(PassRegistry &)
llvm::Value::use_iterator
use_iterator_impl< Use > use_iterator
Definition: Value.h:353
llvm::AAResults
Definition: AliasAnalysis.h:511
llvm::objcarc::ARCInstKind::InitWeak
@ InitWeak
objc_initWeak (derived)
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::objcarc::GetArgRCIdentityRoot
Value * GetArgRCIdentityRoot(Value *Inst)
Assuming the given instruction is one of the special calls such as objc_retain or objc_release,...
Definition: ObjCARCAnalysisUtils.h:131
llvm::User
Definition: User.h:44
DependencyAnalysis.h
C
(vector float) vec_cmpeq(*A, *B) C
Definition: README_ALTIVEC.txt:86
llvm::ARM_PROC::A
@ A
Definition: ARMBaseInfo.h:34
findRetainForStoreStrongContraction
static Instruction * findRetainForStoreStrongContraction(Value *New, StoreInst *Store, Instruction *Release, ProvenanceAnalysis &PA)
Definition: ObjCARCContract.cpp:284
llvm::BasicBlock::begin
iterator begin()
Instruction iterator methods.
Definition: BasicBlock.h:297
llvm::AnalysisUsage
Represent the analysis usage information of a pass.
Definition: PassAnalysisSupport.h:47
llvm::objcarc::ARCInstKind::Release
@ Release
objc_release
llvm::objcarc::ARCInstKind::RetainRV
@ RetainRV
objc_retainAutoreleasedReturnValue
false
Definition: StackSlotColoring.cpp:141
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::objcarc::getEquivalentPHIs
void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList)
Return the list of PHI nodes that are equivalent to PN.
Definition: ObjCARC.h:74
llvm::Instruction
Definition: Instruction.h:42
llvm::SPII::Store
@ Store
Definition: SparcInstrInfo.h:33
llvm::DominatorTreeWrapperPass
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:302
llvm::STATISTIC
STATISTIC(NumFunctions, "Total number of functions")
llvm::objcarc::ARCInstKind::IntrinsicUser
@ IntrinsicUser
llvm.objc.clang.arc.use
llvm::Use::getUser
User * getUser() const
Returns the User that contains this Use.
Definition: Use.h:72
llvm::objcarc::DependenceKind
DependenceKind
Definition: DependencyAnalysis.h:44
llvm::BasicBlock::getFirstNonPHI
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
Definition: BasicBlock.cpp:209
llvm::MCID::Call
@ Call
Definition: MCInstrDesc.h:155
llvm::isModSet
LLVM_NODISCARD bool isModSet(const ModRefInfo MRI)
Definition: AliasAnalysis.h:196
llvm::InlineAsm::get
static InlineAsm * get(FunctionType *Ty, StringRef AsmString, StringRef Constraints, bool hasSideEffects, bool isAlignStack=false, AsmDialect asmDialect=AD_ATT, bool canThrow=false)
InlineAsm::get - Return the specified uniqued inline asm string.
Definition: InlineAsm.cpp:41
llvm::objcarc::ARCInstKind
ARCInstKind
Definition: ObjCARCInstKind.h:28
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
INITIALIZE_PASS_END
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:58
llvm::dxil::PointerTypeAnalysis::run
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
Definition: PointerTypeAnalysis.cpp:101
ARCRuntimeEntryPoints.h
llvm::PHINode::getIncomingValueNumForOperand
static unsigned getIncomingValueNumForOperand(unsigned i)
Definition: Instructions.h:2774
llvm::InlineAsm
Definition: InlineAsm.h:31
llvm::Use::set
void set(Value *Val)
Definition: Value.h:868
llvm::StoreInst
An instruction for storing to memory.
Definition: Instructions.h:305
llvm::Instruction::eraseFromParent
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:77
ProvenanceAnalysis.h
llvm::PointerType::getUnqual
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
Definition: DerivedTypes.h:651
llvm::colorEHFunclets
DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)
If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...
Definition: EHPersonalities.cpp:81
D
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
INITIALIZE_PASS_DEPENDENCY
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
llvm::objcarc::ARCInstKind::FusedRetainAutorelease
@ FusedRetainAutorelease
objc_retainAutorelease
llvm::ConstantPointerNull::get
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
Definition: Constants.cpp:1755
llvm::LLVMContext
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:68
llvm::numbers::e
constexpr double e
Definition: MathExtras.h:57
llvm::DenseMap
Definition: DenseMap.h:716
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::isScopedEHPersonality
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
Definition: EHPersonalities.h:79
llvm::cl::init
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:432
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
INITIALIZE_PASS_BEGIN
INITIALIZE_PASS_BEGIN(ObjCARCContractLegacyPass, "objc-arc-contract", "ObjC ARC contraction", false, false) INITIALIZE_PASS_END(ObjCARCContractLegacyPass
llvm::objcarc::EnableARCOpts
bool EnableARCOpts
A handy option to enable/disable all ARC Optimizations.
Definition: ObjCARCAnalysisUtils.cpp:23
llvm::objcarc::IsRetain
bool IsRetain(ARCInstKind Class)
Test if the given class is objc_retain or equivalent.
Definition: ObjCARCInstKind.cpp:344
llvm::objcarc
Definition: ObjCARCAliasAnalysis.h:29
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
llvm::objcarc::ARCRuntimeEntryPointKind::RetainAutorelease
@ RetainAutorelease
llvm::objcarc::IsNoopInstruction
bool IsNoopInstruction(const Instruction *I)
Definition: ObjCARCAnalysisUtils.h:139
llvm::objcarc::RetainAutoreleaseRVDep
@ RetainAutoreleaseRVDep
Blocks objc_retainAutoreleaseReturnValue.
Definition: DependencyAnalysis.h:49
llvm::CallBase::getIntrinsicID
Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
Definition: Instructions.cpp:311
llvm::objcarc::IsNullOrUndef
bool IsNullOrUndef(const Value *V)
Definition: ObjCARCAnalysisUtils.h:135
llvm::Value::getType
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
llvm::ObjCARCContractPass::run
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Definition: ObjCARCContract.cpp:745
llvm::CFGAnalyses
Represents analyses that only rely on functions' control flow.
Definition: PassManager.h:113
llvm::Value::replaceAllUsesWith
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:529
llvm::ms_demangle::IntrinsicFunctionKind::New
@ New
llvm::Value::getContext
LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:991
llvm::ilist_node_impl::getIterator
self_iterator getIterator()
Definition: ilist_node.h:82
LLVM_FALLTHROUGH
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
Definition: Compiler.h:280
llvm::LoadInst
An instruction for reading from memory.
Definition: Instructions.h:176
llvm::objcarc::GetRCIdentityRoot
const Value * GetRCIdentityRoot(const Value *V)
The RCIdentity root of a value V is a dominating value U for which retaining or releasing U is equiva...
Definition: ObjCARCAnalysisUtils.h:110
llvm::Value::stripPointerCasts
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition: Value.cpp:682
ObjCARCUtil.h
runOnFunction
static bool runOnFunction(Function &F, bool PostInlining)
Definition: EntryExitInstrumenter.cpp:69
llvm::objcarc::ARCRuntimeEntryPoints
Declarations for ObjC runtime functions and constants.
Definition: ARCRuntimeEntryPoints.h:52
llvm::PreservedAnalyses::all
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
llvm::objcarc::getRVInstMarker
static MDString * getRVInstMarker(Module &M)
Definition: ObjCARC.h:92
llvm::objcarc::ARCInstKind::FusedRetainAutoreleaseRV
@ FusedRetainAutoreleaseRV
objc_retainAutoreleaseReturnValue
llvm::inst_end
inst_iterator inst_end(Function *F)
Definition: InstIterator.h:132
contraction
objc arc ObjC ARC contraction
Definition: ObjCARCContract.cpp:726
PassManager.h
llvm::objcarc::findSingleDependency
llvm::Instruction * findSingleDependency(DependenceKind Flavor, const Value *Arg, BasicBlock *StartBB, Instruction *StartInst, ProvenanceAnalysis &PA)
Find dependent instructions.
Definition: DependencyAnalysis.cpp:258
llvm::objcarc::ARCInstKind::StoreStrong
@ StoreStrong
objc_storeStrong (derived)
llvm::objcarc::CanDecrementRefCount
bool CanDecrementRefCount(ARCInstKind Kind)
Returns false if conservatively we can prove that any instruction mapped to this kind can not decreme...
Definition: ObjCARCInstKind.cpp:667
llvm::tgtok::Class
@ Class
Definition: TGLexer.h:50
llvm::objcarc::EraseInstruction
static void EraseInstruction(Instruction *CI)
Erase the given instruction.
Definition: ObjCARC.h:39
AA
llvm::BasicBlock::back
const Instruction & back() const
Definition: BasicBlock.h:311
llvm::DominatorTreeAnalysis
Analysis pass which computes a DominatorTree.
Definition: Dominators.h:267
llvm::Type::getVoidTy
static Type * getVoidTy(LLVMContext &C)
Definition: Type.cpp:222
llvm::Pass
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:91
llvm::PreservedAnalyses::preserveSet
void preserveSet()
Mark an analysis set as preserved.
Definition: PassManager.h:188
ObjCARC.h
Dominators.h
llvm::CallBase::getArgOperand
Value * getArgOperand(unsigned i) const
Definition: InstrTypes.h:1341
llvm::AAResultsWrapperPass
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
Definition: AliasAnalysis.h:1347
llvm::Instruction::getParent
const BasicBlock * getParent() const
Definition: Instruction.h:91
llvm::objcarc::createCallInstWithColors
CallInst * createCallInstWithColors(FunctionCallee Func, ArrayRef< Value * > Args, const Twine &NameStr, Instruction *InsertBefore, const DenseMap< BasicBlock *, ColorVector > &BlockColors)
Create a call instruction with the correct funclet token.
Definition: ObjCARC.cpp:45
llvm::PHINode
Definition: Instructions.h:2664
llvm::BasicBlock::getTerminator
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Definition: BasicBlock.h:119
llvm::AnalysisManager
A container for analyses that lazily runs them and caches their results.
Definition: InstructionSimplify.h:42
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1474
llvm::InliningAdvisorMode::Release
@ Release
BB
Common register allocation spilling lr str ldr sxth r3 ldr mla r4 can lr mov lr str ldr sxth r3 mla r4 and then merge mul and lr str ldr sxth r3 mla r4 It also increase the likelihood the store may become dead bb27 Successors according to LLVM BB
Definition: README.txt:39
llvm::inst_begin
inst_iterator inst_begin(Function *F)
Definition: InstIterator.h:131
llvm::createObjCARCContractPass
Pass * createObjCARCContractPass()
Definition: ObjCARCContract.cpp:733
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:394
llvm::InstIterator
Definition: InstIterator.h:32
raw_ostream.h
llvm::MDString
A single uniqued string.
Definition: Metadata.h:612
InitializePasses.h
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::objcarc::ARCInstKind::Retain
@ Retain
objc_retain
Debug.h
llvm::Value::users
iterator_range< user_iterator > users()
Definition: Value.h:421
llvm::MemoryLocation
Representation for a specific memory location.
Definition: MemoryLocation.h:210
llvm::BasicBlock::const_iterator
InstListType::const_iterator const_iterator
Definition: BasicBlock.h:88
llvm::Use
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
llvm::objcarc::ARCInstKind::UnsafeClaimRV
@ UnsafeClaimRV
objc_unsafeClaimAutoreleasedReturnValue
llvm::objcarc::ARCInstKind::AutoreleaseRV
@ AutoreleaseRV
objc_autoreleaseReturnValue
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37