Teach clang to add metadata tags to calls and invokes in ObjC with
-fno-objc-arc-exceptions. This will allow the optimizer to perform optimizations which are only safe under that flag. This is a part of rdar://10803830. llvm-svn: 150644
This commit is contained in:
parent
90e7c12961
commit
515a60daff
|
@ -1593,6 +1593,16 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
|
||||||
args.add(EmitAnyExprToTemp(E), type);
|
args.add(EmitAnyExprToTemp(E), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
|
||||||
|
// optimizer it can aggressively ignore unwind edges.
|
||||||
|
void
|
||||||
|
CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
|
||||||
|
if (CGM.getCodeGenOpts().OptimizationLevel != 0 &&
|
||||||
|
!CGM.getCodeGenOpts().ObjCAutoRefCountExceptions)
|
||||||
|
Inst->setMetadata("clang.arc.no_objc_arc_exceptions",
|
||||||
|
CGM.getNoObjCARCExceptionsMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
/// Emits a call or invoke instruction to the given function, depending
|
/// Emits a call or invoke instruction to the given function, depending
|
||||||
/// on the current state of the EH stack.
|
/// on the current state of the EH stack.
|
||||||
llvm::CallSite
|
llvm::CallSite
|
||||||
|
@ -1600,14 +1610,22 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
|
||||||
ArrayRef<llvm::Value *> Args,
|
ArrayRef<llvm::Value *> Args,
|
||||||
const Twine &Name) {
|
const Twine &Name) {
|
||||||
llvm::BasicBlock *InvokeDest = getInvokeDest();
|
llvm::BasicBlock *InvokeDest = getInvokeDest();
|
||||||
if (!InvokeDest)
|
|
||||||
return Builder.CreateCall(Callee, Args, Name);
|
|
||||||
|
|
||||||
llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
|
llvm::Instruction *Inst;
|
||||||
llvm::InvokeInst *Invoke = Builder.CreateInvoke(Callee, ContBB, InvokeDest,
|
if (!InvokeDest)
|
||||||
Args, Name);
|
Inst = Builder.CreateCall(Callee, Args, Name);
|
||||||
EmitBlock(ContBB);
|
else {
|
||||||
return Invoke;
|
llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
|
||||||
|
Inst = Builder.CreateInvoke(Callee, ContBB, InvokeDest, Args, Name);
|
||||||
|
EmitBlock(ContBB);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
|
||||||
|
// optimizer it can aggressively ignore unwind edges.
|
||||||
|
if (CGM.getLangOptions().ObjCAutoRefCount)
|
||||||
|
AddObjCARCExceptionMetadata(Inst);
|
||||||
|
|
||||||
|
return Inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::CallSite
|
llvm::CallSite
|
||||||
|
@ -1916,6 +1934,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||||
CS.setAttributes(Attrs);
|
CS.setAttributes(Attrs);
|
||||||
CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
|
CS.setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
|
||||||
|
|
||||||
|
// In ObjC ARC mode with no ObjC ARC exception safety, tell the ARC
|
||||||
|
// optimizer it can aggressively ignore unwind edges.
|
||||||
|
if (CGM.getLangOptions().ObjCAutoRefCount)
|
||||||
|
AddObjCARCExceptionMetadata(CS.getInstruction());
|
||||||
|
|
||||||
// If the call doesn't return, finish the basic block and clear the
|
// If the call doesn't return, finish the basic block and clear the
|
||||||
// insertion point; this allows the rest of IRgen to discard
|
// insertion point; this allows the rest of IRgen to discard
|
||||||
// unreachable code.
|
// unreachable code.
|
||||||
|
|
|
@ -2566,6 +2566,8 @@ private:
|
||||||
CodeGenModule::ByrefHelpers *
|
CodeGenModule::ByrefHelpers *
|
||||||
buildByrefHelpers(llvm::StructType &byrefType,
|
buildByrefHelpers(llvm::StructType &byrefType,
|
||||||
const AutoVarEmission &emission);
|
const AutoVarEmission &emission);
|
||||||
|
|
||||||
|
void AddObjCARCExceptionMetadata(llvm::Instruction *Inst);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper class with most of the code for saving a value for a
|
/// Helper class with most of the code for saving a value for a
|
||||||
|
|
|
@ -69,7 +69,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
|
||||||
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO),
|
Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI, CGO),
|
||||||
TBAA(0),
|
TBAA(0),
|
||||||
VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
|
VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
|
||||||
DebugInfo(0), ARCData(0), RRData(0), CFConstantStringClassRef(0),
|
DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0),
|
||||||
|
RRData(0), CFConstantStringClassRef(0),
|
||||||
ConstantStringClassRef(0), NSConstantStringType(0),
|
ConstantStringClassRef(0), NSConstantStringType(0),
|
||||||
VMContext(M.getContext()),
|
VMContext(M.getContext()),
|
||||||
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
|
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
|
||||||
|
|
|
@ -233,6 +233,7 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||||
CGCUDARuntime* CUDARuntime;
|
CGCUDARuntime* CUDARuntime;
|
||||||
CGDebugInfo* DebugInfo;
|
CGDebugInfo* DebugInfo;
|
||||||
ARCEntrypoints *ARCData;
|
ARCEntrypoints *ARCData;
|
||||||
|
llvm::MDNode *NoObjCARCExceptionsMetadata;
|
||||||
RREntrypoints *RRData;
|
RREntrypoints *RRData;
|
||||||
|
|
||||||
// WeakRefReferences - A set of references that have only been seen via
|
// WeakRefReferences - A set of references that have only been seen via
|
||||||
|
@ -421,6 +422,14 @@ public:
|
||||||
|
|
||||||
CGDebugInfo *getModuleDebugInfo() { return DebugInfo; }
|
CGDebugInfo *getModuleDebugInfo() { return DebugInfo; }
|
||||||
|
|
||||||
|
llvm::MDNode *getNoObjCARCExceptionsMetadata() {
|
||||||
|
if (!NoObjCARCExceptionsMetadata)
|
||||||
|
NoObjCARCExceptionsMetadata =
|
||||||
|
llvm::MDNode::get(getLLVMContext(),
|
||||||
|
SmallVector<llvm::Value*,1>());
|
||||||
|
return NoObjCARCExceptionsMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
ASTContext &getContext() const { return Context; }
|
ASTContext &getContext() const { return Context; }
|
||||||
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
|
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
|
||||||
const LangOptions &getLangOptions() const { return Features; }
|
const LangOptions &getLangOptions() const { return Features; }
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s | FileCheck %s
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O0 -disable-llvm-optzns -o - %s | FileCheck -check-prefix=NO-METADATA %s
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fblocks -fexceptions -fobjc-exceptions -O2 -disable-llvm-optzns -o - %s -fobjc-arc-exceptions | FileCheck -check-prefix=NO-METADATA %s
|
||||||
|
|
||||||
|
// The front-end should emit clang.arc.no_objc_arc_exceptions in -fobjc-arc-exceptions
|
||||||
|
// mode when optimization is enabled, and not otherwise.
|
||||||
|
|
||||||
|
void thrower(void);
|
||||||
|
void not(void) __attribute__((nothrow));
|
||||||
|
|
||||||
|
// CHECK: define void @test0(
|
||||||
|
// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !0
|
||||||
|
// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions !0
|
||||||
|
// NO-METADATA: define void @test0(
|
||||||
|
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
|
||||||
|
// NO-METADATA: }
|
||||||
|
void test0(void) {
|
||||||
|
thrower();
|
||||||
|
not();
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: define void @test1(
|
||||||
|
// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !0
|
||||||
|
// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions !0
|
||||||
|
// NO-METADATA: define void @test1(
|
||||||
|
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
|
||||||
|
// NO-METADATA: }
|
||||||
|
void test1(id x) {
|
||||||
|
id y = x;
|
||||||
|
thrower();
|
||||||
|
not();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NSLog(id, ...);
|
||||||
|
|
||||||
|
// CHECK: define void @test2(
|
||||||
|
// CHECK: invoke void (i8*, ...)* @NSLog(i8* bitcast (%struct.NSConstantString* @_unnamed_cfstring_ to i8*), i32* %x2)
|
||||||
|
// CHECK: to label %invoke.cont unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
|
||||||
|
// NO-METADATA: define void @test2(
|
||||||
|
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
|
||||||
|
// NO-METADATA: }
|
||||||
|
void test2(void) {
|
||||||
|
@autoreleasepool {
|
||||||
|
__attribute__((__blocks__(byref))) int x;
|
||||||
|
NSLog(@"Address of x outside of block: %p", &x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: define void @test3(
|
||||||
|
// CHECK: invoke void %9(i8* %7)
|
||||||
|
// CHECK: to label %invoke.cont unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
|
||||||
|
// NO-METADATA: define void @test3(
|
||||||
|
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
|
||||||
|
// NO-METADATA: }
|
||||||
|
void test3(void) {
|
||||||
|
@autoreleasepool {
|
||||||
|
__attribute__((__blocks__(byref))) int x;
|
||||||
|
^{
|
||||||
|
NSLog(@"Address of x in non-assigned block: %p", &x);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: define void @test4(
|
||||||
|
// CHECK: invoke void %13(i8* %11)
|
||||||
|
// CHECK: to label %invoke.cont unwind label %lpad, !clang.arc.no_objc_arc_exceptions !0
|
||||||
|
// NO-METADATA: define void @test4(
|
||||||
|
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
|
||||||
|
// NO-METADATA: }
|
||||||
|
void test4(void) {
|
||||||
|
@autoreleasepool {
|
||||||
|
__attribute__((__blocks__(byref))) int x;
|
||||||
|
void (^b)(void) = ^{
|
||||||
|
NSLog(@"Address of x in assigned block: %p", &x);
|
||||||
|
};
|
||||||
|
b();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue