[objc-arc] Remove annotations code.

It will always be in the history if it is needed again. Now it is just dead
code.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231435 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael Gottesman 2015-03-06 00:34:29 +00:00
parent 368d2e9976
commit 0d7cce41ff
2 changed files with 0 additions and 410 deletions

View File

@ -401,282 +401,6 @@ void BBState::MergeSucc(const BBState &Other) {
MI->second.Merge(PtrState(), /*TopDown=*/false);
}
// Only enable ARC Annotations if we are building a debug version of
// libObjCARCOpts.
#ifndef NDEBUG
#define ARC_ANNOTATIONS
#endif
// Define some macros along the lines of DEBUG and some helper functions to make
// it cleaner to create annotations in the source code and to no-op when not
// building in debug mode.
#ifdef ARC_ANNOTATIONS
#include "llvm/Support/CommandLine.h"
/// Enable/disable ARC sequence annotations.
static cl::opt<bool>
EnableARCAnnotations("enable-objc-arc-annotations", cl::init(false),
cl::desc("Enable emission of arc data flow analysis "
"annotations"));
static cl::opt<bool>
DisableCheckForCFGHazards("disable-objc-arc-checkforcfghazards", cl::init(false),
cl::desc("Disable check for cfg hazards when "
"annotating"));
static cl::opt<std::string>
ARCAnnotationTargetIdentifier("objc-arc-annotation-target-identifier",
cl::init(""),
cl::desc("filter out all data flow annotations "
"but those that apply to the given "
"target llvm identifier."));
/// This function appends a unique ARCAnnotationProvenanceSourceMDKind id to an
/// instruction so that we can track backwards when post processing via the llvm
/// arc annotation processor tool. If the function is an
static MDString *AppendMDNodeToSourcePtr(unsigned NodeId,
Value *Ptr) {
MDString *Hash = nullptr;
// If pointer is a result of an instruction and it does not have a source
// MDNode it, attach a new MDNode onto it. If pointer is a result of
// an instruction and does have a source MDNode attached to it, return a
// reference to said Node. Otherwise just return 0.
if (auto *Inst = dyn_cast<Instruction>(Ptr)) {
MDNode *Node;
if (!(Node = Inst->getMetadata(NodeId))) {
// We do not have any node. Generate and attatch the hash MDString to the
// instruction.
// We just use an MDString to ensure that this metadata gets written out
// of line at the module level and to provide a very simple format
// encoding the information herein. Both of these makes it simpler to
// parse the annotations by a simple external program.
std::string Str;
raw_string_ostream os(Str);
os << "(" << Inst->getParent()->getParent()->getName() << ",%"
<< Inst->getName() << ")";
Hash = MDString::get(Inst->getContext(), os.str());
Inst->setMetadata(NodeId, MDNode::get(Inst->getContext(),Hash));
} else {
// We have a node. Grab its hash and return it.
assert(Node->getNumOperands() == 1 &&
"An ARCAnnotationProvenanceSourceMDKind can only have 1 operand.");
Hash = cast<MDString>(Node->getOperand(0));
}
} else if (auto *Arg = dyn_cast<Argument>(Ptr)) {
std::string str;
raw_string_ostream os(str);
os << "(" << Arg->getParent()->getName() << ",%" << Arg->getName()
<< ")";
Hash = MDString::get(Arg->getContext(), os.str());
}
return Hash;
}
static std::string SequenceToString(Sequence A) {
std::string str;
raw_string_ostream os(str);
os << A;
return os.str();
}
/// Helper function to change a Sequence into a String object using our overload
/// for raw_ostream so we only have printing code in one location.
static MDString *SequenceToMDString(LLVMContext &Context,
Sequence A) {
return MDString::get(Context, SequenceToString(A));
}
/// A simple function to generate a MDNode which describes the change in state
/// for Value *Ptr caused by Instruction *Inst.
static void AppendMDNodeToInstForPtr(unsigned NodeId,
Instruction *Inst,
Value *Ptr,
MDString *PtrSourceMDNodeID,
Sequence OldSeq,
Sequence NewSeq) {
MDNode *Node = nullptr;
Metadata *tmp[3] = {PtrSourceMDNodeID,
SequenceToMDString(Inst->getContext(), OldSeq),
SequenceToMDString(Inst->getContext(), NewSeq)};
Node = MDNode::get(Inst->getContext(), tmp);
Inst->setMetadata(NodeId, Node);
}
/// Add to the beginning of the basic block llvm.ptr.annotations which show the
/// state of a pointer at the entrance to a basic block.
static void GenerateARCBBEntranceAnnotation(const char *Name, BasicBlock *BB,
Value *Ptr, Sequence Seq) {
// If we have a target identifier, make sure that we match it before
// continuing.
if(!ARCAnnotationTargetIdentifier.empty() &&
!Ptr->getName().equals(ARCAnnotationTargetIdentifier))
return;
Module *M = BB->getParent()->getParent();
LLVMContext &C = M->getContext();
Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
Type *I8XX = PointerType::getUnqual(I8X);
Type *Params[] = {I8XX, I8XX};
FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), Params,
/*isVarArg=*/false);
Constant *Callee = M->getOrInsertFunction(Name, FTy);
IRBuilder<> Builder(BB, BB->getFirstInsertionPt());
Value *PtrName;
StringRef Tmp = Ptr->getName();
if (nullptr == (PtrName = M->getGlobalVariable(Tmp, true))) {
Value *ActualPtrName = Builder.CreateGlobalStringPtr(Tmp,
Tmp + "_STR");
PtrName = new GlobalVariable(*M, I8X, true, GlobalVariable::InternalLinkage,
cast<Constant>(ActualPtrName), Tmp);
}
Value *S;
std::string SeqStr = SequenceToString(Seq);
if (nullptr == (S = M->getGlobalVariable(SeqStr, true))) {
Value *ActualPtrName = Builder.CreateGlobalStringPtr(SeqStr,
SeqStr + "_STR");
S = new GlobalVariable(*M, I8X, true, GlobalVariable::InternalLinkage,
cast<Constant>(ActualPtrName), SeqStr);
}
Builder.CreateCall2(Callee, PtrName, S);
}
/// Add to the end of the basic block llvm.ptr.annotations which show the state
/// of the pointer at the bottom of the basic block.
static void GenerateARCBBTerminatorAnnotation(const char *Name, BasicBlock *BB,
Value *Ptr, Sequence Seq) {
// If we have a target identifier, make sure that we match it before emitting
// an annotation.
if(!ARCAnnotationTargetIdentifier.empty() &&
!Ptr->getName().equals(ARCAnnotationTargetIdentifier))
return;
Module *M = BB->getParent()->getParent();
LLVMContext &C = M->getContext();
Type *I8X = PointerType::getUnqual(Type::getInt8Ty(C));
Type *I8XX = PointerType::getUnqual(I8X);
Type *Params[] = {I8XX, I8XX};
FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), Params,
/*isVarArg=*/false);
Constant *Callee = M->getOrInsertFunction(Name, FTy);
IRBuilder<> Builder(BB, std::prev(BB->end()));
Value *PtrName;
StringRef Tmp = Ptr->getName();
if (nullptr == (PtrName = M->getGlobalVariable(Tmp, true))) {
Value *ActualPtrName = Builder.CreateGlobalStringPtr(Tmp,
Tmp + "_STR");
PtrName = new GlobalVariable(*M, I8X, true, GlobalVariable::InternalLinkage,
cast<Constant>(ActualPtrName), Tmp);
}
Value *S;
std::string SeqStr = SequenceToString(Seq);
if (nullptr == (S = M->getGlobalVariable(SeqStr, true))) {
Value *ActualPtrName = Builder.CreateGlobalStringPtr(SeqStr,
SeqStr + "_STR");
S = new GlobalVariable(*M, I8X, true, GlobalVariable::InternalLinkage,
cast<Constant>(ActualPtrName), SeqStr);
}
Builder.CreateCall2(Callee, PtrName, S);
}
/// Adds a source annotation to pointer and a state change annotation to Inst
/// referencing the source annotation and the old/new state of pointer.
static void GenerateARCAnnotation(unsigned InstMDId,
unsigned PtrMDId,
Instruction *Inst,
Value *Ptr,
Sequence OldSeq,
Sequence NewSeq) {
if (EnableARCAnnotations) {
// If we have a target identifier, make sure that we match it before
// emitting an annotation.
if(!ARCAnnotationTargetIdentifier.empty() &&
!Ptr->getName().equals(ARCAnnotationTargetIdentifier))
return;
// First generate the source annotation on our pointer. This will return an
// MDString* if Ptr actually comes from an instruction implying we can put
// in a source annotation. If AppendMDNodeToSourcePtr returns 0 (i.e. NULL),
// then we know that our pointer is from an Argument so we put a reference
// to the argument number.
//
// The point of this is to make it easy for the
// llvm-arc-annotation-processor tool to cross reference where the source
// pointer is in the LLVM IR since the LLVM IR parser does not submit such
// information via debug info for backends to use (since why would anyone
// need such a thing from LLVM IR besides in non-standard cases
// [i.e. this]).
MDString *SourcePtrMDNode =
AppendMDNodeToSourcePtr(PtrMDId, Ptr);
AppendMDNodeToInstForPtr(InstMDId, Inst, Ptr, SourcePtrMDNode, OldSeq,
NewSeq);
}
}
// The actual interface for accessing the above functionality is defined via
// some simple macros which are defined below. We do this so that the user does
// not need to pass in what metadata id is needed resulting in cleaner code and
// additionally since it provides an easy way to conditionally no-op all
// annotation support in a non-debug build.
/// Use this macro to annotate a sequence state change when processing
/// instructions bottom up,
#define ANNOTATE_BOTTOMUP(inst, ptr, old, new) \
GenerateARCAnnotation(ARCAnnotationBottomUpMDKind, \
ARCAnnotationProvenanceSourceMDKind, (inst), \
const_cast<Value*>(ptr), (old), (new))
/// Use this macro to annotate a sequence state change when processing
/// instructions top down.
#define ANNOTATE_TOPDOWN(inst, ptr, old, new) \
GenerateARCAnnotation(ARCAnnotationTopDownMDKind, \
ARCAnnotationProvenanceSourceMDKind, (inst), \
const_cast<Value*>(ptr), (old), (new))
#define ANNOTATE_BB(_states, _bb, _name, _type, _direction) \
do { \
if (EnableARCAnnotations) { \
for(BBState::ptr_const_iterator I = (_states)._direction##_ptr_begin(), \
E = (_states)._direction##_ptr_end(); I != E; ++I) { \
Value *Ptr = const_cast<Value*>(I->first); \
Sequence Seq = I->second.GetSeq(); \
GenerateARCBB ## _type ## Annotation(_name, (_bb), Ptr, Seq); \
} \
} \
} while (0)
#define ANNOTATE_BOTTOMUP_BBSTART(_states, _basicblock) \
ANNOTATE_BB(_states, _basicblock, "llvm.arc.annotation.bottomup.bbstart", \
Entrance, bottom_up)
#define ANNOTATE_BOTTOMUP_BBEND(_states, _basicblock) \
ANNOTATE_BB(_states, _basicblock, "llvm.arc.annotation.bottomup.bbend", \
Terminator, bottom_up)
#define ANNOTATE_TOPDOWN_BBSTART(_states, _basicblock) \
ANNOTATE_BB(_states, _basicblock, "llvm.arc.annotation.topdown.bbstart", \
Entrance, top_down)
#define ANNOTATE_TOPDOWN_BBEND(_states, _basicblock) \
ANNOTATE_BB(_states, _basicblock, "llvm.arc.annotation.topdown.bbend", \
Terminator, top_down)
#else // !ARC_ANNOTATION
// If annotations are off, noop.
#define ANNOTATE_BOTTOMUP(inst, ptr, old, new)
#define ANNOTATE_TOPDOWN(inst, ptr, old, new)
#define ANNOTATE_BOTTOMUP_BBSTART(states, basicblock)
#define ANNOTATE_BOTTOMUP_BBEND(states, basicblock)
#define ANNOTATE_TOPDOWN_BBSTART(states, basicblock)
#define ANNOTATE_TOPDOWN_BBEND(states, basicblock)
#endif // !ARC_ANNOTATION
namespace {
/// \brief The main ARC optimization pass.
class ObjCARCOpt : public FunctionPass {
@ -703,14 +427,6 @@ namespace {
/// The Metadata Kind for clang.arc.no_objc_arc_exceptions metadata.
unsigned NoObjCARCExceptionsMDKind;
#ifdef ARC_ANNOTATIONS
/// The Metadata Kind for llvm.arc.annotation.bottomup metadata.
unsigned ARCAnnotationBottomUpMDKind;
/// The Metadata Kind for llvm.arc.annotation.topdown metadata.
unsigned ARCAnnotationTopDownMDKind;
/// The Metadata Kind for llvm.arc.annotation.provenancesource metadata.
unsigned ARCAnnotationProvenanceSourceMDKind;
#endif // ARC_ANNOATIONS
bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV);
void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
@ -1345,7 +1061,6 @@ bool ObjCARCOpt::VisitInstructionBottomUp(
MDNode *ReleaseMetadata = Inst->getMetadata(ImpreciseReleaseMDKind);
Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
ANNOTATE_BOTTOMUP(Inst, Arg, S.GetSeq(), NewSeq);
S.ResetSequenceProgress(NewSeq);
S.SetReleaseMetadata(ReleaseMetadata);
S.SetKnownSafe(S.HasKnownPositiveRefCount());
@ -1390,7 +1105,6 @@ bool ObjCARCOpt::VisitInstructionBottomUp(
case S_Retain:
llvm_unreachable("bottom-up pointer in retain state!");
}
ANNOTATE_BOTTOMUP(Inst, Arg, OldSeq, S.GetSeq());
// A retain moving bottom up can be a use.
break;
}
@ -1446,7 +1160,6 @@ bool ObjCARCOpt::VisitInstructionBottomUp(
switch (Seq) {
case S_Use:
S.SetSeq(S_CanRelease);
ANNOTATE_BOTTOMUP(Inst, Ptr, Seq, S.GetSeq());
continue;
case S_CanRelease:
case S_Release:
@ -1475,13 +1188,11 @@ bool ObjCARCOpt::VisitInstructionBottomUp(
else
S.InsertReverseInsertPt(std::next(BasicBlock::iterator(Inst)));
S.SetSeq(S_Use);
ANNOTATE_BOTTOMUP(Inst, Ptr, Seq, S_Use);
} else if (Seq == S_Release && IsUser(Class)) {
DEBUG(dbgs() << "PreciseReleaseUse: Seq: " << Seq << "; " << *Ptr
<< "\n");
// Non-movable releases depend on any possible objc pointer use.
S.SetSeq(S_Stop);
ANNOTATE_BOTTOMUP(Inst, Ptr, S_Release, S_Stop);
assert(!S.HasReverseInsertPts());
// As above; handle invoke specially.
if (isa<InvokeInst>(Inst))
@ -1495,7 +1206,6 @@ bool ObjCARCOpt::VisitInstructionBottomUp(
DEBUG(dbgs() << "PreciseStopUse: Seq: " << Seq << "; " << *Ptr
<< "\n");
S.SetSeq(S_Use);
ANNOTATE_BOTTOMUP(Inst, Ptr, Seq, S_Use);
}
break;
case S_CanRelease:
@ -1537,10 +1247,6 @@ bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
}
}
// If ARC Annotations are enabled, output the current state of pointers at the
// bottom of the basic block.
ANNOTATE_BOTTOMUP_BBEND(MyStates, BB);
// Visit all the instructions, bottom-up.
for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; --I) {
Instruction *Inst = std::prev(I);
@ -1564,10 +1270,6 @@ bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates);
}
// If ARC Annotations are enabled, output the current state of pointers at the
// top of the basic block.
ANNOTATE_BOTTOMUP_BBSTART(MyStates, BB);
return NestingDetected;
}
@ -1605,7 +1307,6 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
if (S.GetSeq() == S_Retain)
NestingDetected = true;
ANNOTATE_TOPDOWN(Inst, Arg, S.GetSeq(), S_Retain);
S.ResetSequenceProgress(S_Retain);
S.SetKnownSafe(S.HasKnownPositiveRefCount());
S.InsertCall(Inst);
@ -1637,7 +1338,6 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
S.SetReleaseMetadata(ReleaseMetadata);
S.SetTailCallRelease(cast<CallInst>(Inst)->isTailCall());
Releases[Inst] = S.GetRRInfo();
ANNOTATE_TOPDOWN(Inst, Arg, S.GetSeq(), S_None);
S.ClearSequenceProgress();
break;
case S_None:
@ -1679,7 +1379,6 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
switch (Seq) {
case S_Retain:
S.SetSeq(S_CanRelease);
ANNOTATE_TOPDOWN(Inst, Ptr, Seq, S_CanRelease);
assert(!S.HasReverseInsertPts());
S.InsertReverseInsertPt(Inst);
@ -1705,7 +1404,6 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction *Inst,
DEBUG(dbgs() << "CanUse: Seq: " << Seq << "; " << *Ptr
<< "\n");
S.SetSeq(S_Use);
ANNOTATE_TOPDOWN(Inst, Ptr, Seq, S_Use);
}
break;
case S_Retain:
@ -1748,10 +1446,6 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
}
}
// If ARC Annotations are enabled, output the current state of pointers at the
// top of the basic block.
ANNOTATE_TOPDOWN_BBSTART(MyStates, BB);
// Visit all the instructions, top-down.
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
Instruction *Inst = I;
@ -1761,13 +1455,6 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
NestingDetected |= VisitInstructionTopDown(Inst, Releases, MyStates);
}
// If ARC Annotations are enabled, output the current state of pointers at the
// bottom of the basic block.
ANNOTATE_TOPDOWN_BBEND(MyStates, BB);
#ifdef ARC_ANNOTATIONS
if (!(EnableARCAnnotations && DisableCheckForCFGHazards))
#endif
CheckForCFGHazards(BB, BBStates, MyStates);
return NestingDetected;
}
@ -2142,12 +1829,6 @@ bool ObjCARCOpt::ConnectTDBUTraversals(
if (OldDelta != 0)
return false;
#ifdef ARC_ANNOTATIONS
// Do not move calls if ARC annotations are requested.
if (EnableARCAnnotations)
return false;
#endif // ARC_ANNOTATIONS
Changed = true;
assert(OldCount != 0 && "Unreachable code?");
NumRRs += OldCount - NewCount;
@ -2604,14 +2285,6 @@ bool ObjCARCOpt::doInitialization(Module &M) {
M.getContext().getMDKindID("clang.arc.copy_on_escape");
NoObjCARCExceptionsMDKind =
M.getContext().getMDKindID("clang.arc.no_objc_arc_exceptions");
#ifdef ARC_ANNOTATIONS
ARCAnnotationBottomUpMDKind =
M.getContext().getMDKindID("llvm.arc.annotation.bottomup");
ARCAnnotationTopDownMDKind =
M.getContext().getMDKindID("llvm.arc.annotation.topdown");
ARCAnnotationProvenanceSourceMDKind =
M.getContext().getMDKindID("llvm.arc.annotation.provenancesource");
#endif // ARC_ANNOTATIONS
// Intuitively, objc_retain and others are nocapture, however in practice
// they are not, because they return their argument value. And objc_release

View File

@ -1,83 +0,0 @@
; This file consists of various tests which ensure that the objc-arc-annotations
; are working correctly. In the future, I will use this in other lit tests to
; check the data flow analysis of ARC.
; REQUIRES: asserts
; RUN: opt -S -objc-arc -enable-objc-arc-annotations < %s | FileCheck %s
declare i8* @objc_retain(i8*)
declare i8* @objc_retainAutoreleasedReturnValue(i8*)
declare void @objc_release(i8*)
declare i8* @objc_autorelease(i8*)
declare i8* @objc_autoreleaseReturnValue(i8*)
declare void @objc_autoreleasePoolPop(i8*)
declare i8* @objc_autoreleasePoolPush()
declare i8* @objc_retainBlock(i8*)
declare i8* @objc_retainedObject(i8*)
declare i8* @objc_unretainedObject(i8*)
declare i8* @objc_unretainedPointer(i8*)
declare void @use_pointer(i8*)
declare void @callee()
declare void @callee_fnptr(void ()*)
declare void @invokee()
declare i8* @returner()
; Simple retain+release pair deletion, with some intervening control
; flow and harmless instructions.
; CHECK-LABEL: define void @test0(
; CHECK: entry:
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_None)
; CHECK: %0 = tail call i8* @objc_retain(i8* %a) #0, !llvm.arc.annotation.bottomup ![[ANN0:[0-9]+]], !llvm.arc.annotation.topdown ![[ANN1:[0-9]+]]
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_Use)
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_Retain)
; CHECK: t:
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_Retain)
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_Use)
; CHECK: store float 2.000000e+00, float* %b, !llvm.arc.annotation.bottomup ![[ANN2:[0-9]+]]
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_Release)
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_Retain)
; CHECK: f:
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_Retain)
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_Use)
; CHECK: store i32 7, i32* %x, !llvm.arc.annotation.bottomup ![[ANN2]]
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_Release)
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_Retain)
; CHECK: return:
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_Retain)
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_Release)
; CHECK: call void @objc_release(i8* %c) #0, !llvm.arc.annotation.bottomup ![[ANN3:[0-9]+]], !llvm.arc.annotation.topdown ![[ANN4:[0-9]+]]
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_None)
; CHECK: }
define void @test0(i32* %x, i1 %p) nounwind {
entry:
%a = bitcast i32* %x to i8*
%0 = call i8* @objc_retain(i8* %a) nounwind
br i1 %p, label %t, label %f
t:
store i8 3, i8* %a
%b = bitcast i32* %x to float*
store float 2.0, float* %b
br label %return
f:
store i32 7, i32* %x
br label %return
return:
%c = bitcast i32* %x to i8*
call void @objc_release(i8* %c) nounwind
ret void
}
!0 = !{}
; CHECK: ![[ANN0]] = !{!"(test0,%x)", !"S_Use", !"S_None"}
; CHECK: ![[ANN1]] = !{!"(test0,%x)", !"S_None", !"S_Retain"}
; CHECK: ![[ANN2]] = !{!"(test0,%x)", !"S_Release", !"S_Use"}
; CHECK: ![[ANN3]] = !{!"(test0,%x)", !"S_None", !"S_Release"}
; CHECK: ![[ANN4]] = !{!"(test0,%x)", !"S_Retain", !"S_None"}