Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[ObjCARC Annotations] Implemented ARC annotation metadata to expose t…

…he ARC data flow analysis state in the IR via metadata.

Previously the inner works of the data flow analysis in ObjCARCOpts was hard to
get out of the optimizer for analysis of bugs or testing. All of the current ARC
unit tests are based off of testing the effect of the data flow
analysis (i.e. what statements are removed or moved, etc.). This creates
weakness in the current unit testing regimem since we are not actually testing
what effects various instructions have on the modeled pointer state.
Additionally in order to analyze a bug in the optimizer, one would need to track
by hand what the optimizer was actually doing either through use of DEBUG
statements or through the usage of a debugger, both yielding large loses in
developer productivity.

This patch deals with these two issues by providing ARC annotation
metadata that annotates instructions with the state changes that they cause in
various pointers as well as provides metadata to annotate provenance sources.

Specifically, we introduce the following metadata types:

1. llvm.arc.annotation.bottomup.
2. llvm.arc.annotation.topdown.
3. llvm.arc.annotation.provenancesource.

llvm.arc.annotation.{bottomup,topdown}: These annotations describes a state
change in a pointer when we are visiting instructions bottomup/topdown
respectively. The output format for both is the same:

  !1 = metadata !{metadata !"(test,%x)", metadata !"S_Release", metadata !"S_Use"}

The first element is a string tuple with the following format:

  (function,variable name)

The second two elements of the metadata show the previous state of the
pointer (in this case S_Release) and the new state of the pointer (S_Use). We
write the metadata in such a manner to ensure that it is easy for outside tools
to parse. This is important since I am currently working on a tool for taking
this information and pretty printing it besides the IR and that can be used for
LIT style testing via the generation of an index.

