mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
[ObjCARC Annotations] Added support for displaying the state of pointers at the bottom/top of BBs of the ARC dataflow analysis for both bottomup and topdown analyses.
This will allow for verification and analysis of the merge function of the data flow analyses in the ARC optimizer. The actual implementation of this feature is by introducing calls to the functions llvm.arc.annotation.{bottomup,topdown}.{bbstart,bbend} which are only declared. Each such call takes in a pointer to a global with the same name as the pointer whose provenance is being tracked and a pointer whose name is one of our Sequence states and points to a string that contains the same name. To ensure that the optimizer does not consider these annotations in any way, I made it so that the annotations are considered to be of IC_None type. A test case is included for this commit and the previous ObjCARCAnnotation commit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@177952 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7bef073622
commit
26dbfb6a78
@ -33,6 +33,7 @@
|
|||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/SmallPtrSet.h"
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include "llvm/IR/IRBuilder.h"
|
||||||
#include "llvm/IR/LLVMContext.h"
|
#include "llvm/IR/LLVMContext.h"
|
||||||
#include "llvm/Support/CFG.h"
|
#include "llvm/Support/CFG.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
@ -763,14 +764,18 @@ static MDString *AppendMDNodeToSourcePtr(unsigned NodeId,
|
|||||||
return Hash;
|
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
|
/// 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.
|
/// for raw_ostream so we only have printing code in one location.
|
||||||
static MDString *SequenceToMDString(LLVMContext &Context,
|
static MDString *SequenceToMDString(LLVMContext &Context,
|
||||||
Sequence A) {
|
Sequence A) {
|
||||||
std::string str;
|
return MDString::get(Context, SequenceToString(A));
|
||||||
raw_string_ostream os(str);
|
|
||||||
os << A;
|
|
||||||
return MDString::get(Context, os.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple function to generate a MDNode which describes the change in state
|
/// A simple function to generate a MDNode which describes the change in state
|
||||||
@ -793,6 +798,79 @@ static void AppendMDNodeToInstForPtr(unsigned NodeId,
|
|||||||
Inst->setMetadata(NodeId, Node);
|
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) {
|
||||||
|
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),
|
||||||
|
ArrayRef<Type*>(Params, 2),
|
||||||
|
/*isVarArg=*/false);
|
||||||
|
Constant *Callee = M->getOrInsertFunction(Name, FTy);
|
||||||
|
|
||||||
|
IRBuilder<> Builder(BB, BB->getFirstInsertionPt());
|
||||||
|
|
||||||
|
Value *PtrName;
|
||||||
|
StringRef Tmp = Ptr->getName();
|
||||||
|
if (0 == (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 (0 == (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) {
|
||||||
|
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),
|
||||||
|
ArrayRef<Type*>(Params, 2),
|
||||||
|
/*isVarArg=*/false);
|
||||||
|
Constant *Callee = M->getOrInsertFunction(Name, FTy);
|
||||||
|
|
||||||
|
IRBuilder<> Builder(BB, llvm::prior(BB->end()));
|
||||||
|
|
||||||
|
Value *PtrName;
|
||||||
|
StringRef Tmp = Ptr->getName();
|
||||||
|
if (0 == (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 (0 == (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
|
/// Adds a source annotation to pointer and a state change annotation to Inst
|
||||||
/// referencing the source annotation and the old/new state of pointer.
|
/// referencing the source annotation and the old/new state of pointer.
|
||||||
static void GenerateARCAnnotation(unsigned InstMDId,
|
static void GenerateARCAnnotation(unsigned InstMDId,
|
||||||
@ -1818,6 +1896,21 @@ ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ARC_ANNOTATIONS
|
||||||
|
if (EnableARCAnnotations) {
|
||||||
|
// If ARC Annotations are enabled, output the current state of pointers at the
|
||||||
|
// bottom of the basic block.
|
||||||
|
for(BBState::ptr_const_iterator I = MyStates.bottom_up_ptr_begin(),
|
||||||
|
E = MyStates.bottom_up_ptr_end(); I != E; ++I) {
|
||||||
|
Value *Ptr = const_cast<Value*>(I->first);
|
||||||
|
Sequence Seq = I->second.GetSeq();
|
||||||
|
GenerateARCBBTerminatorAnnotation("llvm.arc.annotation.bottomup.bbend",
|
||||||
|
BB, Ptr, Seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Visit all the instructions, bottom-up.
|
// Visit all the instructions, bottom-up.
|
||||||
for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; --I) {
|
for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; --I) {
|
||||||
Instruction *Inst = llvm::prior(I);
|
Instruction *Inst = llvm::prior(I);
|
||||||
@ -1841,6 +1934,20 @@ ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
|
|||||||
NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates);
|
NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ARC_ANNOTATIONS
|
||||||
|
if (EnableARCAnnotations) {
|
||||||
|
// If ARC Annotations are enabled, output the current state of pointers at the
|
||||||
|
// top of the basic block.
|
||||||
|
for(BBState::ptr_const_iterator I = MyStates.bottom_up_ptr_begin(),
|
||||||
|
E = MyStates.bottom_up_ptr_end(); I != E; ++I) {
|
||||||
|
Value *Ptr = const_cast<Value*>(I->first);
|
||||||
|
Sequence Seq = I->second.GetSeq();
|
||||||
|
GenerateARCBBEntranceAnnotation("llvm.arc.annotation.bottomup.bbstart",
|
||||||
|
BB, Ptr, Seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return NestingDetected;
|
return NestingDetected;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2012,6 +2119,20 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ARC_ANNOTATIONS
|
||||||
|
if (EnableARCAnnotations) {
|
||||||
|
// If ARC Annotations are enabled, output the current state of pointers at the
|
||||||
|
// top of the basic block.
|
||||||
|
for(BBState::ptr_const_iterator I = MyStates.top_down_ptr_begin(),
|
||||||
|
E = MyStates.top_down_ptr_end(); I != E; ++I) {
|
||||||
|
Value *Ptr = const_cast<Value*>(I->first);
|
||||||
|
Sequence Seq = I->second.GetSeq();
|
||||||
|
GenerateARCBBEntranceAnnotation("llvm.arc.annotation.topdown.bbstart",
|
||||||
|
BB, Ptr, Seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Visit all the instructions, top-down.
|
// Visit all the instructions, top-down.
|
||||||
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
|
||||||
Instruction *Inst = I;
|
Instruction *Inst = I;
|
||||||
@ -2021,6 +2142,20 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB,
|
|||||||
NestingDetected |= VisitInstructionTopDown(Inst, Releases, MyStates);
|
NestingDetected |= VisitInstructionTopDown(Inst, Releases, MyStates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ARC_ANNOTATIONS
|
||||||
|
if (EnableARCAnnotations) {
|
||||||
|
// If ARC Annotations are enabled, output the current state of pointers at the
|
||||||
|
// bottom of the basic block.
|
||||||
|
for(BBState::ptr_const_iterator I = MyStates.top_down_ptr_begin(),
|
||||||
|
E = MyStates.top_down_ptr_end(); I != E; ++I) {
|
||||||
|
Value *Ptr = const_cast<Value*>(I->first);
|
||||||
|
Sequence Seq = I->second.GetSeq();
|
||||||
|
GenerateARCBBTerminatorAnnotation("llvm.arc.annotation.topdown.bbend",
|
||||||
|
BB, Ptr, Seq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
CheckForCFGHazards(BB, BBStates, MyStates);
|
CheckForCFGHazards(BB, BBStates, MyStates);
|
||||||
return NestingDetected;
|
return NestingDetected;
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,14 @@ InstructionClass llvm::objcarc::GetFunctionClass(const Function *F) {
|
|||||||
return StringSwitch<InstructionClass>(F->getName())
|
return StringSwitch<InstructionClass>(F->getName())
|
||||||
.Case("objc_moveWeak", IC_MoveWeak)
|
.Case("objc_moveWeak", IC_MoveWeak)
|
||||||
.Case("objc_copyWeak", IC_CopyWeak)
|
.Case("objc_copyWeak", IC_CopyWeak)
|
||||||
|
// Ignore annotation calls. This is important to stop the
|
||||||
|
// optimizer from treating annotations as uses which would
|
||||||
|
// make the state of the pointers they are attempting to
|
||||||
|
// elucidate to be incorrect.
|
||||||
|
.Case("llvm.arc.annotation.topdown.bbstart", IC_None)
|
||||||
|
.Case("llvm.arc.annotation.topdown.bbend", IC_None)
|
||||||
|
.Case("llvm.arc.annotation.bottomup.bbstart", IC_None)
|
||||||
|
.Case("llvm.arc.annotation.bottomup.bbend", IC_None)
|
||||||
.Default(IC_CallOrUser);
|
.Default(IC_CallOrUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
306
test/Transforms/ObjCARC/arc-annotations.ll
Normal file
306
test/Transforms/ObjCARC/arc-annotations.ll
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
; 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.
|
||||||
|
|
||||||
|
; 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: 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 !0, !llvm.arc.annotation.topdown !1
|
||||||
|
; 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 !2
|
||||||
|
; 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 !2
|
||||||
|
; 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 !3, !llvm.arc.annotation.topdown !4
|
||||||
|
; 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
|
||||||
|
}
|
||||||
|
|
||||||
|
; Like test0 but the release isn't always executed when the retain is,
|
||||||
|
; so the optimization is not safe.
|
||||||
|
|
||||||
|
; TODO: Make the objc_release's argument be %0.
|
||||||
|
|
||||||
|
; CHECK: define void @test1(
|
||||||
|
; 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 !5, !llvm.arc.annotation.topdown !6
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_None)
|
||||||
|
; 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 !7
|
||||||
|
; 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_None)
|
||||||
|
; CHECK: call void @callee(), !llvm.arc.annotation.topdown !8
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_CanRelease)
|
||||||
|
; CHECK: return:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_None)
|
||||||
|
; 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 !9
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: alt_return:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: }
|
||||||
|
define void @test1(i32* %x, i1 %p, i1 %q) 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
|
||||||
|
call void @callee()
|
||||||
|
br i1 %q, label %return, label %alt_return
|
||||||
|
|
||||||
|
return:
|
||||||
|
%c = bitcast i32* %x to i8*
|
||||||
|
call void @objc_release(i8* %c) nounwind
|
||||||
|
ret void
|
||||||
|
|
||||||
|
alt_return:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Don't do partial elimination into two different CFG diamonds.
|
||||||
|
|
||||||
|
; CHECK: define void @test1b(
|
||||||
|
; CHECK: entry:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: %0 = tail call i8* @objc_retain(i8* %x) #0, !llvm.arc.annotation.bottomup !10, !llvm.arc.annotation.topdown !11
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_Retain)
|
||||||
|
; CHECK: if.then:
|
||||||
|
; 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_CanRelease)
|
||||||
|
; CHECK: tail call void @callee(), !llvm.arc.annotation.bottomup !12, !llvm.arc.annotation.topdown !13
|
||||||
|
; 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_CanRelease)
|
||||||
|
; CHECK: if.end:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_CanRelease)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_Use)
|
||||||
|
; 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_CanRelease)
|
||||||
|
; CHECK: if.then3:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_CanRelease)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_Use)
|
||||||
|
; CHECK: tail call void @use_pointer(i8* %x), !llvm.arc.annotation.bottomup !14, !llvm.arc.annotation.topdown !15
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_MovableRelease)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_Use)
|
||||||
|
; CHECK: if.end5:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_MovableRelease)
|
||||||
|
; CHECK: tail call void @objc_release(i8* %x) #0, !clang.imprecise_release !16, !llvm.arc.annotation.bottomup !17
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: }
|
||||||
|
define void @test1b(i8* %x, i1 %p, i1 %q) {
|
||||||
|
entry:
|
||||||
|
tail call i8* @objc_retain(i8* %x) nounwind
|
||||||
|
br i1 %p, label %if.then, label %if.end
|
||||||
|
|
||||||
|
if.then: ; preds = %entry
|
||||||
|
tail call void @callee()
|
||||||
|
br label %if.end
|
||||||
|
|
||||||
|
if.end: ; preds = %if.then, %entry
|
||||||
|
br i1 %q, label %if.then3, label %if.end5
|
||||||
|
|
||||||
|
if.then3: ; preds = %if.end
|
||||||
|
tail call void @use_pointer(i8* %x)
|
||||||
|
br label %if.end5
|
||||||
|
|
||||||
|
if.end5: ; preds = %if.then3, %if.end
|
||||||
|
tail call void @objc_release(i8* %x) nounwind, !clang.imprecise_release !0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Like test0 but the pointer is passed to an intervening call,
|
||||||
|
; so the optimization is not safe.
|
||||||
|
|
||||||
|
; CHECK: define void @test2(
|
||||||
|
; CHECK: entry:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: %e = tail call i8* @objc_retain(i8* %a) #0, !llvm.arc.annotation.bottomup !18, !llvm.arc.annotation.topdown !19
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbend(i8** @x, i8** @S_CanRelease)
|
||||||
|
; 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 !20
|
||||||
|
; 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_CanRelease)
|
||||||
|
; CHECK: call void @use_pointer(i8* %e), !llvm.arc.annotation.bottomup !21, !llvm.arc.annotation.topdown !22
|
||||||
|
; CHECK: store float 3.000000e+00, float* %d, !llvm.arc.annotation.bottomup !20, !llvm.arc.annotation.topdown !23
|
||||||
|
; 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_Use)
|
||||||
|
; CHECK: return:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_Use)
|
||||||
|
; 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 !24, !llvm.arc.annotation.topdown !25
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: }
|
||||||
|
define void @test2(i32* %x, i1 %p) nounwind {
|
||||||
|
entry:
|
||||||
|
%a = bitcast i32* %x to i8*
|
||||||
|
%e = 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
|
||||||
|
call void @use_pointer(i8* %e)
|
||||||
|
%d = bitcast i32* %x to float*
|
||||||
|
store float 3.0, float* %d
|
||||||
|
br label %return
|
||||||
|
|
||||||
|
return:
|
||||||
|
%c = bitcast i32* %x to i8*
|
||||||
|
call void @objc_release(i8* %c) nounwind
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Like test0 but the release is in a loop,
|
||||||
|
; so the optimization is not safe.
|
||||||
|
|
||||||
|
; TODO: For now, assume this can't happen.
|
||||||
|
|
||||||
|
; CHECK: define void @test3(
|
||||||
|
; CHECK: entry:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.bottomup.bbstart(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: tail call i8* @objc_retain(i8* %a) #0, !llvm.arc.annotation.bottomup !26, !llvm.arc.annotation.topdown !27
|
||||||
|
; 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: loop:
|
||||||
|
; 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 !28, !llvm.arc.annotation.topdown !29
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: return:
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbstart(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: call void @llvm.arc.annotation.topdown.bbend(i8** @x, i8** @S_None)
|
||||||
|
; CHECK: }
|
||||||
|
define void @test3(i32* %x, i1* %q) nounwind {
|
||||||
|
entry:
|
||||||
|
%a = bitcast i32* %x to i8*
|
||||||
|
%0 = call i8* @objc_retain(i8* %a) nounwind
|
||||||
|
br label %loop
|
||||||
|
|
||||||
|
loop:
|
||||||
|
%c = bitcast i32* %x to i8*
|
||||||
|
call void @objc_release(i8* %c) nounwind
|
||||||
|
%j = load volatile i1* %q
|
||||||
|
br i1 %j, label %loop, label %return
|
||||||
|
|
||||||
|
return:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
!0 = metadata !{}
|
||||||
|
|
||||||
|
; CHECK: !0 = metadata !{metadata !"(test0,%x)", metadata !"S_Use", metadata !"S_None"}
|
||||||
|
; CHECK: !1 = metadata !{metadata !"(test0,%x)", metadata !"S_None", metadata !"S_Retain"}
|
||||||
|
; CHECK: !2 = metadata !{metadata !"(test0,%x)", metadata !"S_Release", metadata !"S_Use"}
|
||||||
|
; CHECK: !3 = metadata !{metadata !"(test0,%x)", metadata !"S_None", metadata !"S_Release"}
|
||||||
|
; CHECK: !4 = metadata !{metadata !"(test0,%x)", metadata !"S_Retain", metadata !"S_None"}
|
||||||
|
; CHECK: !5 = metadata !{metadata !"(test1,%x)", metadata !"S_None", metadata !"S_None"}
|
||||||
|
; CHECK: !6 = metadata !{metadata !"(test1,%x)", metadata !"S_None", metadata !"S_Retain"}
|
||||||
|
; CHECK: !7 = metadata !{metadata !"(test1,%x)", metadata !"S_Release", metadata !"S_Use"}
|
||||||
|
; CHECK: !8 = metadata !{metadata !"(test1,%x)", metadata !"S_Retain", metadata !"S_CanRelease"}
|
||||||
|
; CHECK: !9 = metadata !{metadata !"(test1,%x)", metadata !"S_None", metadata !"S_Release"}
|
||||||
|
; CHECK: !10 = metadata !{metadata !"(test1b,%x)", metadata !"S_None", metadata !"S_None"}
|
||||||
|
; CHECK: !11 = metadata !{metadata !"(test1b,%x)", metadata !"S_None", metadata !"S_Retain"}
|
||||||
|
; CHECK: !12 = metadata !{metadata !"(test1b,%x)", metadata !"S_Use", metadata !"S_CanRelease"}
|
||||||
|
; CHECK: !13 = metadata !{metadata !"(test1b,%x)", metadata !"S_Retain", metadata !"S_CanRelease"}
|
||||||
|
; CHECK: !14 = metadata !{metadata !"(test1b,%x)", metadata !"S_MovableRelease", metadata !"S_Use"}
|
||||||
|
; CHECK: !15 = metadata !{metadata !"(test1b,%x)", metadata !"S_CanRelease", metadata !"S_Use"}
|
||||||
|
; CHECK: !16 = metadata !{}
|
||||||
|
; CHECK: !17 = metadata !{metadata !"(test1b,%x)", metadata !"S_None", metadata !"S_MovableRelease"}
|
||||||
|
; CHECK: !18 = metadata !{metadata !"(test2,%x)", metadata !"S_CanRelease", metadata !"S_None"}
|
||||||
|
; CHECK: !19 = metadata !{metadata !"(test2,%x)", metadata !"S_None", metadata !"S_Retain"}
|
||||||
|
; CHECK: !20 = metadata !{metadata !"(test2,%x)", metadata !"S_Release", metadata !"S_Use"}
|
||||||
|
; CHECK: !21 = metadata !{metadata !"(test2,%x)", metadata !"S_Use", metadata !"S_CanRelease"}
|
||||||
|
; CHECK: !22 = metadata !{metadata !"(test2,%x)", metadata !"S_Retain", metadata !"S_CanRelease"}
|
||||||
|
; CHECK: !23 = metadata !{metadata !"(test2,%x)", metadata !"S_CanRelease", metadata !"S_Use"}
|
||||||
|
; CHECK: !24 = metadata !{metadata !"(test2,%x)", metadata !"S_None", metadata !"S_Release"}
|
||||||
|
; CHECK: !25 = metadata !{metadata !"(test2,%x)", metadata !"S_Use", metadata !"S_None"}
|
||||||
|
; CHECK: !26 = metadata !{metadata !"(test3,%x)", metadata !"S_Release", metadata !"S_None"}
|
||||||
|
; CHECK: !27 = metadata !{metadata !"(test3,%x)", metadata !"S_None", metadata !"S_Retain"}
|
||||||
|
; CHECK: !28 = metadata !{metadata !"(test3,%x)", metadata !"S_None", metadata !"S_Release"}
|
||||||
|
; CHECK: !29 = metadata !{metadata !"(test3,%x)", metadata !"S_Retain", metadata !"S_None"}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user