|
12 | 12 |
|
13 | 13 | #include "CIRGenCXXABI.h"
|
14 | 14 | #include "CIRGenFunction.h"
|
| 15 | +#include "CIRGenValue.h" |
15 | 16 |
|
16 | 17 | #include "clang/AST/ExprCXX.h"
|
17 | 18 | #include "clang/AST/RecordLayout.h"
|
@@ -311,6 +312,116 @@ void CIRGenFunction::emitInitializerForField(FieldDecl *field, LValue lhs,
|
311 | 312 | assert(!cir::MissingFeatures::requiresCleanups());
|
312 | 313 | }
|
313 | 314 |
|
| 315 | +/// Emit a loop to call a particular constructor for each of several members |
| 316 | +/// of an array. |
| 317 | +/// |
| 318 | +/// \param ctor the constructor to call for each element |
| 319 | +/// \param arrayType the type of the array to initialize |
| 320 | +/// \param arrayBegin an arrayType* |
| 321 | +/// \param zeroInitialize true if each element should be |
| 322 | +/// zero-initialized before it is constructed |
| 323 | +void CIRGenFunction::emitCXXAggrConstructorCall( |
| 324 | + const CXXConstructorDecl *ctor, const clang::ArrayType *arrayType, |
| 325 | + Address arrayBegin, const CXXConstructExpr *e, bool newPointerIsChecked, |
| 326 | + bool zeroInitialize) { |
| 327 | + QualType elementType; |
| 328 | + mlir::Value numElements = emitArrayLength(arrayType, elementType, arrayBegin); |
| 329 | + emitCXXAggrConstructorCall(ctor, numElements, arrayBegin, e, |
| 330 | + newPointerIsChecked, zeroInitialize); |
| 331 | +} |
| 332 | + |
| 333 | +/// Emit a loop to call a particular constructor for each of several members |
| 334 | +/// of an array. |
| 335 | +/// |
| 336 | +/// \param ctor the constructor to call for each element |
| 337 | +/// \param numElements the number of elements in the array; |
| 338 | +/// may be zero |
| 339 | +/// \param arrayBase a T*, where T is the type constructed by ctor |
| 340 | +/// \param zeroInitialize true if each element should be |
| 341 | +/// zero-initialized before it is constructed |
| 342 | +void CIRGenFunction::emitCXXAggrConstructorCall( |
| 343 | + const CXXConstructorDecl *ctor, mlir::Value numElements, Address arrayBase, |
| 344 | + const CXXConstructExpr *e, bool newPointerIsChecked, bool zeroInitialize) { |
| 345 | + // It's legal for numElements to be zero. This can happen both |
| 346 | + // dynamically, because x can be zero in 'new A[x]', and statically, |
| 347 | + // because of GCC extensions that permit zero-length arrays. There |
| 348 | + // are probably legitimate places where we could assume that this |
| 349 | + // doesn't happen, but it's not clear that it's worth it. |
| 350 | + |
| 351 | + // Optimize for a constant count. |
| 352 | + auto constantCount = dyn_cast<cir::ConstantOp>(numElements.getDefiningOp()); |
| 353 | + if (constantCount) { |
| 354 | + auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constantCount.getValue()); |
| 355 | + // Just skip out if the constant count is zero. |
| 356 | + if (constIntAttr && constIntAttr.getUInt() == 0) |
| 357 | + return; |
| 358 | + } else { |
| 359 | + // Otherwise, emit the check. |
| 360 | + cgm.errorNYI(e->getSourceRange(), "dynamic-length array expression"); |
| 361 | + } |
| 362 | + |
| 363 | + auto arrayTy = mlir::cast<cir::ArrayType>(arrayBase.getElementType()); |
| 364 | + mlir::Type elementType = arrayTy.getElementType(); |
| 365 | + cir::PointerType ptrToElmType = builder.getPointerTo(elementType); |
| 366 | + |
| 367 | + // Tradional LLVM codegen emits a loop here. CIR lowers to a loop as part of |
| 368 | + // LoweringPrepare. |
| 369 | + |
| 370 | + // The alignment of the base, adjusted by the size of a single element, |
| 371 | + // provides a conservative estimate of the alignment of every element. |
| 372 | + // (This assumes we never start tracking offsetted alignments.) |
| 373 | + // |
| 374 | + // Note that these are complete objects and so we don't need to |
| 375 | + // use the non-virtual size or alignment. |
| 376 | + QualType type = getContext().getTypeDeclType(ctor->getParent()); |
| 377 | + CharUnits eltAlignment = arrayBase.getAlignment().alignmentOfArrayElement( |
| 378 | + getContext().getTypeSizeInChars(type)); |
| 379 | + |
| 380 | + // Zero initialize the storage, if requested. |
| 381 | + if (zeroInitialize) |
| 382 | + emitNullInitialization(*currSrcLoc, arrayBase, type); |
| 383 | + |
| 384 | + // C++ [class.temporary]p4: |
| 385 | + // There are two contexts in which temporaries are destroyed at a different |
| 386 | + // point than the end of the full-expression. The first context is when a |
| 387 | + // default constructor is called to initialize an element of an array. |
| 388 | + // If the constructor has one or more default arguments, the destruction of |
| 389 | + // every temporary created in a default argument expression is sequenced |
| 390 | + // before the construction of the next array element, if any. |
| 391 | + { |
| 392 | + assert(!cir::MissingFeatures::runCleanupsScope()); |
| 393 | + |
| 394 | + // Evaluate the constructor and its arguments in a regular |
| 395 | + // partial-destroy cleanup. |
| 396 | + if (getLangOpts().Exceptions && |
| 397 | + !ctor->getParent()->hasTrivialDestructor()) { |
| 398 | + cgm.errorNYI(e->getSourceRange(), "partial array cleanups"); |
| 399 | + } |
| 400 | + |
| 401 | + // Emit the constructor call that will execute for every array element. |
| 402 | + mlir::Value arrayOp = |
| 403 | + builder.createPtrBitcast(arrayBase.getPointer(), arrayTy); |
| 404 | + builder.create<cir::ArrayCtor>( |
| 405 | + *currSrcLoc, arrayOp, [&](mlir::OpBuilder &b, mlir::Location loc) { |
| 406 | + mlir::BlockArgument arg = |
| 407 | + b.getInsertionBlock()->addArgument(ptrToElmType, loc); |
| 408 | + Address curAddr = Address(arg, elementType, eltAlignment); |
| 409 | + assert(!cir::MissingFeatures::sanitizers()); |
| 410 | + auto currAVS = AggValueSlot::forAddr( |
| 411 | + curAddr, type.getQualifiers(), AggValueSlot::IsDestructed, |
| 412 | + AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap, |
| 413 | + AggValueSlot::IsNotZeroed); |
| 414 | + emitCXXConstructorCall(ctor, Ctor_Complete, |
| 415 | + /*ForVirtualBase=*/false, |
| 416 | + /*Delegating=*/false, currAVS, e); |
| 417 | + builder.create<cir::YieldOp>(loc); |
| 418 | + }); |
| 419 | + } |
| 420 | + |
| 421 | + if (constantCount.use_empty()) |
| 422 | + constantCount.erase(); |
| 423 | +} |
| 424 | + |
314 | 425 | void CIRGenFunction::emitDelegateCXXConstructorCall(
|
315 | 426 | const CXXConstructorDecl *ctor, CXXCtorType ctorType,
|
316 | 427 | const FunctionArgList &args, SourceLocation loc) {
|
|
0 commit comments