llvm.arc.annotation.provenancesource: This metadata is used to annotate
instructions which act as provenance sources, i.e. ones that introduce a
new (from the optimizer's perspective) non-argument pointer to track. This
enables cross-referencing in between provenance sources and the state changes
that occur to them.

This is still a work in progress. Additionally I plan on committing
later today additions to the annotations that annotate at the top/bottom
of basic blocks the state of the various pointers being tracked.

*NOTE* The metadata support is conditionally compiled into libObjCARCOpts only
when we are producing a debug build of llvm/clang and even so are
disabled by default. To enable the annotation metadata, pass in
-enable-objc-arc-annotations to opt.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@177951 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information...
commit 7bef073622b95116598f16630c0a9a3265a743a8 1 parent 872b4e5
Michael Gottesman authored

Showing 1 changed file with 186 additions and 5 deletions. Show diff stats Hide diff stats

  1. +186 5 lib/Transforms/ObjCARC/ObjCARCOpts.cpp
191 lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -701,6 +701,151 @@ void BBState::MergeSucc(const BBState &Other) {
701 701 MI->second.Merge(PtrState(), /*TopDown=*/false);
702 702 }
703 703
  704 +// Only enable ARC Annotations if we are building a debug version of
  705 +// libObjCARCOpts.
  706 +#ifndef NDEBUG
  707 +#define ARC_ANNOTATIONS
  708 +#endif
  709 +
  710 +// Define some macros along the lines of DEBUG and some helper functions to make
  711 +// it cleaner to create annotations in the source code and to no-op when not
  712 +// building in debug mode.
  713 +#ifdef ARC_ANNOTATIONS
  714 +
  715 +#include "llvm/Support/CommandLine.h"
  716 +
  717 +/// Enable/disable ARC sequence annotations.
  718 +static cl::opt<bool>
  719 +EnableARCAnnotations("enable-objc-arc-annotations", cl::init(false));
  720 +
  721 +/// This function appends a unique ARCAnnotationProvenanceSourceMDKind id to an
  722 +/// instruction so that we can track backwards when post processing via the llvm
  723 +/// arc annotation processor tool. If the function is an
  724 +static MDString *AppendMDNodeToSourcePtr(unsigned NodeId,
  725 + Value *Ptr) {
  726 + MDString *Hash = 0;
  727 +
  728 + // If pointer is a result of an instruction and it does not have a source
  729 + // MDNode it, attach a new MDNode onto it. If pointer is a result of
  730 + // an instruction and does have a source MDNode attached to it, return a
  731 + // reference to said Node. Otherwise just return 0.
  732 + if (Instruction *Inst = dyn_cast<Instruction>(Ptr)) {
  733 + MDNode *Node;
  734 + if (!(Node = Inst->getMetadata(NodeId))) {
  735 + // We do not have any node. Generate and attatch the hash MDString to the
  736 + // instruction.
  737 +
  738 + // We just use an MDString to ensure that this metadata gets written out
  739 + // of line at the module level and to provide a very simple format
  740 + // encoding the information herein. Both of these makes it simpler to
  741 + // parse the annotations by a simple external program.
  742 + std::string Str;
  743 + raw_string_ostream os(Str);
  744 + os << "(" << Inst->getParent()->getParent()->getName() << ",%"
  745 + << Inst->getName() << ")";
  746 +
  747 + Hash = MDString::get(Inst->getContext(), os.str());
  748 + Inst->setMetadata(NodeId, MDNode::get(Inst->getContext(),Hash));
  749 + } else {
  750 + // We have a node. Grab its hash and return it.
  751 + assert(Node->getNumOperands() == 1 &&
  752 + "An ARCAnnotationProvenanceSourceMDKind can only have 1 operand.");
  753 + Hash = cast<MDString>(Node->getOperand(0));
  754 + }
  755 + } else if (Argument *Arg = dyn_cast<Argument>(Ptr)) {
  756 + std::string str;
  757 + raw_string_ostream os(str);
  758 + os << "(" << Arg->getParent()->getName() << ",%" << Arg->getName()
  759 + << ")";
  760 + Hash = MDString::get(Arg->getContext(), os.str());
  761 + }
  762 +
  763 + return Hash;
  764 +}
  765 +
  766 +/// Helper function to change a Sequence into a String object using our overload
  767 +/// for raw_ostream so we only have printing code in one location.
  768 +static MDString *SequenceToMDString(LLVMContext &Context,
  769 + Sequence A) {
  770 + std::string str;
  771 + raw_string_ostream os(str);
  772 + os << A;
  773 + return MDString::get(Context, os.str());
  774 +}
  775 +
  776 +/// A simple function to generate a MDNode which describes the change in state
  777 +/// for Value *Ptr caused by Instruction *Inst.
  778 +static void AppendMDNodeToInstForPtr(unsigned NodeId,
  779 + Instruction *Inst,
  780 + Value *Ptr,
  781 + MDString *PtrSourceMDNodeID,
  782 + Sequence OldSeq,
  783 + Sequence NewSeq) {
  784 + MDNode *Node = 0;
  785 + Value *tmp[3] = {PtrSourceMDNodeID,
  786 + SequenceToMDString(Inst->getContext(),
  787 + OldSeq),
  788 + SequenceToMDString(Inst->getContext(),
  789 + NewSeq)};
  790 + Node = MDNode::get(Inst->getContext(),
  791 + ArrayRef<Value*>(tmp, 3));
  792 +
  793 + Inst->setMetadata(NodeId, Node);
  794 +}
  795 +
  796 +/// Adds a source annotation to pointer and a state change annotation to Inst
  797 +/// referencing the source annotation and the old/new state of pointer.
  798 +static void GenerateARCAnnotation(unsigned InstMDId,
  799 + unsigned PtrMDId,
  800 + Instruction *Inst,
  801 + Value *Ptr,
  802 + Sequence OldSeq,
  803 + Sequence NewSeq) {
  804 + if (EnableARCAnnotations) {
  805 + // First generate the source annotation on our pointer. This will return an
  806 + // MDString* if Ptr actually comes from an instruction implying we can put
  807 + // in a source annotation. If AppendMDNodeToSourcePtr returns 0 (i.e. NULL),
  808 + // then we know that our pointer is from an Argument so we put a reference
  809 + // to the argument number.
  810 + //
  811 + // The point of this is to make it easy for the
  812 + // llvm-arc-annotation-processor tool to cross reference where the source
  813 + // pointer is in the LLVM IR since the LLVM IR parser does not submit such
  814 + // information via debug info for backends to use (since why would anyone
  815 + // need such a thing from LLVM IR besides in non standard cases
  816 + // [i.e. this]).
  817 + MDString *SourcePtrMDNode =
  818 + AppendMDNodeToSourcePtr(PtrMDId, Ptr);
  819 + AppendMDNodeToInstForPtr(InstMDId, Inst, Ptr, SourcePtrMDNode, OldSeq,
  820 + NewSeq);
  821 + }
  822 +}
  823 +
  824 +// The actual interface for accessing the above functionality is defined via
  825 +// some simple macros which are defined below. We do this so that the user does
  826 +// not need to pass in what metadata id is needed resulting in cleaner code and
  827 +// additionally since it provides an easy way to conditionally no-op all
  828 +// annotation support in a non-debug build.
  829 +
  830 +/// Use this macro to annotate a sequence state change when processing
  831 +/// instructions bottom up,
  832 +#define ANNOTATE_BOTTOMUP(inst, ptr, old, new) \
  833 + GenerateARCAnnotation(ARCAnnotationBottomUpMDKind, \
  834 + ARCAnnotationProvenanceSourceMDKind, (inst), \
  835 + const_cast<Value*>(ptr), (old), (new))
  836 +/// Use this macro to annotate a sequence state change when processing
  837 +/// instructions top down.
  838 +#define ANNOTATE_TOPDOWN(inst, ptr, old, new) \
  839 + GenerateARCAnnotation(ARCAnnotationTopDownMDKind, \
  840 + ARCAnnotationProvenanceSourceMDKind, (inst), \
  841 + const_cast<Value*>(ptr), (old), (new))
  842 +
  843 +#else // !ARC_ANNOTATION
  844 +// If annotations are off, noop.
  845 +#define ANNOTATE_BOTTOMUP(inst, ptr, old, new)
  846 +#define ANNOTATE_TOPDOWN(inst, ptr, old, new)
  847 +#endif // !ARC_ANNOTATION
  848 +
704 849 namespace {
705 850 /// \brief The main ARC optimization pass.
706 851 class ObjCARCOpt : public FunctionPass {
@@ -741,6 +886,15 @@ namespace {
741 886 /// The Metadata Kind for clang.arc.no_objc_arc_exceptions metadata.
742 887 unsigned NoObjCARCExceptionsMDKind;
743 888
  889 +#ifdef ARC_ANNOTATIONS
  890 + /// The Metadata Kind for llvm.arc.annotation.bottomup metadata.
  891 + unsigned ARCAnnotationBottomUpMDKind;
  892 + /// The Metadata Kind for llvm.arc.annotation.topdown metadata.
  893 + unsigned ARCAnnotationTopDownMDKind;
  894 + /// The Metadata Kind for llvm.arc.annotation.provenancesource metadata.
  895 + unsigned ARCAnnotationProvenanceSourceMDKind;
  896 +#endif // ARC_ANNOATIONS
  897 +
744 898 Constant *getRetainRVCallee(Module *M);
745 899 Constant *getAutoreleaseRVCallee(Module *M);
746 900 Constant *getReleaseCallee(Module *M);
@@ -1505,12 +1659,13 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
1505 1659 }
1506 1660
1507 1661 MDNode *ReleaseMetadata = Inst->getMetadata(ImpreciseReleaseMDKind);
1508   - S.ResetSequenceProgress(ReleaseMetadata ? S_MovableRelease : S_Release);
  1662 + Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
  1663 + ANNOTATE_BOTTOMUP(Inst, Arg, S.GetSeq(), NewSeq);
  1664 + S.ResetSequenceProgress(NewSeq);
1509 1665 S.RRI.ReleaseMetadata = ReleaseMetadata;
1510 1666 S.RRI.KnownSafe = S.HasKnownPositiveRefCount();
1511 1667 S.RRI.IsTailCallRelease = cast<CallInst>(Inst)->isTailCall();
1512 1668 S.RRI.Calls.insert(Inst);
1513   -
1514 1669 S.SetKnownPositiveRefCount();
1515 1670 break;
1516 1671 }
@@ -1527,7 +1682,8 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
1527 1682 PtrState &S = MyStates.getPtrBottomUpState(Arg);
1528 1683 S.SetKnownPositiveRefCount();
1529 1684
1530   - switch (S.GetSeq()) {
  1685 + Sequence OldSeq = S.GetSeq();
  1686 + switch (OldSeq) {
1531 1687 case S_Stop:
1532 1688 case S_Release:
1533 1689 case S_MovableRelease:
@@ -1548,6 +1704,7 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
1548 1704 case S_Retain:
1549 1705 llvm_unreachable("bottom-up pointer in retain state!");
1550 1706 }
  1707 + ANNOTATE_BOTTOMUP(Inst, Arg, OldSeq, S.GetSeq());
1551 1708 return NestingDetected;
1552 1709 }
1553 1710 case IC_AutoreleasepoolPop:
@@ -1578,6 +1735,7 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
1578 1735 switch (Seq) {
1579 1736 case S_Use:
1580 1737 S.SetSeq(S_CanRelease);
  1738 + ANNOTATE_BOTTOMUP(Inst, Ptr, Seq, S.GetSeq());
1581 1739 continue;
1582 1740 case S_CanRelease:
1583 1741 case S_Release:
@@ -1604,9 +1762,11 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
1604 1762 else
1605 1763 S.RRI.ReverseInsertPts.insert(llvm::next(BasicBlock::iterator(Inst)));
1606 1764 S.SetSeq(S_Use);
  1765 + ANNOTATE_BOTTOMUP(Inst, Ptr, Seq, S_Use);
1607 1766 } else if (Seq == S_Release && IsUser(Class)) {
1608 1767 // Non-movable releases depend on any possible objc pointer use.
1609 1768 S.SetSeq(S_Stop);
  1769 + ANNOTATE_BOTTOMUP(Inst, Ptr, S_Release, S_Stop);
1610 1770 assert(S.RRI.ReverseInsertPts.empty());
1611 1771 // As above; handle invoke specially.
1612 1772 if (isa<InvokeInst>(Inst))
@@ -1616,8 +1776,10 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst,
1616 1776 }
1617 1777 break;
1618 1778 case S_Stop:
1619   - if (CanUse(Inst, Ptr, PA, Class))
  1779 + if (CanUse(Inst, Ptr, PA, Class)) {
1620 1780 S.SetSeq(S_Use);
  1781 + ANNOTATE_BOTTOMUP(Inst, Ptr, Seq, S_Use);
  1782 + }
1621 1783 break;
1622 1784 case S_CanRelease:
1623 1785 case S_Use:
@@ -1716,6 +1878,7 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
1716 1878 if (S.GetSeq() == S_Retain)
1717 1879 NestingDetected = true;
1718 1880
  1881 + ANNOTATE_TOPDOWN(Inst, Arg, S.GetSeq(), S_Retain);
1719 1882 S.ResetSequenceProgress(S_Retain);
1720 1883 S.RRI.IsRetainBlock = Class == IC_RetainBlock;
1721 1884 S.RRI.KnownSafe = S.HasKnownPositiveRefCount();
@@ -1743,6 +1906,7 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
1743 1906 S.RRI.ReleaseMetadata = Inst->getMetadata(ImpreciseReleaseMDKind);
1744 1907 S.RRI.IsTailCallRelease = cast<CallInst>(Inst)->isTailCall();
1745 1908 Releases[Inst] = S.RRI;
  1909 + ANNOTATE_TOPDOWN(Inst, Arg, S.GetSeq(), S_None);
1746 1910 S.ClearSequenceProgress();
1747 1911 break;
1748 1912 case S_None:
@@ -1782,6 +1946,7 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
1782 1946 switch (Seq) {
1783 1947 case S_Retain:
1784 1948 S.SetSeq(S_CanRelease);
  1949 + ANNOTATE_TOPDOWN(Inst, Ptr, Seq, S_CanRelease);
1785 1950 assert(S.RRI.ReverseInsertPts.empty());
1786 1951 S.RRI.ReverseInsertPts.insert(Inst);
1787 1952
@@ -1803,8 +1968,10 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
1803 1968 // Check for possible direct uses.
1804 1969 switch (Seq) {
1805 1970 case S_CanRelease:
1806   - if (CanUse(Inst, Ptr, PA, Class))
  1971 + if (CanUse(Inst, Ptr, PA, Class)) {
1807 1972 S.SetSeq(S_Use);
  1973 + ANNOTATE_TOPDOWN(Inst, Ptr, Seq, S_Use);
  1974 + }
1808 1975 break;
1809 1976 case S_Retain:
1810 1977 case S_Use:
@@ -2273,6 +2440,12 @@ ObjCARCOpt::PerformCodePlacement(DenseMap<const BasicBlock *, BBState>
2273 2440 ReleasesToMove, Arg, KnownSafe,
2274 2441 AnyPairsCompletelyEliminated);
2275 2442
  2443 +#ifdef ARC_ANNOTATIONS
  2444 + // Do not move calls if ARC annotations are requested. If we were to move
  2445 + // calls in this case, we would not be able
  2446 + PerformMoveCalls = PerformMoveCalls && !EnableARCAnnotations;
  2447 +#endif // ARC_ANNOTATIONS
  2448 +
2276 2449 if (PerformMoveCalls) {
2277 2450 // Ok, everything checks out and we're all set. Let's move/delete some
2278 2451 // code!
@@ -2620,6 +2793,14 @@ bool ObjCARCOpt::doInitialization(Module &M) {
2620 2793 M.getContext().getMDKindID("clang.arc.copy_on_escape");
2621 2794 NoObjCARCExceptionsMDKind =
2622 2795 M.getContext().getMDKindID("clang.arc.no_objc_arc_exceptions");
  2796 +#ifdef ARC_ANNOTATIONS
  2797 + ARCAnnotationBottomUpMDKind =
  2798 + M.getContext().getMDKindID("llvm.arc.annotation.bottomup");
  2799 + ARCAnnotationTopDownMDKind =
  2800 + M.getContext().getMDKindID("llvm.arc.annotation.topdown");
  2801 + ARCAnnotationProvenanceSourceMDKind =
  2802 + M.getContext().getMDKindID("llvm.arc.annotation.provenancesource");
  2803 +#endif // ARC_ANNOTATIONS
2623 2804
2624 2805 // Intuitively, objc_retain and others are nocapture, however in practice
2625 2806 // they are not, because they return their argument value. And objc_release

0 comments on commit 7bef073

Please sign in to comment.
Something went wrong with that request. Please try again.