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);
|
||||
}
|
||||
|
||||
// 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
|
||||
/// on the current state of the EH stack.
|
||||
llvm::CallSite
|
||||
|
@ -1600,14 +1610,22 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
|
|||
ArrayRef<llvm::Value *> Args,
|
||||
const Twine &Name) {
|
||||
llvm::BasicBlock *InvokeDest = getInvokeDest();
|
||||
if (!InvokeDest)
|
||||
return Builder.CreateCall(Callee, Args, Name);
|
||||
|
||||
llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
|
||||
llvm::InvokeInst *Invoke = Builder.CreateInvoke(Callee, ContBB, InvokeDest,
|
||||
Args, Name);
|
||||
EmitBlock(ContBB);
|
||||
return Invoke;
|
||||
llvm::Instruction *Inst;
|
||||
if (!InvokeDest)
|
||||
Inst = Builder.CreateCall(Callee, Args, Name);
|
||||
else {
|
||||
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
|
||||
|
@ -1916,6 +1934,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
|||
CS.setAttributes(Attrs);
|
||||
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
|
||||
// insertion point; this allows the rest of IRgen to discard
|
||||
// unreachable code.
|
||||
|
|
|
@ -2566,6 +2566,8 @@ private:
|
|||
CodeGenModule::ByrefHelpers *
|
||||
buildByrefHelpers(llvm::StructType &byrefType,
|
||||
const AutoVarEmission &emission);
|
||||
|
||||
void AddObjCARCExceptionMetadata(llvm::Instruction *Inst);
|
||||
};
|
||||
|
||||
/// 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),
|
||||
TBAA(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),
|
||||
VMContext(M.getContext()),
|
||||
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
|
||||
|
|
|
@ -233,6 +233,7 @@ class CodeGenModule : public CodeGenTypeCache {
|
|||
CGCUDARuntime* CUDARuntime;
|
||||
CGDebugInfo* DebugInfo;
|
||||
ARCEntrypoints *ARCData;
|
||||
llvm::MDNode *NoObjCARCExceptionsMetadata;
|
||||
RREntrypoints *RRData;
|
||||
|
||||
// WeakRefReferences - A set of references that have only been seen via
|
||||
|
@ -421,6 +422,14 @@ public:
|
|||
|
||||
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; }
|
||||
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
|
||||
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