@@ -148,6 +148,10 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
148
148
void buildCopy (QualType type, const AggValueSlot &dest,
149
149
const AggValueSlot &src);
150
150
151
+ void buildArrayInit (Address DestPtr, mlir::cir::ArrayType AType,
152
+ QualType ArrayQTy, Expr *ExprToVisit,
153
+ ArrayRef<Expr *> Args, Expr *ArrayFiller);
154
+
151
155
AggValueSlot::NeedsGCBarriers_t needsGC (QualType T) {
152
156
if (CGF.getLangOpts ().getGC () && TypeRequiresGCollection (T))
153
157
llvm_unreachable (" garbage collection is NYI" );
@@ -394,6 +398,113 @@ void AggExprEmitter::buildCopy(QualType type, const AggValueSlot &dest,
394
398
CGF.buildAggregateCopy (DestLV, SrcLV, type, dest.mayOverlap (), false );
395
399
}
396
400
401
+ // FIXME(cir): This function could be shared with traditional LLVM codegen
402
+ // / Determine if E is a trivial array filler, that is, one that is
403
+ // / equivalent to zero-initialization.
404
+ static bool isTrivialFiller (Expr *E) {
405
+ if (!E)
406
+ return true ;
407
+
408
+ if (isa<ImplicitValueInitExpr>(E))
409
+ return true ;
410
+
411
+ if (auto *ILE = dyn_cast<InitListExpr>(E)) {
412
+ if (ILE->getNumInits ())
413
+ return false ;
414
+ return isTrivialFiller (ILE->getArrayFiller ());
415
+ }
416
+
417
+ if (auto *Cons = dyn_cast_or_null<CXXConstructExpr>(E))
418
+ return Cons->getConstructor ()->isDefaultConstructor () &&
419
+ Cons->getConstructor ()->isTrivial ();
420
+
421
+ // FIXME: Are there other cases where we can avoid emitting an initializer?
422
+ return false ;
423
+ }
424
+
425
+ void AggExprEmitter::buildArrayInit (Address DestPtr, mlir::cir::ArrayType AType,
426
+ QualType ArrayQTy, Expr *ExprToVisit,
427
+ ArrayRef<Expr *> Args, Expr *ArrayFiller) {
428
+ uint64_t NumInitElements = Args.size ();
429
+
430
+ uint64_t NumArrayElements = AType.getSize ();
431
+ assert (NumInitElements != 0 && " expected at least one initializaed value" );
432
+ assert (NumInitElements <= NumArrayElements);
433
+
434
+ QualType elementType =
435
+ CGF.getContext ().getAsArrayType (ArrayQTy)->getElementType ();
436
+
437
+ auto cirElementType = CGF.convertType (elementType);
438
+ auto cirElementPtrType = mlir::cir::PointerType::get (
439
+ CGF.getBuilder ().getContext (), cirElementType);
440
+ auto loc = CGF.getLoc (ExprToVisit->getSourceRange ());
441
+
442
+ // Cast from cir.ptr<cir.array<elementType> to cir.ptr<elementType>
443
+ auto begin = CGF.getBuilder ().create <mlir::cir::CastOp>(
444
+ loc, cirElementPtrType, mlir::cir::CastKind::array_to_ptrdecay,
445
+ DestPtr.getPointer ());
446
+
447
+ CharUnits elementSize = CGF.getContext ().getTypeSizeInChars (elementType);
448
+ CharUnits elementAlign =
449
+ DestPtr.getAlignment ().alignmentOfArrayElement (elementSize);
450
+
451
+ // Exception safety requires us to destroy all the
452
+ // already-constructed members if an initializer throws.
453
+ // For that, we'll need an EH cleanup.
454
+ [[maybe_unused]] QualType::DestructionKind dtorKind =
455
+ elementType.isDestructedType ();
456
+ [[maybe_unused]] Address endOfInit = Address::invalid ();
457
+ assert (!CGF.needsEHCleanup (dtorKind) && " destructed types NIY" );
458
+
459
+ // The 'current element to initialize'. The invariants on this
460
+ // variable are complicated. Essentially, after each iteration of
461
+ // the loop, it points to the last initialized element, except
462
+ // that it points to the beginning of the array before any
463
+ // elements have been initialized.
464
+ mlir::Value element = begin;
465
+
466
+ // Don't build the 'one' before the cycle to avoid
467
+ // emmiting the redundant cir.const(1) instrs.
468
+ mlir::Value one;
469
+
470
+ // Emit the explicit initializers.
471
+ for (uint64_t i = 0 ; i != NumInitElements; ++i) {
472
+ if (i == 1 )
473
+ one = CGF.getBuilder ().getConstInt (
474
+ loc, CGF.PtrDiffTy .cast <mlir::cir::IntType>(), 1 );
475
+
476
+ // Advance to the next element.
477
+ if (i > 0 ) {
478
+ element = CGF.getBuilder ().create <mlir::cir::PtrStrideOp>(
479
+ loc, cirElementPtrType, element, one);
480
+
481
+ // Tell the cleanup that it needs to destroy up to this
482
+ // element. TODO: some of these stores can be trivially
483
+ // observed to be unnecessary.
484
+ assert (!endOfInit.isValid () && " destructed types NIY" );
485
+ }
486
+
487
+ LValue elementLV = CGF.makeAddrLValue (
488
+ Address (element, cirElementType, elementAlign), elementType);
489
+ buildInitializationToLValue (Args[i], elementLV);
490
+ }
491
+
492
+ // Check whether there's a non-trivial array-fill expression.
493
+ bool hasTrivialFiller = isTrivialFiller (ArrayFiller);
494
+
495
+ // Any remaining elements need to be zero-initialized, possibly
496
+ // using the filler expression. We can skip this if the we're
497
+ // emitting to zeroed memory.
498
+ if (NumInitElements != NumArrayElements &&
499
+ !(Dest.isZeroed () && hasTrivialFiller &&
500
+ CGF.getTypes ().isZeroInitializable (elementType))) {
501
+ llvm_unreachable (" zero-initialization of arrays NIY" );
502
+ }
503
+
504
+ // Leave the partial-array cleanup if we entered one.
505
+ assert (!dtorKind && " destructed types NIY" );
506
+ }
507
+
397
508
// / True if the given aggregate type requires special GC API calls.
398
509
bool AggExprEmitter::TypeRequiresGCollection (QualType T) {
399
510
// Only record types have members that might require garbage collection.
@@ -888,6 +999,16 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
888
999
LValue DestLV = CGF.makeAddrLValue (Dest.getAddress (), ExprToVisit->getType ());
889
1000
890
1001
// Handle initialization of an array.
1002
+ if (ExprToVisit->getType ()->isConstantArrayType ()) {
1003
+ auto AType = cast<mlir::cir::ArrayType>(Dest.getAddress ().getElementType ());
1004
+ buildArrayInit (Dest.getAddress (), AType, ExprToVisit->getType (),
1005
+ ExprToVisit, InitExprs, ArrayFiller);
1006
+ return ;
1007
+ } else if (ExprToVisit->getType ()->isVariableArrayType ()) {
1008
+ llvm_unreachable (" variable arrays NYI" );
1009
+ return ;
1010
+ }
1011
+
891
1012
if (ExprToVisit->getType ()->isArrayType ()) {
892
1013
llvm_unreachable (" NYI" );
893
1014
}
0 commit comments