diff options
author | John McCall <rjmccall@apple.com> | 2011-07-09 01:37:26 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-07-09 01:37:26 +0000 |
commit | bdc4d80956c83a486e58d3df6bb524a1f66ff574 (patch) | |
tree | cdc5066e4d501cf66fb81be3ae37163fba4f890d /lib/CodeGen | |
parent | 6bb31e42076f192f01e92b83297500f62b5eb94c (diff) |
A number of array-related IR-gen cleanups.
- Emit default-initialization of arrays that were partially initialized
with initializer lists with a loop, rather than emitting the default
initializer N times;
- support destroying VLAs of non-trivial type, although this is not
yet exposed to users; and
- support the partial destruction of arrays initialized with
initializer lists when an initializer throws an exception.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134784 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 11 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 270 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 159 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 171 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.cpp | 78 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 56 |
6 files changed, 527 insertions, 218 deletions
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 313ee57f7f..911dbf782f 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1172,6 +1172,17 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, EmitBlock(AfterFor, true); } +void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF, + llvm::Value *addr, + QualType type) { + const RecordType *rtype = type->castAs<RecordType>(); + const CXXRecordDecl *record = cast<CXXRecordDecl>(rtype->getDecl()); + const CXXDestructorDecl *dtor = record->getDestructor(); + assert(!dtor->isTrivial()); + CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false, + addr); +} + /// EmitCXXAggrDestructorCall - calls the default destructor on array /// elements in reverse order of construction. void diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 95294bf8e5..5ce7b3374e 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -304,30 +304,25 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, } namespace { - struct CallArrayDtor : EHScopeStack::Cleanup { - CallArrayDtor(const CXXDestructorDecl *Dtor, - const ConstantArrayType *Type, - llvm::Value *Loc) - : Dtor(Dtor), Type(Type), Loc(Loc) {} + struct DestroyObject : EHScopeStack::Cleanup { + DestroyObject(llvm::Value *addr, QualType type, + CodeGenFunction::Destroyer *destroyer) + : addr(addr), type(type), destroyer(*destroyer) {} - const CXXDestructorDecl *Dtor; - const ConstantArrayType *Type; - llvm::Value *Loc; + llvm::Value *addr; + QualType type; + CodeGenFunction::Destroyer &destroyer; void Emit(CodeGenFunction &CGF, bool IsForEH) { - QualType BaseElementTy = CGF.getContext().getBaseElementType(Type); - const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(Loc, BasePtr); - CGF.EmitCXXAggrDestructorCall(Dtor, Type, BaseAddrPtr); + CGF.emitDestroy(addr, type, destroyer); } }; - struct CallVarDtor : EHScopeStack::Cleanup { - CallVarDtor(const CXXDestructorDecl *Dtor, - llvm::Value *NRVOFlag, - llvm::Value *Loc) - : Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(Loc) {} + struct DestroyNRVOVariable : EHScopeStack::Cleanup { + DestroyNRVOVariable(llvm::Value *addr, + const CXXDestructorDecl *Dtor, + llvm::Value *NRVOFlag) + : Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(addr) {} const CXXDestructorDecl *Dtor; llvm::Value *NRVOFlag; @@ -1014,6 +1009,59 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, } } +/// Enter a destroy cleanup for the given local variable. +void CodeGenFunction::emitAutoVarTypeCleanup( + const CodeGenFunction::AutoVarEmission &emission, + QualType::DestructionKind dtorKind) { + assert(dtorKind != QualType::DK_none); + + // Note that for __block variables, we want to destroy the + // original stack object, not the possibly forwarded object. + llvm::Value *addr = emission.getObjectAddress(*this); + + const VarDecl *var = emission.Variable; + QualType type = var->getType(); + + CleanupKind cleanupKind = NormalAndEHCleanup; + CodeGenFunction::Destroyer *destroyer = 0; + + switch (dtorKind) { + case QualType::DK_none: + llvm_unreachable("no cleanup for trivially-destructible variable"); + + case QualType::DK_cxx_destructor: + // If there's an NRVO flag on the emission, we need a different + // cleanup. + if (emission.NRVOFlag) { + assert(!type->isArrayType()); + CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor(); + EHStack.pushCleanup<DestroyNRVOVariable>(cleanupKind, addr, dtor, + emission.NRVOFlag); + return; + } + break; + + case QualType::DK_objc_strong_lifetime: + // Suppress cleanups for pseudo-strong variables. + if (var->isARCPseudoStrong()) return; + + // Otherwise, consider whether to use an EH cleanup or not. + cleanupKind = getARCCleanupKind(); + + // Use the imprecise destroyer by default. + if (!var->hasAttr<ObjCPreciseLifetimeAttr>()) + destroyer = CodeGenFunction::destroyARCStrongImprecise; + break; + + case QualType::DK_objc_weak_lifetime: + break; + } + + // If we haven't chosen a more specific destroyer, use the default. + if (!destroyer) destroyer = &getDestroyer(dtorKind); + EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer); +} + void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { assert(emission.Variable && "emission was not valid!"); @@ -1022,44 +1070,9 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { const VarDecl &D = *emission.Variable; - // Handle C++ or ARC destruction of variables. - if (getLangOptions().CPlusPlus) { - QualType type = D.getType(); - QualType baseType = getContext().getBaseElementType(type); - if (const RecordType *RT = baseType->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - if (!ClassDecl->hasTrivialDestructor()) { - // Note: We suppress the destructor call when the corresponding NRVO - // flag has been set. - - // Note that for __block variables, we want to destroy the - // original stack object, not the possible forwarded object. - llvm::Value *Loc = emission.getObjectAddress(*this); - - const CXXDestructorDecl *D = ClassDecl->getDestructor(); - assert(D && "EmitLocalBlockVarDecl - destructor is nul"); - - if (type != baseType) { - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(type); - assert(Array && "types changed without array?"); - EHStack.pushCleanup<CallArrayDtor>(NormalAndEHCleanup, - D, Array, Loc); - } else { - EHStack.pushCleanup<CallVarDtor>(NormalAndEHCleanup, - D, emission.NRVOFlag, Loc); - } - } - } - } - - if (Qualifiers::ObjCLifetime lifetime - = D.getType().getQualifiers().getObjCLifetime()) { - if (!D.isARCPseudoStrong()) { - llvm::Value *loc = emission.getObjectAddress(*this); - EmitAutoVarWithLifetime(*this, D, loc, lifetime); - } - } + // Check the type for a cleanup. + if (QualType::DestructionKind dtorKind = D.getType().isDestructedType()) + emitAutoVarTypeCleanup(emission, dtorKind); // In GC mode, honor objc_precise_lifetime. if (getLangOptions().getGCMode() != LangOptions::NonGC && @@ -1084,6 +1097,151 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { enterByrefCleanup(emission); } +CodeGenFunction::Destroyer & +CodeGenFunction::getDestroyer(QualType::DestructionKind kind) { + switch (kind) { + case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor"); + case QualType::DK_cxx_destructor: return destroyCXXObject; + case QualType::DK_objc_strong_lifetime: return destroyARCStrongPrecise; + case QualType::DK_objc_weak_lifetime: return destroyARCWeak; + } +} + +void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr, + QualType type, Destroyer &destroyer) { + EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer); +} + +void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type, + Destroyer &destroyer) { + const ArrayType *arrayType = getContext().getAsArrayType(type); + if (!arrayType) + return destroyer(*this, addr, type); + + llvm::Value *begin = addr; + llvm::Value *length = emitArrayLength(arrayType, type, begin); + llvm::Value *end = Builder.CreateInBoundsGEP(begin, length); + emitArrayDestroy(begin, end, type, destroyer); +} + +void CodeGenFunction::emitArrayDestroy(llvm::Value *begin, + llvm::Value *end, + QualType type, + Destroyer &destroyer) { + assert(!type->isArrayType()); + + // The basic structure here is a do-while loop, because we don't + // need to check for the zero-element case. + llvm::BasicBlock *bodyBB = createBasicBlock("arraydestroy.body"); + llvm::BasicBlock *doneBB = createBasicBlock("arraydestroy.done"); + + // Enter the loop body, making that address the current address. + llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); + EmitBlock(bodyBB); + llvm::PHINode *elementPast = + Builder.CreatePHI(begin->getType(), 2, "arraydestroy.elementPast"); + elementPast->addIncoming(end, entryBB); + + // Shift the address back by one element. + llvm::Value *negativeOne = llvm::ConstantInt::get(SizeTy, -1, true); + llvm::Value *element = Builder.CreateInBoundsGEP(elementPast, negativeOne, + "arraydestroy.element"); + + // Perform the actual destruction there. + destroyer(*this, element, type); + + // Check whether we've reached the end. + llvm::Value *done = Builder.CreateICmpEQ(element, begin, "arraydestroy.done"); + Builder.CreateCondBr(done, doneBB, bodyBB); + elementPast->addIncoming(element, Builder.GetInsertBlock()); + + // Done. + EmitBlock(doneBB); +} + +namespace { + class PartialArrayDestroy : public EHScopeStack::Cleanup { + llvm::Value *ArrayBegin; + llvm::Value *ArrayEndPointer; + QualType ElementType; + CodeGenFunction::Destroyer &Destroyer; + public: + PartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEndPointer, + QualType elementType, + CodeGenFunction::Destroyer *destroyer) + : ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer), + ElementType(elementType), Destroyer(*destroyer) {} + + void Emit(CodeGenFunction &CGF, bool isForEH) { + llvm::Value *arrayBegin = ArrayBegin; + llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer); + + // It's possible for the count to be zero here, so we're going + // to need a check. For the sake of prettier IR, we just want + // to jump to the end of the array destroy loop. This assumes + // the structure of the IR generated by emitArrayDestroy, but + // that assumption is pretty reliable. + llvm::Value *earlyTest = + CGF.Builder.CreateICmpEQ(arrayBegin, arrayEnd, "pad.isempty"); + + llvm::BasicBlock *nextBB = CGF.createBasicBlock("pad.arraydestroy"); + + // For now, use a conditional branch with both successors the + // same. We'll patch this later. + llvm::BranchInst *br = + CGF.Builder.CreateCondBr(earlyTest, nextBB, nextBB); + CGF.EmitBlock(nextBB); + + llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); + + // If the element type is itself an array, drill down. + QualType type = ElementType; + llvm::SmallVector<llvm::Value*,4> gepIndices; + gepIndices.push_back(zero); + while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) { + // VLAs don't require a GEP index to walk into. + if (!isa<VariableArrayType>(arrayType)) + gepIndices.push_back(zero); + type = arrayType->getElementType(); + } + if (gepIndices.size() != 1) { + arrayBegin = + CGF.Builder.CreateInBoundsGEP(arrayBegin, gepIndices.begin(), + gepIndices.end(), "pad.arraybegin"); + arrayEnd = + CGF.Builder.CreateInBoundsGEP(arrayEnd, gepIndices.begin(), + gepIndices.end(), "pad.arrayend"); + } + + CGF.emitArrayDestroy(arrayBegin, arrayEnd, type, Destroyer); + + // Set the conditional branch's 'false' successor to doneBB. + llvm::BasicBlock *doneBB = CGF.Builder.GetInsertBlock(); + assert(CGF.Builder.GetInsertPoint() == doneBB->begin()); + br->setSuccessor(1, doneBB); + } + }; +} + +/// pushPartialArrayCleanup - Push a cleanup to destroy +/// already-constructed elements of the given array. The cleanup +/// may be popped with DeactivateCleanupBlock. +/// +/// \param elementType - the immediate element type of the array; +/// possibly still an array type +/// \param array - a value of type elementType* +/// \param destructionKind - the kind of destruction required +/// \param initializedElementCount - a value of type size_t* holding +/// the number of successfully-constructed elements +void CodeGenFunction::pushPartialArrayCleanup(llvm::Value *array, + QualType elementType, + Destroyer &destroyer, + llvm::Value *arrayEndPointer) { + // FIXME: can this be in a conditional expression? + EHStack.pushCleanup<PartialArrayDestroy>(EHCleanup, array, arrayEndPointer, + elementType, &destroyer); +} + namespace { /// A cleanup to perform a release of an object at the end of a /// function. This is used to balance out the incoming +1 of a diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 93f93b77e8..1d473f6012 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -661,45 +661,132 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { } uint64_t NumArrayElements = AType->getNumElements(); - QualType ElementType = CGF.getContext().getCanonicalType(E->getType()); - ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType(); - ElementType = CGF.getContext().getQualifiedType(ElementType, - Dest.getQualifiers()); - - bool hasNonTrivialCXXConstructor = false; - if (CGF.getContext().getLangOptions().CPlusPlus) - if (const RecordType *RT = CGF.getContext() - .getBaseElementType(ElementType)->getAs<RecordType>()) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor(); - } + assert(NumInitElements <= NumArrayElements); + + QualType elementType = E->getType().getCanonicalType(); + elementType = CGF.getContext().getQualifiedType( + cast<ArrayType>(elementType)->getElementType(), + elementType.getQualifiers() + Dest.getQualifiers()); + + // DestPtr is an array*. Construct an elementType* by drilling + // down a level. + llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); + llvm::Value *indices[] = { zero, zero }; + llvm::Value *begin = + Builder.CreateInBoundsGEP(DestPtr, indices, indices+2, "arrayinit.begin"); + + // Exception safety requires us to destroy all the + // already-constructed members if an initializer throws. + // For that, we'll need an EH cleanup. + QualType::DestructionKind dtorKind = elementType.isDestructedType(); + llvm::AllocaInst *endOfInit = 0; + EHScopeStack::stable_iterator cleanup; + if (CGF.needsEHCleanup(dtorKind)) { + // In principle we could tell the cleanup where we are more + // directly, but the control flow can get so varied here that it + // would actually be quite complex. Therefore we go through an + // alloca. + endOfInit = CGF.CreateTempAlloca(begin->getType(), + "arrayinit.endOfInit"); + Builder.CreateStore(begin, endOfInit); + CGF.pushPartialArrayCleanup(begin, elementType, + CGF.getDestroyer(dtorKind), endOfInit); + cleanup = CGF.EHStack.stable_begin(); + + // Otherwise, remember that we didn't need a cleanup. + } else { + dtorKind = QualType::DK_none; + } - for (uint64_t i = 0; i != NumArrayElements; ++i) { - // If we're done emitting initializers and the destination is known-zeroed - // then we're done. - if (i == NumInitElements && - Dest.isZeroed() && - CGF.getTypes().isZeroInitializable(ElementType) && - !hasNonTrivialCXXConstructor) - break; - - llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array"); - LValue LV = CGF.MakeAddrLValue(NextVal, ElementType); - - if (i < NumInitElements) - EmitInitializationToLValue(E->getInit(i), LV); - else if (Expr *filler = E->getArrayFiller()) - EmitInitializationToLValue(filler, LV); + llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1); + + // The 'current element to initialize'. The invariants on this + // variable are complicated. Essentially, after each iteration of + // the loop, it points to the last initialized element, except + // that it points to the beginning of the array before any + // elements have been initialized. + llvm::Value *element = begin; + + // Emit the explicit initializers. + for (uint64_t i = 0; i != NumInitElements; ++i) { + // Advance to the next element. + if (i > 0) + element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element"); + + LValue elementLV = CGF.MakeAddrLValue(element, elementType); + EmitInitializationToLValue(E->getInit(i), elementLV); + + // Tell the cleanup that it needs to destroy this element. + // TODO: some of these stores can be trivially observed to be + // unnecessary. + if (endOfInit) Builder.CreateStore(element, endOfInit); + } + + // Check whether there's a non-trivial array-fill expression. + // Note that this will be a CXXConstructExpr even if the element + // type is an array (or array of array, etc.) of class type. + Expr *filler = E->getArrayFiller(); + bool hasTrivialFiller = true; + if (CXXConstructExpr *cons = dyn_cast_or_null<CXXConstructExpr>(filler)) { + assert(cons->getConstructor()->isDefaultConstructor()); + hasTrivialFiller = cons->getConstructor()->isTrivial(); + } + + // Any remaining elements need to be zero-initialized, possibly + // using the filler expression. We can skip this if the we're + // emitting to zeroed memory. + if (NumInitElements != NumArrayElements && + !(Dest.isZeroed() && hasTrivialFiller && + CGF.getTypes().isZeroInitializable(elementType))) { + + // Use an actual loop. This is basically + // do { *array++ = filler; } while (array != end); + + // Advance to the start of the rest of the array. + if (NumInitElements) + element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start"); + + // Compute the end of the array. + llvm::Value *end = Builder.CreateInBoundsGEP(begin, + llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements), + "arrayinit.end"); + + llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); + llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body"); + + // Jump into the body. + CGF.EmitBlock(bodyBB); + llvm::PHINode *currentElement = + Builder.CreatePHI(element->getType(), 2, "arrayinit.cur"); + currentElement->addIncoming(element, entryBB); + + // Emit the actual filler expression. + LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType); + if (filler) + EmitInitializationToLValue(filler, elementLV); else - EmitNullInitializationToLValue(LV); - - // If the GEP didn't get used because of a dead zero init or something - // else, clean it up for -O0 builds and general tidiness. - if (llvm::GetElementPtrInst *GEP = - dyn_cast<llvm::GetElementPtrInst>(NextVal)) - if (GEP->use_empty()) - GEP->eraseFromParent(); + EmitNullInitializationToLValue(elementLV); + + // Tell the EH cleanup that we finished with that element. + if (endOfInit) Builder.CreateStore(element, endOfInit); + + // Move on to the next element. + llvm::Value *nextElement = + Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next"); + + // Leave the loop if we're done. + llvm::Value *done = Builder.CreateICmpEQ(nextElement, end, + "arrayinit.done"); + llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end"); + Builder.CreateCondBr(done, endBB, bodyBB); + currentElement->addIncoming(nextElement, Builder.GetInsertBlock()); + + CGF.EmitBlock(endBB); } + + // Leave the partial-array cleanup if we entered one. + if (dtorKind) CGF.DeactivateCleanupBlock(cleanup); + return; } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 1b271ef2af..be38d36f6c 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -1807,25 +1807,43 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) { getContext().VoidTy, DrainSel, Arg, Args); } +void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF, + llvm::Value *addr, + QualType type) { + llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy"); + CGF.EmitARCRelease(ptr, /*precise*/ true); +} + +void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF, + llvm::Value *addr, + QualType type) { + llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy"); + CGF.EmitARCRelease(ptr, /*precise*/ false); +} + +void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF, + llvm::Value *addr, + QualType type) { + CGF.EmitARCDestroyWeak(addr); +} + namespace { struct ObjCReleasingCleanup : EHScopeStack::Cleanup { private: QualType type; llvm::Value *addr; + CodeGenFunction::Destroyer &destroyer; protected: - ObjCReleasingCleanup(QualType type, llvm::Value *addr) - : type(type), addr(addr) {} + ObjCReleasingCleanup(QualType type, llvm::Value *addr, + CodeGenFunction::Destroyer *destroyer) + : type(type), addr(addr), destroyer(*destroyer) {} virtual llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *addr) { return addr; } - virtual void release(CodeGenFunction &CGF, - QualType type, - llvm::Value *addr) = 0; - public: void Emit(CodeGenFunction &CGF, bool isForEH) { const ArrayType *arrayType = CGF.getContext().getAsArrayType(type); @@ -1834,14 +1852,13 @@ namespace { // If we don't have an array type, this is easy. if (!arrayType) - return release(CGF, type, addr); + return destroyer(CGF, addr, type); llvm::Value *begin = addr; QualType baseType; // Otherwise, this is more painful. - llvm::Value *count = emitArrayLength(CGF, arrayType, baseType, - begin); + llvm::Value *count = CGF.emitArrayLength(arrayType, baseType, begin); assert(baseType == CGF.getContext().getBaseElementType(arrayType)); @@ -1867,7 +1884,7 @@ namespace { CGF.EmitBlock(bodyBB); // Release the value at 'cur'. - release(CGF, baseType, cur); + destroyer(CGF, cur, baseType); // ++cur; // goto loopBB; @@ -1878,112 +1895,18 @@ namespace { // endBB: CGF.EmitBlock(endBB); } - - private: - /// Computes the length of an array in elements, as well - /// as the base - static llvm::Value *emitArrayLength(CodeGenFunction &CGF, - const ArrayType *origArrayType, - QualType &baseType, - llvm::Value *&addr) { - ASTContext &Ctx = CGF.getContext(); - const ArrayType *arrayType = origArrayType; - - // If it's a VLA, we have to load the stored size. Note that - // this is the size of the VLA in bytes, not its size in elements. - llvm::Value *numVLAElements = 0; - if (isa<VariableArrayType>(arrayType)) { - numVLAElements = - CGF.getVLASize(cast<VariableArrayType>(arrayType)).first; - - // Walk into all VLAs. This doesn't require changes to addr, - // which has type T* where T is the first non-VLA element type. - do { - QualType elementType = arrayType->getElementType(); - arrayType = Ctx.getAsArrayType(elementType); - - // If we only have VLA components, 'addr' requires no adjustment. - if (!arrayType) { - baseType = elementType; - return numVLAElements; - } - } while (isa<VariableArrayType>(arrayType)); - - // We get out here only if we find a constant array type - // inside the VLA. - } - - // We have some number of constant-length arrays, so addr should - // have LLVM type [M x [N x [...]]]*. Build a GEP that walks - // down to the first element of addr. - llvm::SmallVector<llvm::Value*, 8> gepIndices; - - // GEP down to the array type. - llvm::ConstantInt *zero = CGF.Builder.getInt32(0); - gepIndices.push_back(zero); - - // It's more efficient to calculate the count from the LLVM - // constant-length arrays than to re-evaluate the array bounds. - uint64_t countFromCLAs = 1; - - const llvm::ArrayType *llvmArrayType = - cast<llvm::ArrayType>( - cast<llvm::PointerType>(addr->getType())->getElementType()); - while (true) { - assert(isa<ConstantArrayType>(arrayType)); - assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue() - == llvmArrayType->getNumElements()); - - gepIndices.push_back(zero); - countFromCLAs *= llvmArrayType->getNumElements(); - - llvmArrayType = - dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType()); - if (!llvmArrayType) break; - - arrayType = Ctx.getAsArrayType(arrayType->getElementType()); - assert(arrayType && "LLVM and Clang types are out-of-synch"); - } - - baseType = arrayType->getElementType(); - - // Create the actual GEP. - addr = CGF.Builder.CreateInBoundsGEP(addr, gepIndices.begin(), - gepIndices.end(), "array.begin"); - - llvm::Value *numElements - = llvm::ConstantInt::get(CGF.IntPtrTy, countFromCLAs); - - // If we had any VLA dimensions, factor them in. - if (numVLAElements) - numElements = CGF.Builder.CreateNUWMul(numVLAElements, numElements); - - return numElements; - } - - static llvm::Value *divideVLASizeByBaseType(CodeGenFunction &CGF, - llvm::Value *vlaSizeInBytes, - QualType baseType) { - // Divide the base type size back out of the - CharUnits baseSize = CGF.getContext().getTypeSizeInChars(baseType); - llvm::Value *baseSizeInBytes = - llvm::ConstantInt::get(vlaSizeInBytes->getType(), - baseSize.getQuantity()); - - return CGF.Builder.CreateUDiv(vlaSizeInBytes, baseSizeInBytes, - "array.vla-count"); - } }; /// A cleanup that calls @objc_release on all the objects to release. struct CallReleaseForObject : ObjCReleasingCleanup { - bool precise; - CallReleaseForObject(QualType type, llvm::Value *addr, bool precise) - : ObjCReleasingCleanup(type, addr), precise(precise) {} + CallReleaseForObject(QualType type, llvm::Value *addr, + CodeGenFunction::Destroyer *destroyer) + : ObjCReleasingCleanup(type, addr, destroyer) {} using ObjCReleasingCleanup::Emit; static void Emit(CodeGenFunction &CGF, bool IsForEH, - QualType type, llvm::Value *addr, bool precise) { + QualType type, llvm::Value *addr, + CodeGenFunction::Destroyer *destroyer) { // EHScopeStack::Cleanup objects can never have their destructors called, // so use placement new to construct our temporary object. union { @@ -1992,15 +1915,10 @@ namespace { }; CallReleaseForObject *Object - = new (&align) CallReleaseForObject(type, addr, precise); + = new (&align) CallReleaseForObject(type, addr, destroyer); Object->Emit(CGF, IsForEH); (void)data[0]; } - - void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) { - llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "tmp"); - CGF.EmitARCRelease(ptr, precise); - } }; /// A cleanup that calls @objc_storeStrong(nil) on all the objects to @@ -2008,7 +1926,8 @@ namespace { struct CallReleaseForIvar : ObjCReleasingCleanup { const ObjCIvarDecl *ivar; CallReleaseForIvar(const ObjCIvarDecl *ivar, llvm::Value *self) - : ObjCReleasingCleanup(ivar->getType(), self), ivar(ivar) {} + : ObjCReleasingCleanup(ivar->getType(), self, + destroyARCStrongIvar), ivar(ivar) {} llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *addr) { LValue lvalue @@ -2016,8 +1935,9 @@ namespace { return lvalue.getAddress(); } - void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) { - // Release ivars by storing nil into them; it just makes things easier. + static void destroyARCStrongIvar(CodeGenFunction &CGF, + llvm::Value *addr, + QualType type) { llvm::Value *null = getNullForVariable(addr); CGF.EmitARCStoreStrongCall(addr, null, /*ignored*/ true); } @@ -2029,7 +1949,8 @@ namespace { const FieldDecl *Field; explicit CallReleaseForField(const FieldDecl *Field) - : CallReleaseForObject(Field->getType(), 0, /*precise=*/true), + : CallReleaseForObject(Field->getType(), 0, + CodeGenFunction::destroyARCStrongPrecise), Field(Field) { } llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *) { @@ -2043,7 +1964,7 @@ namespace { /// release in an object. struct CallWeakReleaseForObject : ObjCReleasingCleanup { CallWeakReleaseForObject(QualType type, llvm::Value *addr) - : ObjCReleasingCleanup(type, addr) {} + : ObjCReleasingCleanup(type, addr, CodeGenFunction::destroyARCWeak) {} using ObjCReleasingCleanup::Emit; static void Emit(CodeGenFunction &CGF, bool IsForEH, @@ -2060,10 +1981,6 @@ namespace { Object->Emit(CGF, IsForEH); (void)data[0]; } - - void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) { - CGF.EmitARCDestroyWeak(addr); - } }; @@ -2129,10 +2046,12 @@ void CodeGenFunction::PushARCReleaseCleanup(CleanupKind cleanupKind, llvm::Value *addr, bool precise, bool forFullExpr) { + Destroyer *dtor = + (precise ? destroyARCStrongPrecise : destroyARCStrongImprecise); if (forFullExpr) - pushFullExprCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise); + pushFullExprCleanup<CallReleaseForObject>(cleanupKind, type, addr, dtor); else - EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise); + EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, dtor); } /// PushARCWeakReleaseCleanup - Enter a cleanup to perform a weak diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 43e07e24fc..596358bee5 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -785,6 +785,84 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { return IndirectBranch->getParent(); } +/// Computes the length of an array in elements, as well as the base +/// element type and a properly-typed first element pointer. +llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, + QualType &baseType, + llvm::Value *&addr) { + const ArrayType *arrayType = origArrayType; + + // If it's a VLA, we have to load the stored size. Note that + // this is the size of the VLA in bytes, not its size in elements. + llvm::Value *numVLAElements = 0; + if (isa<VariableArrayType>(arrayType)) { + numVLAElements = getVLASize(cast<VariableArrayType>(arrayType)).first; + + // Walk into all VLAs. This doesn't require changes to addr, + // which has type T* where T is the first non-VLA element type. + do { + QualType elementType = arrayType->getElementType(); + arrayType = getContext().getAsArrayType(elementType); + + // If we only have VLA components, 'addr' requires no adjustment. + if (!arrayType) { + baseType = elementType; + return numVLAElements; + } + } while (isa<VariableArrayType>(arrayType)); + + // We get out here only if we find a constant array type + // inside the VLA. + } + + // We have some number of constant-length arrays, so addr should + // have LLVM type [M x [N x [...]]]*. Build a GEP that walks + // down to the first element of addr. + llvm::SmallVector<llvm::Value*, 8> gepIndices; + + // GEP down to the array type. + llvm::ConstantInt *zero = Builder.getInt32(0); + gepIndices.push_back(zero); + + // It's more efficient to calculate the count from the LLVM + // constant-length arrays than to re-evaluate the array bounds. + uint64_t countFromCLAs = 1; + + const llvm::ArrayType *llvmArrayType = + cast<llvm::ArrayType>( + cast<llvm::PointerType>(addr->getType())->getElementType()); + while (true) { + assert(isa<ConstantArrayType>(arrayType)); + assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue() + == llvmArrayType->getNumElements()); + + gepIndices.push_back(zero); + countFromCLAs *= llvmArrayType->getNumElements(); + + llvmArrayType = + dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType()); + if (!llvmArrayType) break; + + arrayType = getContext().getAsArrayType(arrayType->getElementType()); + assert(arrayType && "LLVM and Clang types are out-of-synch"); + } + + baseType = arrayType->getElementType(); + + // Create the actual GEP. + addr = Builder.CreateInBoundsGEP(addr, gepIndices.begin(), + gepIndices.end(), "array.begin"); + + llvm::Value *numElements + = llvm::ConstantInt::get(SizeTy, countFromCLAs); + + // If we had any VLA dimensions, factor them in. + if (numVLAElements) + numElements = Builder.CreateNUWMul(numVLAElements, numElements); + + return numElements; +} + std::pair<llvm::Value*, QualType> CodeGenFunction::getVLASize(QualType type) { const VariableArrayType * |