block literal irgen: several improvements on naming block
literal helper functions. All helper functions (global and locals) use block_invoke as their prefix. Local literal helper names are prefixed by their enclosing mangled function names. Blocks in non-local initializers (e.g. a global variable or a C++11 field) are prefixed by their mangled variable name. The descriminator number added to end of the name starts off with blank (for first block) and _<N> (for the N+2-th block). llvm-svn: 159206
This commit is contained in:
parent
4196046714
commit
6362803cfe
|
@ -121,6 +121,7 @@ public:
|
|||
raw_ostream &) = 0;
|
||||
|
||||
void mangleGlobalBlock(const BlockDecl *BD,
|
||||
const NamedDecl *ID,
|
||||
raw_ostream &Out);
|
||||
void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT,
|
||||
const BlockDecl *BD, raw_ostream &Out);
|
||||
|
@ -129,7 +130,8 @@ public:
|
|||
void mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
||||
raw_ostream &Out);
|
||||
// Do the right thing.
|
||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out);
|
||||
void mangleBlock(const BlockDecl *BD, raw_ostream &Out,
|
||||
const NamedDecl *ID=0);
|
||||
|
||||
void mangleObjCMethodName(const ObjCMethodDecl *MD,
|
||||
raw_ostream &);
|
||||
|
|
|
@ -40,7 +40,11 @@ static void mangleFunctionBlock(MangleContext &Context,
|
|||
StringRef Outer,
|
||||
const BlockDecl *BD,
|
||||
raw_ostream &Out) {
|
||||
Out << "__" << Outer << "_block_invoke_" << Context.getBlockId(BD, true);
|
||||
unsigned discriminator = Context.getBlockId(BD, true);
|
||||
if (discriminator == 0)
|
||||
Out << "__" << Outer << "_block_invoke";
|
||||
else
|
||||
Out << "__" << Outer << "_block_invoke_" << discriminator+1;
|
||||
}
|
||||
|
||||
static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
|
||||
|
@ -62,8 +66,20 @@ static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
|
|||
void MangleContext::anchor() { }
|
||||
|
||||
void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
|
||||
const NamedDecl *ID,
|
||||
raw_ostream &Out) {
|
||||
Out << "__block_global_" << getBlockId(BD, false);
|
||||
unsigned discriminator = getBlockId(BD, false);
|
||||
if (ID) {
|
||||
if (shouldMangleDeclName(ID))
|
||||
mangleName(ID, Out);
|
||||
else {
|
||||
Out << ID->getIdentifier()->getName();
|
||||
}
|
||||
}
|
||||
if (discriminator == 0)
|
||||
Out << "_block_invoke";
|
||||
else
|
||||
Out << "_block_invoke_" << discriminator+1;
|
||||
}
|
||||
|
||||
void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
|
||||
|
@ -99,8 +115,8 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
|
|||
mangleObjCMethodName(Method, Stream);
|
||||
} else {
|
||||
const NamedDecl *ND = cast<NamedDecl>(DC);
|
||||
if (IdentifierInfo *II = ND->getIdentifier())
|
||||
Stream << II->getName();
|
||||
if (!shouldMangleDeclName(ND) && ND->getIdentifier())
|
||||
Stream << ND->getIdentifier()->getName();
|
||||
else {
|
||||
// FIXME: We were doing a mangleUnqualifiedName() before, but that's
|
||||
// a private member of a class that will soon itself be private to the
|
||||
|
@ -131,12 +147,13 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
|
|||
}
|
||||
|
||||
void MangleContext::mangleBlock(const BlockDecl *BD,
|
||||
raw_ostream &Out) {
|
||||
raw_ostream &Out,
|
||||
const NamedDecl *ID) {
|
||||
const DeclContext *DC = BD->getDeclContext();
|
||||
while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
|
||||
DC = DC->getParent();
|
||||
if (DC->isFunctionOrMethod())
|
||||
mangleBlock(DC, BD, Out);
|
||||
else
|
||||
mangleGlobalBlock(BD, Out);
|
||||
mangleGlobalBlock(BD, ID, Out);
|
||||
}
|
||||
|
|
|
@ -630,7 +630,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
|
|||
// Using the computed layout, generate the actual block function.
|
||||
bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
|
||||
llvm::Constant *blockFn
|
||||
= CodeGenFunction(CGM).GenerateBlockFunction(CurGD, blockInfo,
|
||||
= CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo,
|
||||
CurFuncDecl, LocalDeclMap,
|
||||
isLambdaConv);
|
||||
blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
|
||||
|
@ -1003,7 +1003,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
|
|||
// Check if we should generate debug info for this block function.
|
||||
if (CGM.getModuleDebugInfo())
|
||||
DebugInfo = CGM.getModuleDebugInfo();
|
||||
|
||||
CurGD = GD;
|
||||
|
||||
BlockInfo = &blockInfo;
|
||||
|
||||
// Arrange for local static and local extern declarations to appear
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
||||
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
|
||||
: CodeGenTypeCache(cgm), CGM(cgm),
|
||||
Target(CGM.getContext().getTargetInfo()),
|
||||
Builder(cgm.getModule().getContext()),
|
||||
|
@ -42,7 +42,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
|||
TerminateHandler(0), TrapBB(0) {
|
||||
|
||||
CatchUndefined = getContext().getLangOpts().CatchUndefined;
|
||||
CGM.getCXXABI().getMangleContext().startNewFunction();
|
||||
if (!suppressNewContext)
|
||||
CGM.getCXXABI().getMangleContext().startNewFunction();
|
||||
}
|
||||
|
||||
CodeGenFunction::~CodeGenFunction() {
|
||||
|
|
|
@ -1198,7 +1198,7 @@ private:
|
|||
llvm::BasicBlock *TrapBB;
|
||||
|
||||
public:
|
||||
CodeGenFunction(CodeGenModule &cgm);
|
||||
CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext=false);
|
||||
~CodeGenFunction();
|
||||
|
||||
CodeGenTypes &getTypes() const { return CGM.getTypes(); }
|
||||
|
|
|
@ -347,7 +347,8 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
|
|||
else if (const CXXDestructorDecl *D = dyn_cast<CXXDestructorDecl>(ND))
|
||||
getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Out);
|
||||
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(ND))
|
||||
getCXXABI().getMangleContext().mangleBlock(BD, Out);
|
||||
getCXXABI().getMangleContext().mangleBlock(BD, Out,
|
||||
dyn_cast_or_null<VarDecl>(initializedGlobalDecl.getDecl()));
|
||||
else
|
||||
getCXXABI().getMangleContext().mangleName(ND, Out);
|
||||
|
||||
|
@ -368,7 +369,8 @@ void CodeGenModule::getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer,
|
|||
const Decl *D = GD.getDecl();
|
||||
llvm::raw_svector_ostream Out(Buffer.getBuffer());
|
||||
if (D == 0)
|
||||
MangleCtx.mangleGlobalBlock(BD, Out);
|
||||
MangleCtx.mangleGlobalBlock(BD,
|
||||
dyn_cast_or_null<VarDecl>(initializedGlobalDecl.getDecl()), Out);
|
||||
else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
|
||||
MangleCtx.mangleCtorBlock(CD, GD.getCtorType(), BD, Out);
|
||||
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
|
||||
|
@ -1551,8 +1553,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
|
|||
// FIXME: It does so in a global constructor, which is *not* what we
|
||||
// want.
|
||||
|
||||
if (!Init)
|
||||
if (!Init) {
|
||||
initializedGlobalDecl = GlobalDecl(D);
|
||||
Init = EmitConstantInit(*InitDecl);
|
||||
}
|
||||
if (!Init) {
|
||||
QualType T = InitExpr->getType();
|
||||
if (D->getType()->isReferenceType())
|
||||
|
|
|
@ -351,6 +351,8 @@ class CodeGenModule : public CodeGenTypeCache {
|
|||
struct {
|
||||
int GlobalUniqueCount;
|
||||
} Block;
|
||||
|
||||
GlobalDecl initializedGlobalDecl;
|
||||
|
||||
/// @}
|
||||
public:
|
||||
|
@ -596,7 +598,7 @@ public:
|
|||
|
||||
/// getUniqueBlockCount - Fetches the global unique block count.
|
||||
int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; }
|
||||
|
||||
|
||||
/// getBlockDescriptorType - Fetches the type of a generic block
|
||||
/// descriptor.
|
||||
llvm::Type *getBlockDescriptorType();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace PR12746 {
|
||||
// CHECK: define zeroext i1 @_ZN7PR127462f1EPi
|
||||
bool f1(int *x) {
|
||||
// CHECK: store i8* bitcast (i1 (i8*)* @__f1_block_invoke_0 to i8*)
|
||||
// CHECK: store i8* bitcast (i1 (i8*)* @___ZN7PR127462f1EPi_block_invoke to i8*)
|
||||
bool (^outer)() = ^ {
|
||||
auto inner = [&]() -> bool {
|
||||
return x == 0;
|
||||
|
@ -13,8 +13,8 @@ namespace PR12746 {
|
|||
return outer();
|
||||
}
|
||||
|
||||
// CHECK: define internal zeroext i1 @__f1_block_invoke_0
|
||||
// CHECK: call zeroext i1 @"_ZNK7PR127462f119__f1_block_invoke_03$_0clEv"
|
||||
// CHECK: define internal zeroext i1 @___ZN7PR127462f1EPi_block_invoke
|
||||
// CHECK: call zeroext i1 @"_ZNK7PR127462f132___ZN7PR127462f1EPi_block_invoke3$_0clEv"
|
||||
|
||||
bool f2(int *x) {
|
||||
auto outer = [&]() -> bool {
|
||||
|
|
|
@ -12,7 +12,7 @@ struct s0 {
|
|||
int a[64];
|
||||
};
|
||||
|
||||
// CHECK: define internal void @__f2_block_invoke_0(%struct.s0* noalias sret {{%.*}}, i8* {{%.*}}, %struct.s0* byval align 4 {{.*}})
|
||||
// CHECK: define internal void @__f2_block_invoke(%struct.s0* noalias sret {{%.*}}, i8* {{%.*}}, %struct.s0* byval align 4 {{.*}})
|
||||
struct s0 f2(struct s0 a0) {
|
||||
return ^(struct s0 a1){ return a1; }(a0);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
// X32: [[STR1:@.*]] = private unnamed_addr constant [6 x i8] c"v4@?0\00"
|
||||
// X32: @__block_descriptor_tmp = internal constant [[FULL_DESCRIPTOR_T:.*]] { i32 0, i32 20, i8* getelementptr inbounds ([6 x i8]* [[STR1]], i32 0, i32 0), i8* null }
|
||||
// X32: @__block_literal_global = internal constant [[GLOBAL_LITERAL_T:.*]] { i8** @_NSConcreteGlobalBlock, i32 1342177280, i32 0, i8* bitcast (void (i8*)* @__block_global_{{.*}} to i8*), [[DESCRIPTOR_T:%.*]]* bitcast ([[FULL_DESCRIPTOR_T]]* @__block_descriptor_tmp to {{%.*}}*) }
|
||||
// X32: @__block_literal_global = internal constant [[GLOBAL_LITERAL_T:.*]] { i8** @_NSConcreteGlobalBlock, i32 1342177280, i32 0, i8* bitcast (void (i8*)* @global_block_invoke{{.*}} to i8*), [[DESCRIPTOR_T:%.*]]* bitcast ([[FULL_DESCRIPTOR_T]]* @__block_descriptor_tmp to {{%.*}}*) }
|
||||
// X32: [[STR2:@.*]] = private unnamed_addr constant [11 x i8] c"i12@?0c4f8\00"
|
||||
// X32: @__block_descriptor_tmp{{.*}} = internal constant [[FULL_DESCRIPTOR_T]] { i32 0, i32 24, i8* getelementptr inbounds ([11 x i8]* [[STR2]], i32 0, i32 0), i8* null }
|
||||
// X32: store i32 1073741824, i32*
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -emit-llvm -o - %s | FileCheck %s
|
||||
// pr8707
|
||||
|
||||
// CHECK: @__block_global_0.test = internal global i32
|
||||
// CHECK: @block_block_invoke.test = internal global i32
|
||||
int (^block)(void) = ^ {
|
||||
static int test=0;
|
||||
return test;
|
||||
};
|
||||
// CHECK: @__block_global_1.test = internal global i32
|
||||
// CHECK: @block1_block_invoke_2.test = internal global i32
|
||||
void (^block1)(void) = ^ {
|
||||
static int test = 2;
|
||||
return;
|
||||
};
|
||||
// CHECK: @__block_global_2.test = internal global i32
|
||||
// CHECK: @block2_block_invoke_3.test = internal global i32
|
||||
int (^block2)(void) = ^ {
|
||||
static int test = 5;
|
||||
return test;
|
||||
|
|
|
@ -12,7 +12,7 @@ int main ()
|
|||
b();
|
||||
}
|
||||
|
||||
// CHECK: define internal void @__main_block_invoke_0
|
||||
// CHECK: define internal void @__main_block_invoke
|
||||
// CHECK: [[C1:%.*]] = alloca { double, double }, align 8
|
||||
// CHECK: [[RP:%.*]] = getelementptr inbounds { double, double }* [[C1]], i32 0, i32 0
|
||||
// CHECK-NEXT: [[R:%.*]] = load double* [[RP]]
|
||||
|
|
|
@ -15,5 +15,5 @@ int main()
|
|||
return 0; // not reached
|
||||
}
|
||||
|
||||
// CHECK: @__func__.__main_block_invoke_0 = private unnamed_addr constant [22 x i8] c"__main_block_invoke_0\00"
|
||||
// CHECK: call void @PRINTF({{.*}}@__func__.__main_block_invoke_
|
||||
// CHECK: @__func__.__main_block_invoke = private unnamed_addr constant [20 x i8] c"__main_block_invoke\00"
|
||||
// CHECK: call void @PRINTF({{.*}}@__func__.__main_block_invoke
|
||||
|
|
|
@ -36,13 +36,13 @@ X::~X() {
|
|||
};
|
||||
|
||||
|
||||
// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke
|
||||
// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke
|
||||
// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN1XC1Ev_block_invoke
|
||||
// CHECK: define internal void @___ZN1XC1Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN1XC1Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN1XC2Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN1XC2Ev_block_invoke
|
||||
// CHECK: define internal void @___ZN1XC2Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN1XD2Ev_block_invoke_
|
||||
// CHECK: define internal void @___ZN1XD2Ev_block_invoke
|
||||
// CHECK: define internal void @___ZN1XD2Ev_block_invoke_
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace test0 {
|
||||
// CHECK: define void @_ZN5test04testEi(
|
||||
// CHECK: define internal void @__test_block_invoke_{{.*}}(
|
||||
// CHECK: define internal void @__block_global_{{.*}}(
|
||||
// CHECK: define internal void @___ZN5test04testEi_block_invoke{{.*}}(
|
||||
// CHECK: define internal void @___ZN5test04testEi_block_invoke_2{{.*}}(
|
||||
void test(int x) {
|
||||
^{ ^{ (void) x; }; };
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ namespace test4 {
|
|||
consume(^{ return foo(A()); });
|
||||
}
|
||||
// CHECK: define void @_ZN5test44testEv()
|
||||
// CHECK: define internal void @__test_block_invoke
|
||||
// CHECK: define internal void @___ZN5test44testEv_block_invoke
|
||||
// CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
|
||||
// CHECK-NEXT: bitcast i8*
|
||||
// CHECK-NEXT: call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 %s | FileCheck %s
|
||||
// rdar://11343499
|
||||
|
||||
namespace N {
|
||||
typedef void (^BL)();
|
||||
int func(BL, BL, BL);
|
||||
|
||||
// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke(
|
||||
// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke_2(
|
||||
// CHECK: define internal void @_ZN1N8ArrBlockE_block_invoke_3
|
||||
BL ArrBlock [] = { ^{}, ^{}, ^{} };
|
||||
|
||||
// CHECK: define internal void @_ZN1N4ivalE_block_invoke_4(
|
||||
// CHECK: define internal void @_ZN1N4ivalE_block_invoke_5(
|
||||
// CHECK: define internal void @_ZN1N4ivalE_block_invoke_6(
|
||||
int ival = func(^{}, ^{}, ^{});
|
||||
|
||||
// CHECK: define internal void @_ZN1N9gvarlobalE_block_invoke_7(
|
||||
void (^gvarlobal)(void) = ^{};
|
||||
|
||||
struct S {
|
||||
BL field = ^{};
|
||||
};
|
||||
|
||||
// CHECK: define internal void @_ZN1N3blfE_block_invoke_8(
|
||||
S blf;
|
||||
};
|
|
@ -124,7 +124,7 @@ void test4(void) {
|
|||
// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
|
||||
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
|
||||
|
||||
// CHECK: define internal void @__test4_block_invoke_
|
||||
// CHECK: define internal void @__test4_block_invoke
|
||||
// CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
|
||||
// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
|
||||
// CHECK-NEXT: store i8* null, i8** [[SLOT]],
|
||||
|
@ -200,7 +200,7 @@ void test6(void) {
|
|||
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
|
||||
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
|
||||
|
||||
// CHECK: define internal void @__test6_block_invoke_
|
||||
// CHECK: define internal void @__test6_block_invoke
|
||||
// CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
|
||||
// CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
|
||||
// CHECK-NEXT: ret void
|
||||
|
@ -238,7 +238,7 @@ void test7(void) {
|
|||
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
|
||||
// CHECK-NEXT: ret void
|
||||
|
||||
// CHECK: define internal void @__test7_block_invoke_
|
||||
// CHECK: define internal void @__test7_block_invoke
|
||||
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
|
||||
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
|
||||
// CHECK-NEXT: call void @test7_consume(i8* [[T0]])
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
|
||||
// CHECK: define i8* @{{.*}}test0
|
||||
// CHECK: define internal void @__test0_block_invoke_0(
|
||||
// CHECK: define internal void @{{.*}}_block_invoke(
|
||||
// CHECK: call i8* @objc_assign_strongCast(
|
||||
// CHECK-NEXT: ret void
|
||||
id test0(id x) {
|
||||
|
|
|
@ -18,7 +18,7 @@ void foo(T *P) {
|
|||
-(void) im0;
|
||||
@end
|
||||
|
||||
// CHECK: define internal i32 @"__8-[A im0]_block_invoke_0"(
|
||||
// CHECK: define internal i32 @"__8-[A im0]_block_invoke"(
|
||||
@implementation A
|
||||
-(void) im0 {
|
||||
(void) ^{ return 1; }();
|
||||
|
@ -91,7 +91,7 @@ void test2(Test2 *x) {
|
|||
// rdar://problem/9124263
|
||||
// In the test above, check that the use in the invocation function
|
||||
// doesn't require a read barrier.
|
||||
// CHECK: define internal void @__test2_block_invoke_
|
||||
// CHECK: define internal void @__test2_block_invoke
|
||||
// CHECK: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
|
||||
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
|
||||
// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
|
||||
|
|
|
@ -9,7 +9,7 @@ fp f() { auto x = []{ return 3; }; return x; }
|
|||
// MRC: define i32 ()* @_Z1fv(
|
||||
// MRC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
|
||||
// MRC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
|
||||
// MRC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke_0" to i8*)
|
||||
// MRC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke" to i8*)
|
||||
// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
|
||||
// MRC: call i32 ()* (i8*, i8*)* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 ()* (i8*, i8*)*)
|
||||
// MRC: ret i32 ()*
|
||||
|
@ -17,7 +17,7 @@ fp f() { auto x = []{ return 3; }; return x; }
|
|||
// ARC: define i32 ()* @_Z1fv(
|
||||
// ARC: define internal i32 ()* @"_ZZ1fvENK3$_0cvU13block_pointerFivEEv"
|
||||
// ARC: store i8* bitcast (i8** @_NSConcreteStackBlock to i8*)
|
||||
// ARC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke_0" to i8*)
|
||||
// ARC: store i8* bitcast (i32 (i8*)* @"___ZZ1fvENK3$_0cvU13block_pointerFivEEv_block_invoke" to i8*)
|
||||
// ARC: call i8* @objc_retainBlock
|
||||
// ARC: call i8* @objc_autoreleaseReturnValue
|
||||
|
||||
|
@ -26,14 +26,14 @@ fp global;
|
|||
void f2() { global = []{ return 3; }; }
|
||||
|
||||
// MRC: define void @_Z2f2v() nounwind {
|
||||
// MRC: store i8* bitcast (i32 (i8*)* @__f2_block_invoke_0 to i8*),
|
||||
// MRC: store i8* bitcast (i32 (i8*)* @___Z2f2v_block_invoke to i8*),
|
||||
// MRC-NOT: call
|
||||
// MRC: ret void
|
||||
// ("global" contains a dangling pointer after this function runs.)
|
||||
|
||||
// ARC: define void @_Z2f2v() nounwind {
|
||||
// ARC: store i8* bitcast (i32 (i8*)* @__f2_block_invoke_0 to i8*),
|
||||
// ARC: store i8* bitcast (i32 (i8*)* @___Z2f2v_block_invoke to i8*),
|
||||
// ARC: call i8* @objc_retainBlock
|
||||
// ARC: call void @objc_release
|
||||
// ARC: define internal i32 @__f2_block_invoke_0
|
||||
// ARC: define internal i32 @___Z2f2v_block_invoke
|
||||
// ARC: call i32 @"_ZZ2f2vENK3$_1clEv
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
// RUN: %clang_cc1 -emit-llvm -fblocks -o - -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s | FileCheck %s
|
||||
|
||||
// CHECK: @_ZGVN3foo20__foo_block_invoke_05valueE = internal global i64 0
|
||||
// CHECK: @_ZGVN3foo22___Z3foov_block_invoke5valueE = internal global i64 0
|
||||
|
||||
int f();
|
||||
|
||||
void foo() {
|
||||
// CHECK: define internal i32 @__foo_block_invoke_0
|
||||
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3foo20__foo_block_invoke_05value
|
||||
// CHECK: define internal i32 @___Z3foov_block_invoke
|
||||
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVN3foo22___Z3foov_block_invoke5valueE
|
||||
(void)^(int x) {
|
||||
static int value = f();
|
||||
return x + value;
|
||||
};
|
||||
}
|
||||
|
||||
// CHECK: define internal i32 @__block_global_0
|
||||
// CHECK: define internal i32 @i_block_invoke
|
||||
int i = ^(int x) { return x;}(i);
|
||||
|
||||
@interface A
|
||||
|
@ -22,9 +22,9 @@ int i = ^(int x) { return x;}(i);
|
|||
|
||||
@implementation A
|
||||
- (void)method {
|
||||
// CHECK: define internal signext i8 @"__11-[A method]_block_invoke_0"
|
||||
// CHECK: define internal signext i8 @"__11-[A method]_block_invoke"
|
||||
(void)^(int x) {
|
||||
// CHECK: @"_ZN11-[A method]30__11-[A method]_block_invoke_04nameE"
|
||||
// CHECK: @"_ZN11-[A method]28__11-[A method]_block_invoke4nameE"
|
||||
static const char *name = "hello";
|
||||
return name[x];
|
||||
};
|
||||
|
@ -39,10 +39,10 @@ void foo(int) {
|
|||
}
|
||||
|
||||
namespace N {
|
||||
// CHECK: define internal signext i8 @__bar_block_invoke_0
|
||||
// CHECK: define internal signext i8 @___Z3fooi_block_invoke
|
||||
void bar() {
|
||||
(void)^(int x) {
|
||||
// CHECK: @_ZN1N3bar20__bar_block_invoke_04nameE
|
||||
// CHECK: @_ZN1N3bar26___ZN1N3barEv_block_invoke4nameE
|
||||
static const char *name = "hello";
|
||||
return name[x];
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ struct X {
|
|||
|
||||
X blocksNRVO() {
|
||||
return ^{
|
||||
// CHECK: define internal void @__blocksNRVO_block_invoke_0
|
||||
// CHECK: define internal void @___Z10blocksNRVOv_block_invoke
|
||||
X x;
|
||||
// CHECK: tail call void @_ZN1XC1Ev
|
||||
// CHECK-NEXT: ret void
|
||||
|
|
Loading…
Reference in New Issue