Fixes an IRgen bug where __block variable is

referenced in the block-literal initializer
of that variable. // rdar://8893785

llvm-svn: 124332
This commit is contained in:
Fariborz Jahanian 2011-01-26 23:08:27 +00:00
parent fb4ee9bbde
commit 2f2fa7284b
4 changed files with 47 additions and 10 deletions

View File

@ -305,6 +305,15 @@ unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
return ByRefValueInfo.find(VD)->second.second;
}
llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr,
const VarDecl *V) {
llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding");
Loc = Builder.CreateLoad(Loc);
Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V),
V->getNameAsString());
return Loc;
}
/// BuildByRefType - This routine changes a __block variable declared as T x
/// into:
///
@ -795,9 +804,6 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
SpecialInit(*this, D, DeclPtr);
} else if (Init) {
llvm::Value *Loc = DeclPtr;
if (isByRef)
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
D.getNameAsString());
bool isVolatile = getContext().getCanonicalType(Ty).isVolatileQualified();
@ -844,13 +850,31 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D,
}
} else if (Ty->isReferenceType()) {
RValue RV = EmitReferenceBindingToExpr(Init, &D);
if (isByRef)
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
D.getNameAsString());
EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Alignment, Ty);
} else if (!hasAggregateLLVMType(Init->getType())) {
llvm::Value *V = EmitScalarExpr(Init);
if (isByRef) {
// When RHS has side-effect, must go through "forwarding' field
// to get to the address of the __block variable descriptor.
if (Init->HasSideEffects(getContext()))
Loc = BuildBlockByrefAddress(DeclPtr, &D);
else
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
D.getNameAsString());
}
EmitStoreOfScalar(V, Loc, isVolatile, Alignment, Ty);
} else if (Init->getType()->isAnyComplexType()) {
if (isByRef)
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
D.getNameAsString());
EmitComplexExprIntoAddr(Init, Loc, isVolatile);
} else {
if (isByRef)
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
D.getNameAsString());
EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true, false));
}
}

View File

@ -1164,12 +1164,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
V = CGM.getStaticLocalDeclAddress(VD);
assert(V && "DeclRefExpr not entered in LocalDeclMap?");
if (VD->hasAttr<BlocksAttr>()) {
V = Builder.CreateStructGEP(V, 1, "forwarding");
V = Builder.CreateLoad(V);
V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
VD->getNameAsString());
}
if (VD->hasAttr<BlocksAttr>())
V = BuildBlockByrefAddress(V, VD);
if (VD->getType()->isReferenceType())
V = Builder.CreateLoad(V, "tmp");

View File

@ -811,7 +811,11 @@ public:
/// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
/// number that holds the value.
unsigned getByRefValueLLVMField(const ValueDecl *VD) const;
/// BuildBlockByrefAddress - Computes address location of the
/// variable which is declared as __block.
llvm::Value *BuildBlockByrefAddress(llvm::Value *BaseAddr,
const VarDecl *V);
private:
CGDebugInfo *DebugInfo;

View File

@ -0,0 +1,12 @@
// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s
// rdar://8893785
void MYFUNC() {
// CHECK: [[T1:%.*]] = bitcast i8* ()*
// CHECK-NEXT: [[FORWARDING:%.*]] = getelementptr inbounds [[N_T:%.*]]* [[N:%.*]], i32 0, i32 1
// CHECK-NEXT: [[T0:%.*]] = load [[N_T]]** [[FORWARDING]]
// CHECK-NEXT: [[OBSERVER:%.*]] = getelementptr inbounds [[N_T]]* [[T0]], i32 0, i32 6
// CHECK-NEXT: store i8* [[T1]], i8** [[OBSERVER]]
__block id observer = ^{ return observer; };
}