@@ -534,39 +534,97 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
534534 // Create a value for the variable number of elements
535535 numElements = cgf.emitScalarExpr (*e->getArraySize ());
536536 auto numElementsType = mlir::cast<cir::IntType>(numElements.getType ());
537- [[maybe_unused]] unsigned numElementsWidth = numElementsType.getWidth ();
538-
539- // We might need check for overflow.
540-
541- mlir::Value hasOverflow;
542- // Classic codegen checks for the size variable being signed, having a
543- // smaller width than size_t, and having a larger width than size_t.
544- // However, the AST implicitly casts the size variable to size_t so none of
545- // these conditions will ever be met.
546- assert (
547- !(*e->getArraySize ())->getType ()->isSignedIntegerOrEnumerationType () &&
548- (numElementsWidth == sizeWidth) &&
549- (numElements.getType () == cgf.sizeTy ) &&
550- " Expected array size to be implicitly cast to size_t!" );
551-
552- // There are up to three conditions we need to test for:
553- // 1) if minElements > 0, we need to check whether numElements is smaller
537+ unsigned numElementsWidth = numElementsType.getWidth ();
538+
539+ // The number of elements can have an arbitrary integer type;
540+ // essentially, we need to multiply it by a constant factor, add a
541+ // cookie size, and verify that the result is representable as a
542+ // size_t. That's just a gloss, though, and it's wrong in one
543+ // important way: if the count is negative, it's an error even if
544+ // the cookie size would bring the total size >= 0.
545+ bool isSigned =
546+ (*e->getArraySize ())->getType ()->isSignedIntegerOrEnumerationType ();
547+
548+ // There are up to five conditions we need to test for:
549+ // 1) if isSigned, we need to check whether numElements is negative;
550+ // 2) if numElementsWidth > sizeWidth, we need to check whether
551+ // numElements is larger than something representable in size_t;
552+ // 3) if minElements > 0, we need to check whether numElements is smaller
554553 // than that.
555- // 2 ) we need to compute
554+ // 4 ) we need to compute
556555 // sizeWithoutCookie := numElements * typeSizeMultiplier
557556 // and check whether it overflows; and
558- // 3 ) if we need a cookie, we need to compute
557+ // 5 ) if we need a cookie, we need to compute
559558 // size := sizeWithoutCookie + cookieSize
560559 // and check whether it overflows.
561560
561+ mlir::Value hasOverflow;
562+
563+ // If numElementsWidth > sizeWidth, then one way or another, we're
564+ // going to have to do a comparison for (2), and this happens to
565+ // take care of (1), too.
566+ if (numElementsWidth > sizeWidth) {
567+ llvm::APInt threshold =
568+ llvm::APInt::getOneBitSet (numElementsWidth, sizeWidth);
569+
570+ // Use an unsigned comparison regardless of the sign of numElements.
571+ mlir::Value unsignedNumElements = numElements;
572+ if (isSigned)
573+ unsignedNumElements = cgf.getBuilder ().createIntCast (
574+ numElements, cgf.getBuilder ().getUIntNTy (numElementsWidth));
575+
576+ mlir::Value thresholdV =
577+ cgf.getBuilder ().getConstInt (loc, threshold, /* isUnsigned=*/ true );
578+ hasOverflow = cgf.getBuilder ().createCompare (
579+ loc, cir::CmpOpKind::ge, unsignedNumElements, thresholdV);
580+ numElements = cgf.getBuilder ().createIntCast (
581+ unsignedNumElements, mlir::cast<cir::IntType>(cgf.sizeTy ));
582+
583+ // Otherwise, if we're signed, we want to sext up to size_t.
584+ } else if (isSigned) {
585+ if (numElementsWidth < sizeWidth)
586+ numElements = cgf.getBuilder ().createIntCast (
587+ numElements, cgf.getBuilder ().getSIntNTy (sizeWidth));
588+
589+ // If there's a non-1 type size multiplier, then we can do the
590+ // signedness check at the same time as we do the multiply
591+ // because a negative number times anything will cause an
592+ // unsigned overflow. Otherwise, we have to do it here. But at
593+ // least in this case, we can subsume the >= minElements check.
594+ if (typeSizeMultiplier == 1 )
595+ hasOverflow = cgf.getBuilder ().createCompare (
596+ loc, cir::CmpOpKind::lt, numElements,
597+ cgf.getBuilder ().getConstInt (loc, numElements.getType (),
598+ minElements));
599+
600+ numElements = cgf.getBuilder ().createIntCast (
601+ numElements, mlir::cast<cir::IntType>(cgf.sizeTy ));
602+
603+ // Otherwise, zext up to size_t if necessary.
604+ } else if (numElementsWidth < sizeWidth) {
605+ numElements = cgf.getBuilder ().createIntCast (
606+ numElements, mlir::cast<cir::IntType>(cgf.sizeTy ));
607+ }
608+
609+ assert (numElements.getType () == cgf.sizeTy );
610+
562611 if (minElements) {
563612 // Don't allow allocation of fewer elements than we have initializers.
564613 if (!hasOverflow) {
565- // FIXME: Avoid creating this twice. It may happen above.
566614 mlir::Value minElementsV = cgf.getBuilder ().getConstInt (
567615 loc, llvm::APInt (sizeWidth, minElements));
568616 hasOverflow = cgf.getBuilder ().createCompare (loc, cir::CmpOpKind::lt,
569617 numElements, minElementsV);
618+ } else if (numElementsWidth > sizeWidth) {
619+ // The other existing overflow subsumes this check.
620+ // We do an unsigned comparison, since any signed value < -1 is
621+ // taken care of either above or below.
622+ mlir::Value minElementsV = cgf.getBuilder ().getConstInt (
623+ loc, llvm::APInt (sizeWidth, minElements));
624+ hasOverflow = cgf.getBuilder ().createOr (
625+ loc, hasOverflow,
626+ cgf.getBuilder ().createCompare (loc, cir::CmpOpKind::lt, numElements,
627+ minElementsV));
570628 }
571629 }
572630
0 commit comments