diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/CodeGen/CGExprCXX.cpp | 307 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 3 |
2 files changed, 173 insertions, 137 deletions
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 548cd488900..c6995d8a1b2 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -749,207 +749,242 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init, } void -CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, - QualType elementType, - llvm::Value *beginPtr, - llvm::Value *numElements) { +CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, + QualType ElementType, + llvm::Value *BeginPtr, + llvm::Value *NumElements, + llvm::Value *AllocSizeWithoutCookie) { + // If we have a type with trivial initialization and no initializer, + // there's nothing to do. if (!E->hasInitializer()) - return; // We have a POD type. + return; - llvm::Value *explicitPtr = beginPtr; - // Find the end of the array, hoisted out of the loop. - llvm::Value *endPtr = - Builder.CreateInBoundsGEP(beginPtr, numElements, "array.end"); + llvm::Value *CurPtr = BeginPtr; - unsigned initializerElements = 0; + unsigned InitListElements = 0; const Expr *Init = E->getInitializer(); - llvm::AllocaInst *endOfInit = nullptr; - QualType::DestructionKind dtorKind = elementType.isDestructedType(); - EHScopeStack::stable_iterator cleanup; - llvm::Instruction *cleanupDominator = nullptr; + llvm::AllocaInst *EndOfInit = nullptr; + QualType::DestructionKind DtorKind = ElementType.isDestructedType(); + EHScopeStack::stable_iterator Cleanup; + llvm::Instruction *CleanupDominator = nullptr; // If the initializer is an initializer list, first do the explicit elements. if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) { - initializerElements = ILE->getNumInits(); + InitListElements = ILE->getNumInits(); // If this is a multi-dimensional array new, we will initialize multiple // elements with each init list element. QualType AllocType = E->getAllocatedType(); if (const ConstantArrayType *CAT = dyn_cast_or_null<ConstantArrayType>( AllocType->getAsArrayTypeUnsafe())) { - unsigned AS = explicitPtr->getType()->getPointerAddressSpace(); + unsigned AS = CurPtr->getType()->getPointerAddressSpace(); llvm::Type *AllocPtrTy = ConvertTypeForMem(AllocType)->getPointerTo(AS); - explicitPtr = Builder.CreateBitCast(explicitPtr, AllocPtrTy); - initializerElements *= getContext().getConstantArrayElementCount(CAT); + CurPtr = Builder.CreateBitCast(CurPtr, AllocPtrTy); + InitListElements *= getContext().getConstantArrayElementCount(CAT); } - // Enter a partial-destruction cleanup if necessary. - if (needsEHCleanup(dtorKind)) { - // In principle we could tell the cleanup where we are more + // Enter a partial-destruction Cleanup if necessary. + if (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 = CreateTempAlloca(beginPtr->getType(), "array.endOfInit"); - cleanupDominator = Builder.CreateStore(beginPtr, endOfInit); - pushIrregularPartialArrayCleanup(beginPtr, endOfInit, elementType, - getDestroyer(dtorKind)); - cleanup = EHStack.stable_begin(); + EndOfInit = CreateTempAlloca(BeginPtr->getType(), "array.init.end"); + CleanupDominator = Builder.CreateStore(BeginPtr, EndOfInit); + pushIrregularPartialArrayCleanup(BeginPtr, EndOfInit, ElementType, + getDestroyer(DtorKind)); + Cleanup = EHStack.stable_begin(); } for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) { // Tell the cleanup that it needs to destroy up to this // element. TODO: some of these stores can be trivially // observed to be unnecessary. - if (endOfInit) Builder.CreateStore(explicitPtr, endOfInit); + if (EndOfInit) + Builder.CreateStore(Builder.CreateBitCast(CurPtr, BeginPtr->getType()), + EndOfInit); + // FIXME: If the last initializer is an incomplete initializer list for + // an array, and we have an array filler, we can fold together the two + // initialization loops. StoreAnyExprIntoOneUnit(*this, ILE->getInit(i), - ILE->getInit(i)->getType(), explicitPtr); - explicitPtr = Builder.CreateConstGEP1_32(explicitPtr, 1, - "array.exp.next"); + ILE->getInit(i)->getType(), CurPtr); + CurPtr = Builder.CreateConstInBoundsGEP1_32(CurPtr, 1, "array.exp.next"); } // The remaining elements are filled with the array filler expression. Init = ILE->getArrayFiller(); - explicitPtr = Builder.CreateBitCast(explicitPtr, beginPtr->getType()); + // Extract the initializer for the individual array elements by pulling + // out the array filler from all the nested initializer lists. This avoids + // generating a nested loop for the initialization. + while (Init && Init->getType()->isConstantArrayType()) { + auto *SubILE = dyn_cast<InitListExpr>(Init); + if (!SubILE) + break; + assert(SubILE->getNumInits() == 0 && "explicit inits in array filler?"); + Init = SubILE->getArrayFiller(); + } + + // Switch back to initializing one base element at a time. + CurPtr = Builder.CreateBitCast(CurPtr, BeginPtr->getType()); } - llvm::ConstantInt *constNum = dyn_cast<llvm::ConstantInt>(numElements); + // Attempt to perform zero-initialization using memset. + auto TryMemsetInitialization = [&]() -> bool { + // FIXME: If the type is a pointer-to-data-member under the Itanium ABI, + // we can initialize with a memset to -1. + if (!CGM.getTypes().isZeroInitializable(ElementType)) + return false; + + // Optimization: since zero initialization will just set the memory + // to all zeroes, generate a single memset to do it in one shot. + + // Subtract out the size of any elements we've already initialized. + auto *RemainingSize = AllocSizeWithoutCookie; + if (InitListElements) { + // We know this can't overflow; we check this when doing the allocation. + auto *InitializedSize = llvm::ConstantInt::get( + RemainingSize->getType(), + getContext().getTypeSizeInChars(ElementType).getQuantity() * + InitListElements); + RemainingSize = Builder.CreateSub(RemainingSize, InitializedSize); + } + + // Create the memset. + CharUnits Alignment = getContext().getTypeAlignInChars(ElementType); + Builder.CreateMemSet(CurPtr, Builder.getInt8(0), RemainingSize, + Alignment.getQuantity(), false); + return true; + }; + + // If this is a constructor call, try to optimize it out, and failing that + // emit a single loop to initialize all remaining elements. + if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){ + CXXConstructorDecl *Ctor = CCE->getConstructor(); + if (Ctor->isTrivial()) { + // If new expression did not specify value-initialization, then there + // is no initialization. + if (!CCE->requiresZeroInitialization() || Ctor->getParent()->isEmpty()) + return; + + if (TryMemsetInitialization()) + return; + } + + // Store the new Cleanup position for irregular Cleanups. + // + // FIXME: Share this cleanup with the constructor call emission rather than + // having it create a cleanup of its own. + if (EndOfInit) Builder.CreateStore(CurPtr, EndOfInit); + + // Emit a constructor call loop to initialize the remaining elements. + if (InitListElements) + NumElements = Builder.CreateSub( + NumElements, + llvm::ConstantInt::get(NumElements->getType(), InitListElements)); + EmitCXXAggrConstructorCall(Ctor, NumElements, CurPtr, + CCE->arg_begin(), CCE->arg_end(), + CCE->requiresZeroInitialization()); + return; + } + + // If this is value-initialization, we can usually use memset. + ImplicitValueInitExpr IVIE(ElementType); + if (Init && isa<ImplicitValueInitExpr>(Init)) { + if (TryMemsetInitialization()) + return; + + // Switch to an ImplicitValueInitExpr for the element type. This handles + // only one case: multidimensional array new of pointers to members. In + // all other cases, we already have an initializer for the array element. + Init = &IVIE; + } + + // At this point we should have found an initializer for the individual + // elements of the array. + assert(getContext().hasSameUnqualifiedType(ElementType, Init->getType()) && + "got wrong type of element to initialize"); + + llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements); // If all elements have already been initialized, skip the whole loop. - if (constNum && constNum->getZExtValue() <= initializerElements) { - // If there was a cleanup, deactivate it. - if (cleanupDominator) - DeactivateCleanupBlock(cleanup, cleanupDominator); + if (ConstNum && ConstNum->getZExtValue() <= InitListElements) { + // If there was a Cleanup, deactivate it. + if (CleanupDominator) + DeactivateCleanupBlock(Cleanup, CleanupDominator); return; } - // Create the continuation block. - llvm::BasicBlock *contBB = createBasicBlock("new.loop.end"); + // Create the loop blocks. + llvm::BasicBlock *EntryBB = Builder.GetInsertBlock(); + llvm::BasicBlock *LoopBB = createBasicBlock("new.loop"); + llvm::BasicBlock *ContBB = createBasicBlock("new.loop.end"); + + // Find the end of the array, hoisted out of the loop. + llvm::Value *EndPtr = + Builder.CreateInBoundsGEP(BeginPtr, NumElements, "array.end"); // If the number of elements isn't constant, we have to now check if there is // anything left to initialize. - if (!constNum) { - llvm::BasicBlock *nonEmptyBB = createBasicBlock("new.loop.nonempty"); - llvm::Value *isEmpty = Builder.CreateICmpEQ(explicitPtr, endPtr, + if (!ConstNum) { + llvm::Value *IsEmpty = Builder.CreateICmpEQ(CurPtr, EndPtr, "array.isempty"); - Builder.CreateCondBr(isEmpty, contBB, nonEmptyBB); - EmitBlock(nonEmptyBB); + Builder.CreateCondBr(IsEmpty, ContBB, LoopBB); } // Enter the loop. - llvm::BasicBlock *entryBB = Builder.GetInsertBlock(); - llvm::BasicBlock *loopBB = createBasicBlock("new.loop"); - - EmitBlock(loopBB); + EmitBlock(LoopBB); // Set up the current-element phi. - llvm::PHINode *curPtr = - Builder.CreatePHI(explicitPtr->getType(), 2, "array.cur"); - curPtr->addIncoming(explicitPtr, entryBB); - - // Store the new cleanup position for irregular cleanups. - if (endOfInit) Builder.CreateStore(curPtr, endOfInit); - - // Enter a partial-destruction cleanup if necessary. - if (!cleanupDominator && needsEHCleanup(dtorKind)) { - pushRegularPartialArrayCleanup(beginPtr, curPtr, elementType, - getDestroyer(dtorKind)); - cleanup = EHStack.stable_begin(); - cleanupDominator = Builder.CreateUnreachable(); + llvm::PHINode *CurPtrPhi = + Builder.CreatePHI(CurPtr->getType(), 2, "array.cur"); + CurPtrPhi->addIncoming(CurPtr, EntryBB); + CurPtr = CurPtrPhi; + + // Store the new Cleanup position for irregular Cleanups. + if (EndOfInit) Builder.CreateStore(CurPtr, EndOfInit); + + // Enter a partial-destruction Cleanup if necessary. + if (!CleanupDominator && needsEHCleanup(DtorKind)) { + pushRegularPartialArrayCleanup(BeginPtr, CurPtr, ElementType, + getDestroyer(DtorKind)); + Cleanup = EHStack.stable_begin(); + CleanupDominator = Builder.CreateUnreachable(); } // Emit the initializer into this element. - StoreAnyExprIntoOneUnit(*this, Init, E->getAllocatedType(), curPtr); + StoreAnyExprIntoOneUnit(*this, Init, Init->getType(), CurPtr); - // Leave the cleanup if we entered one. - if (cleanupDominator) { - DeactivateCleanupBlock(cleanup, cleanupDominator); - cleanupDominator->eraseFromParent(); + // Leave the Cleanup if we entered one. + if (CleanupDominator) { + DeactivateCleanupBlock(Cleanup, CleanupDominator); + CleanupDominator->eraseFromParent(); } - // FIXME: The code below intends to initialize the individual array base - // elements, one at a time - but when dealing with multi-dimensional arrays - - // the pointer arithmetic can get confused - so the fix below entails casting - // to the allocated type to ensure that we get the pointer arithmetic right. - // It seems like the right approach here, it to really initialize the - // individual array base elements one at a time since it'll generate less - // code. I think the problem is that the wrong type is being passed into - // StoreAnyExprIntoOneUnit, but directly fixing that doesn't really work, - // because the Init expression has the wrong type at this point. - // So... this is ok for a quick fix, but we can and should do a lot better - // here long-term. - // Advance to the next element by adjusting the pointer type as necessary. - // For new int[10][20][30], alloc type is int[20][30], base type is 'int'. - QualType AllocType = E->getAllocatedType(); - llvm::Type *AllocPtrTy = ConvertTypeForMem(AllocType)->getPointerTo( - curPtr->getType()->getPointerAddressSpace()); - llvm::Value *curPtrAllocTy = Builder.CreateBitCast(curPtr, AllocPtrTy); - llvm::Value *nextPtrAllocTy = - Builder.CreateConstGEP1_32(curPtrAllocTy, 1, "array.next"); - // Cast it back to the base type so that we can compare it to the endPtr. - llvm::Value *nextPtr = - Builder.CreateBitCast(nextPtrAllocTy, endPtr->getType()); + llvm::Value *NextPtr = + Builder.CreateConstInBoundsGEP1_32(CurPtr, 1, "array.next"); + // Check whether we've gotten to the end of the array and, if so, // exit the loop. - llvm::Value *isEnd = Builder.CreateICmpEQ(nextPtr, endPtr, "array.atend"); - Builder.CreateCondBr(isEnd, contBB, loopBB); - curPtr->addIncoming(nextPtr, Builder.GetInsertBlock()); + llvm::Value *IsEnd = Builder.CreateICmpEQ(NextPtr, EndPtr, "array.atend"); + Builder.CreateCondBr(IsEnd, ContBB, LoopBB); + CurPtrPhi->addIncoming(NextPtr, Builder.GetInsertBlock()); - EmitBlock(contBB); + EmitBlock(ContBB); } -static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T, - llvm::Value *NewPtr, llvm::Value *Size) { - CGF.EmitCastToVoidPtr(NewPtr); - CharUnits Alignment = CGF.getContext().getTypeAlignInChars(T); - CGF.Builder.CreateMemSet(NewPtr, CGF.Builder.getInt8(0), Size, - Alignment.getQuantity(), false); -} - static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, QualType ElementType, llvm::Value *NewPtr, llvm::Value *NumElements, llvm::Value *AllocSizeWithoutCookie) { - const Expr *Init = E->getInitializer(); - if (E->isArray()) { - if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){ - CXXConstructorDecl *Ctor = CCE->getConstructor(); - if (Ctor->isTrivial()) { - // If new expression did not specify value-initialization, then there - // is no initialization. - if (!CCE->requiresZeroInitialization() || Ctor->getParent()->isEmpty()) - return; - - if (CGF.CGM.getTypes().isZeroInitializable(ElementType)) { - // Optimization: since zero initialization will just set the memory - // to all zeroes, generate a single memset to do it in one shot. - EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie); - return; - } - } - - CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, - CCE->arg_begin(), CCE->arg_end(), - CCE->requiresZeroInitialization()); - return; - } else if (Init && isa<ImplicitValueInitExpr>(Init) && - CGF.CGM.getTypes().isZeroInitializable(ElementType)) { - // Optimization: since zero initialization will just set the memory - // to all zeroes, generate a single memset to do it in one shot. - EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie); - return; - } - CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements); - return; - } - - if (!Init) - return; - - StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr); + if (E->isArray()) + CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements, + AllocSizeWithoutCookie); + else if (const Expr *Init = E->getInitializer()) + StoreAnyExprIntoOneUnit(CGF, Init, E->getAllocatedType(), NewPtr); } /// Emit a call to an operator new or operator delete function, as implicitly diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 750bec8b07f..d1e63a710bc 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1647,7 +1647,8 @@ public: llvm::Value *This); void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType, - llvm::Value *NewPtr, llvm::Value *NumElements); + llvm::Value *NewPtr, llvm::Value *NumElements, + llvm::Value *AllocSizeWithoutCookie); void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType, llvm::Value *Ptr); |

