@@ -672,8 +672,113 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &CGF, const CXXNewExpr *e,
672
672
size = CGF.getBuilder ().getConstInt (Loc, allocationSize);
673
673
}
674
674
} else {
675
- // TODO: Handle the variable size case
676
- llvm_unreachable (" NYI" );
675
+ // Create a value for the variable number of elements
676
+ numElements = CGF.emitScalarExpr (*e->getArraySize ());
677
+ auto numElementsType = mlir::cast<cir::IntType>(numElements.getType ());
678
+ unsigned numElementsWidth = numElementsType.getWidth ();
679
+
680
+ // We might need check for overflow.
681
+
682
+ mlir::Value hasOverflow = nullptr ;
683
+ // The clang LLVM IR codegen checks for the size variable being signed,
684
+ // having a smaller width than size_t, and having a larger width than
685
+ // size_t. However, the AST implicitly casts the size variable to size_t
686
+ // so none of these conditions will ever be met.
687
+ bool isSigned =
688
+ (*e->getArraySize ())->getType ()->isSignedIntegerOrEnumerationType ();
689
+ assert (!isSigned && (numElementsWidth == sizeWidth) &&
690
+ (numElements.getType () == CGF.SizeTy ) &&
691
+ " Expected array size to be implicitly cast to size_t!" );
692
+
693
+ // There are up to three conditions we need to test for:
694
+ // 1) if minElements > 0, we need to check whether numElements is smaller
695
+ // than that.
696
+ // 2) we need to compute
697
+ // sizeWithoutCookie := numElements * typeSizeMultiplier
698
+ // and check whether it overflows; and
699
+ // 3) if we need a cookie, we need to compute
700
+ // size := sizeWithoutCookie + cookieSize
701
+ // and check whether it overflows.
702
+
703
+ if (minElements) {
704
+ // Don't allow allocation of fewer elements than we have initializers.
705
+ if (!hasOverflow) {
706
+ // FIXME: Avoid creating this twice. It may happen above.
707
+ mlir::Value minElementsV = CGF.getBuilder ().getConstInt (
708
+ Loc, llvm::APInt (sizeWidth, minElements));
709
+ hasOverflow = CGF.getBuilder ().createCompare (Loc, cir::CmpOpKind::lt,
710
+ numElements, minElementsV);
711
+ }
712
+ }
713
+
714
+ size = numElements;
715
+
716
+ // Multiply by the type size if necessary. This multiplier
717
+ // includes all the factors for nested arrays.
718
+ //
719
+ // This step also causes numElements to be scaled up by the
720
+ // nested-array factor if necessary. Overflow on this computation
721
+ // can be ignored because the result shouldn't be used if
722
+ // allocation fails.
723
+ if (typeSizeMultiplier != 1 ) {
724
+ mlir::Value tsmV = CGF.getBuilder ().getConstInt (Loc, typeSizeMultiplier);
725
+ auto mulResult = CGF.getBuilder ().createBinOpOverflowOp (
726
+ Loc, mlir::cast<cir::IntType>(CGF.SizeTy ),
727
+ cir::BinOpOverflowKind::Mul, size, tsmV);
728
+
729
+ if (hasOverflow)
730
+ hasOverflow =
731
+ CGF.getBuilder ().createOr (hasOverflow, mulResult.overflow );
732
+ else
733
+ hasOverflow = mulResult.overflow ;
734
+
735
+ size = mulResult.result ;
736
+
737
+ // Also scale up numElements by the array size multiplier.
738
+ if (arraySizeMultiplier != 1 ) {
739
+ // If the base element type size is 1, then we can re-use the
740
+ // multiply we just did.
741
+ if (typeSize.isOne ()) {
742
+ assert (arraySizeMultiplier == typeSizeMultiplier);
743
+ numElements = size;
744
+
745
+ // Otherwise we need a separate multiply.
746
+ } else {
747
+ mlir::Value asmV =
748
+ CGF.getBuilder ().getConstInt (Loc, arraySizeMultiplier);
749
+ numElements = CGF.getBuilder ().createMul (numElements, asmV);
750
+ }
751
+ }
752
+ } else {
753
+ // numElements doesn't need to be scaled.
754
+ assert (arraySizeMultiplier == 1 );
755
+ }
756
+
757
+ // Add in the cookie size if necessary.
758
+ if (cookieSize != 0 ) {
759
+ sizeWithoutCookie = size;
760
+ mlir::Value cookieSizeV = CGF.getBuilder ().getConstInt (Loc, cookieSize);
761
+ auto addResult = CGF.getBuilder ().createBinOpOverflowOp (
762
+ Loc, mlir::cast<cir::IntType>(CGF.SizeTy ),
763
+ cir::BinOpOverflowKind::Add, size, cookieSizeV);
764
+
765
+ if (hasOverflow)
766
+ hasOverflow =
767
+ CGF.getBuilder ().createOr (hasOverflow, addResult.overflow );
768
+ else
769
+ hasOverflow = addResult.overflow ;
770
+
771
+ size = addResult.result ;
772
+ }
773
+
774
+ // If we had any possibility of dynamic overflow, make a select to
775
+ // overwrite 'size' with an all-ones value, which should cause
776
+ // operator new to throw.
777
+ if (hasOverflow) {
778
+ mlir::Value allOnes =
779
+ CGF.getBuilder ().getConstInt (Loc, llvm::APInt::getAllOnes (sizeWidth));
780
+ size = CGF.getBuilder ().createSelect (Loc, hasOverflow, allOnes, size);
781
+ }
677
782
}
678
783
679
784
if (cookieSize == 0 )
0 commit comments