ahatanak created this revision.

This patch fixes an infinite loop in IRGen that occurs when compiling the 
following code:

  void FUNC2() {
    static void (^const block1)(int) = ^(int a){
      if (a--)
        block1(a);
    };
  
  When IRGen visits the call to "block1", it knows that it always calls the 
block defined in Func2 enclosing the call (because "block1" is const 
qualified), so it tries to emit the reference to "block1" as a constant and 
calls CodeGenModule::GetAddrOfGlobalBlock to get the address of the block. 
CodeGenModule::GetAddrOfGlobalBlock checks whether the block has already been 
emitted (calling getAddrOfGlobalBlockIfEmitted). If the block hasn't been 
emitted, it starts generating the block invoke function, which causes the 
infinite loop.
  
  I believe this happens because clang's constant folding got smarter (see 
commit log of r290661, for example) and the call "refExpr->EvaluateAsRValue" in 
CodeGenFunction::tryEmitAsConstant returns true now as a result.
  
  This patch prevents the infinite loop by building the global block in 
GenerateBlockFunction before it emits the IR of the body of the function.
  
  rdar://problem/34541684


https://reviews.llvm.org/D38118

Files:
  lib/CodeGen/CGBlocks.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/mangle-blocks.c
  test/CodeGenObjC/local-static-block.m
  test/CodeGenObjC/mangle-blocks.m

Index: test/CodeGenObjC/mangle-blocks.m
===================================================================
--- test/CodeGenObjC/mangle-blocks.m
+++ test/CodeGenObjC/mangle-blocks.m
@@ -18,11 +18,11 @@
 @end
 
 // CHECK: @"__func__.__14-[Test mangle]_block_invoke_2" = private unnamed_addr constant [30 x i8] c"-[Test mangle]_block_invoke_2\00", align 1
-// CHECK: @.str = private unnamed_addr constant {{.*}}, align 1
-// CHECK: @.str.1 = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
+// CHECK: @.str{{.*}} = private unnamed_addr constant {{.*}}, align 1
+// CHECK: @.str[[STR1:.*]] = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
 
 // CHECK: define internal void @"__14-[Test mangle]_block_invoke"(i8* %.block_descriptor)
 
 // CHECK: define internal void @"__14-[Test mangle]_block_invoke_2"(i8* %.block_descriptor){{.*}}{
-// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @"__func__.__14-[Test mangle]_block_invoke_2", i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 14, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0))
+// CHECK: call void @__assert_rtn(i8* getelementptr inbounds ([30 x i8], [30 x i8]* @"__func__.__14-[Test mangle]_block_invoke_2", i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 14, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str[[STR1]], i32 0, i32 0))
 // CHECK: }
Index: test/CodeGenObjC/local-static-block.m
===================================================================
--- test/CodeGenObjC/local-static-block.m
+++ test/CodeGenObjC/local-static-block.m
@@ -46,6 +46,17 @@
  }
 }
 
+void FUNC2() {
+  static void (^const block1)(int) = ^(int a){
+    if (a--)
+      block1(a);
+  };
+}
+
+// CHECK-LABEL-LP64: define void @FUNC2(
+// CHECK: define internal void @_block_invoke{{.*}}(
+// CHECK: call void %{{.*}}(i8* bitcast ({ i8**, i32, i32, i8*, %struct.__block_descriptor* }* @__block_literal_global{{.*}} to i8*), i32 %{{.*}})
+
 void FUNC1()
 {
  static  NSArray *(^ArrayRecurs)(NSArray *addresses, unsigned long level) = ^(NSArray *addresses, unsigned long level) {
Index: test/CodeGen/mangle-blocks.c
===================================================================
--- test/CodeGen/mangle-blocks.c
+++ test/CodeGen/mangle-blocks.c
@@ -12,12 +12,12 @@
 }
 
 // CHECK: @__func__.__mangle_block_invoke_2 = private unnamed_addr constant [22 x i8] c"mangle_block_invoke_2\00", align 1
-// CHECK: @.str = private unnamed_addr constant {{.*}}, align 1
-// CHECK: @.str.1 = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
+// CHECK: @.str{{.*}} = private unnamed_addr constant {{.*}}, align 1
+// CHECK: @.str[[STR1:.*]] = private unnamed_addr constant [7 x i8] c"mangle\00", align 1
 
 // CHECK: define internal void @__mangle_block_invoke(i8* %.block_descriptor)
 
 // CHECK: define internal void @__mangle_block_invoke_2(i8* %.block_descriptor){{.*}}{
-// CHECK:   call void @__assert_rtn(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @__func__.__mangle_block_invoke_2, i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 9, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0))
+// CHECK:   call void @__assert_rtn(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @__func__.__mangle_block_invoke_2, i32 0, i32 0), i8* getelementptr inbounds {{.*}}, i32 9, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str[[STR1]], i32 0, i32 0))
 // CHECK: }
 
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1586,7 +1586,8 @@
   llvm::Function *GenerateBlockFunction(GlobalDecl GD,
                                         const CGBlockInfo &Info,
                                         const DeclMapTy &ldm,
-                                        bool IsLambdaConversionToBlock);
+                                        bool IsLambdaConversionToBlock,
+                                        bool BuildGlobalBlock);
 
   llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo);
   llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo);
Index: lib/CodeGen/CGBlocks.cpp
===================================================================
--- lib/CodeGen/CGBlocks.cpp
+++ lib/CodeGen/CGBlocks.cpp
@@ -725,12 +725,13 @@
   llvm::Constant *blockFn
     = CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo,
                                                        LocalDeclMap,
-                                                       isLambdaConv);
+                                                       isLambdaConv,
+                                                       blockInfo.CanBeGlobal);
   blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
 
   // If there is nothing to capture, we can emit this as a global block.
   if (blockInfo.CanBeGlobal)
-    return buildGlobalBlock(CGM, blockInfo, blockFn);
+    return CGM.getAddrOfGlobalBlockIfEmitted(blockInfo.BlockExpression);
 
   // Otherwise, we have to emit this as a local block.
 
@@ -1120,11 +1121,10 @@
     blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(),
                                                            blockInfo,
                                                            LocalDeclMap,
-                                                           false);
+                                                           false, true);
   }
-  blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
 
-  return buildGlobalBlock(*this, blockInfo, blockFn);
+  return getAddrOfGlobalBlockIfEmitted(BE);
 }
 
 static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
@@ -1226,7 +1226,8 @@
 CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
                                        const CGBlockInfo &blockInfo,
                                        const DeclMapTy &ldm,
-                                       bool IsLambdaConversionToBlock) {
+                                       bool IsLambdaConversionToBlock,
+                                       bool BuildGlobalBlock) {
   const BlockDecl *blockDecl = blockInfo.getBlockDecl();
 
   CurGD = GD;
@@ -1285,6 +1286,10 @@
       fnLLVMType, llvm::GlobalValue::InternalLinkage, name, &CGM.getModule());
   CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo);
 
+  if (BuildGlobalBlock)
+    buildGlobalBlock(CGM, blockInfo,
+                     llvm::ConstantExpr::getBitCast(fn, VoidPtrTy));
+
   // Begin generating the function.
   StartFunction(blockDecl, fnType->getReturnType(), fn, fnInfo, args,
                 blockDecl->getLocation(),
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to