11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#include " CIRGenCXXABI.h"
14
+ #include " CIRGenConstantEmitter.h"
14
15
#include " CIRGenFunction.h"
15
16
16
17
#include " clang/AST/DeclCXX.h"
@@ -210,6 +211,19 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
210
211
return emitCall (fnInfo, callee, returnValue, args, nullptr , loc);
211
212
}
212
213
214
+ static CharUnits calculateCookiePadding (CIRGenFunction &cgf,
215
+ const CXXNewExpr *e) {
216
+ if (!e->isArray ())
217
+ return CharUnits::Zero ();
218
+
219
+ // No cookie is required if the operator new[] being used is the
220
+ // reserved placement operator new[].
221
+ if (e->getOperatorNew ()->isReservedGlobalPlacementOperator ())
222
+ return CharUnits::Zero ();
223
+
224
+ return cgf.cgm .getCXXABI ().getArrayCookieSize (e);
225
+ }
226
+
213
227
static mlir::Value emitCXXNewAllocSize (CIRGenFunction &cgf, const CXXNewExpr *e,
214
228
unsigned minElements,
215
229
mlir::Value &numElements,
@@ -224,8 +238,98 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
224
238
return sizeWithoutCookie;
225
239
}
226
240
227
- cgf.cgm .errorNYI (e->getSourceRange (), " emitCXXNewAllocSize: array" );
228
- return {};
241
+ // The width of size_t.
242
+ unsigned sizeWidth = cgf.cgm .getDataLayout ().getTypeSizeInBits (cgf.SizeTy );
243
+
244
+ // The number of elements can be have an arbitrary integer type;
245
+ // essentially, we need to multiply it by a constant factor, add a
246
+ // cookie size, and verify that the result is representable as a
247
+ // size_t. That's just a gloss, though, and it's wrong in one
248
+ // important way: if the count is negative, it's an error even if
249
+ // the cookie size would bring the total size >= 0.
250
+ //
251
+ // If the array size is constant, Sema will have prevented negative
252
+ // values and size overflow.
253
+
254
+ // Compute the constant factor.
255
+ llvm::APInt arraySizeMultiplier (sizeWidth, 1 );
256
+ while (const ConstantArrayType *cat =
257
+ cgf.getContext ().getAsConstantArrayType (type)) {
258
+ type = cat->getElementType ();
259
+ arraySizeMultiplier *= cat->getSize ();
260
+ }
261
+
262
+ CharUnits typeSize = cgf.getContext ().getTypeSizeInChars (type);
263
+ llvm::APInt typeSizeMultiplier (sizeWidth, typeSize.getQuantity ());
264
+ typeSizeMultiplier *= arraySizeMultiplier;
265
+
266
+ // Figure out the cookie size.
267
+ llvm::APInt cookieSize (sizeWidth,
268
+ calculateCookiePadding (cgf, e).getQuantity ());
269
+
270
+ // This will be a size_t.
271
+ mlir::Value size;
272
+
273
+ // Emit the array size expression.
274
+ // We multiply the size of all dimensions for NumElements.
275
+ // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6.
276
+ const Expr *arraySize = *e->getArraySize ();
277
+ mlir::Attribute constNumElements =
278
+ ConstantEmitter (cgf.cgm , &cgf)
279
+ .emitAbstract (arraySize, arraySize->getType ());
280
+ if (constNumElements) {
281
+ // Get an APInt from the constant
282
+ const llvm::APInt &count =
283
+ mlir::cast<cir::IntAttr>(constNumElements).getValue ();
284
+
285
+ unsigned numElementsWidth = count.getBitWidth ();
286
+
287
+ // The equivalent code in CodeGen/CGExprCXX.cpp handles these cases as
288
+ // overflow, but that should never happen. The size argument is implicitly
289
+ // cast to a size_t, so it can never be negative and numElementsWidth will
290
+ // always equal sizeWidth.
291
+ assert (!count.isNegative () && " Expected non-negative array size" );
292
+ assert (numElementsWidth == sizeWidth &&
293
+ " Expected a size_t array size constant" );
294
+
295
+ // Okay, compute a count at the right width.
296
+ llvm::APInt adjustedCount = count.zextOrTrunc (sizeWidth);
297
+
298
+ // Scale numElements by that. This might overflow, but we don't
299
+ // care because it only overflows if allocationSize does too, and
300
+ // if that overflows then we shouldn't use this.
301
+ // This emits a constant that may not be used, but we can't tell here
302
+ // whether it will be needed or not.
303
+ numElements =
304
+ cgf.getBuilder ().getConstInt (loc, adjustedCount * arraySizeMultiplier);
305
+
306
+ // Compute the size before cookie, and track whether it overflowed.
307
+ bool overflow;
308
+ llvm::APInt allocationSize =
309
+ adjustedCount.umul_ov (typeSizeMultiplier, overflow);
310
+
311
+ // Sema prevents us from hitting this case
312
+ assert (!overflow && " Overflow in array allocation size" );
313
+
314
+ // Add in the cookie, and check whether it's overflowed.
315
+ if (cookieSize != 0 ) {
316
+ cgf.cgm .errorNYI (e->getSourceRange (),
317
+ " emitCXXNewAllocSize: array cookie" );
318
+ }
319
+
320
+ size = cgf.getBuilder ().getConstInt (loc, allocationSize);
321
+ } else {
322
+ // TODO: Handle the variable size case
323
+ cgf.cgm .errorNYI (e->getSourceRange (),
324
+ " emitCXXNewAllocSize: variable array size" );
325
+ }
326
+
327
+ if (cookieSize == 0 )
328
+ sizeWithoutCookie = size;
329
+ else
330
+ assert (sizeWithoutCookie && " didn't set sizeWithoutCookie?" );
331
+
332
+ return size;
229
333
}
230
334
231
335
static void storeAnyExprIntoOneUnit (CIRGenFunction &cgf, const Expr *init,
@@ -254,13 +358,26 @@ static void storeAnyExprIntoOneUnit(CIRGenFunction &cgf, const Expr *init,
254
358
llvm_unreachable (" bad evaluation kind" );
255
359
}
256
360
361
+ void CIRGenFunction::emitNewArrayInitializer (
362
+ const CXXNewExpr *e, QualType elementType, mlir::Type elementTy,
363
+ Address beginPtr, mlir::Value numElements,
364
+ mlir::Value allocSizeWithoutCookie) {
365
+ // If we have a type with trivial initialization and no initializer,
366
+ // there's nothing to do.
367
+ if (!e->hasInitializer ())
368
+ return ;
369
+
370
+ cgm.errorNYI (e->getSourceRange (), " emitNewArrayInitializer" );
371
+ }
372
+
257
373
static void emitNewInitializer (CIRGenFunction &cgf, const CXXNewExpr *e,
258
374
QualType elementType, mlir::Type elementTy,
259
375
Address newPtr, mlir::Value numElements,
260
376
mlir::Value allocSizeWithoutCookie) {
261
377
assert (!cir::MissingFeatures::generateDebugInfo ());
262
378
if (e->isArray ()) {
263
- cgf.cgm .errorNYI (e->getSourceRange (), " emitNewInitializer: array" );
379
+ cgf.emitNewArrayInitializer (e, elementType, elementTy, newPtr, numElements,
380
+ allocSizeWithoutCookie);
264
381
} else if (const Expr *init = e->getInitializer ()) {
265
382
storeAnyExprIntoOneUnit (cgf, init, e->getAllocatedType (), newPtr,
266
383
AggValueSlot::DoesNotOverlap);
@@ -536,7 +653,14 @@ mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
536
653
if (allocSize != allocSizeWithoutCookie)
537
654
cgm.errorNYI (e->getSourceRange (), " emitCXXNewExpr: array with cookies" );
538
655
539
- mlir::Type elementTy = convertTypeForMem (allocType);
656
+ mlir::Type elementTy;
657
+ if (e->isArray ()) {
658
+ // For array new, use the allocated type to handle multidimensional arrays
659
+ // correctly
660
+ elementTy = convertTypeForMem (e->getAllocatedType ());
661
+ } else {
662
+ elementTy = convertTypeForMem (allocType);
663
+ }
540
664
Address result = builder.createElementBitCast (getLoc (e->getSourceRange ()),
541
665
allocation, elementTy);
542
666
0 commit comments