Page MenuHomePhabricator

[CodeGen][ObjC] Build the global block structure before emitting the body of global block invoke functions
ClosedPublic

Authored by ahatanak on Sep 20 2017, 8:53 PM.

Details

Summary

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

Diff Detail

Repository
rL LLVM

Event Timeline

ahatanak created this revision.Sep 20 2017, 8:53 PM
rjmccall accepted this revision.Sep 21 2017, 5:29 PM

LGTM with one tweak.

lib/CodeGen/CGBlocks.cpp
1124 ↗(On Diff #116135)

Please /*comment*/ the meaning of these bools.

This revision is now accepted and ready to land.Sep 21 2017, 5:29 PM
This revision was automatically updated to reflect the committed changes.