Skip to content

Commit 764c614

Browse files
jiang1997andykaylor
authored andcommitted
[CIR] Add array new cookie support (llvm#163649)
This patch adds the minimal support for array cookies needed to enable ClangIR generation for an array new expression that requires cookies but does not require an explicit initializer. This only provides the cookie support for the base Itanium CXXABI. Different cookie calculations are required for AppleARM64, which will be added in a subsequent patch. Ported from ClangIR incubator PR llvm/clangir#1297. This is the second PR in a series intended to address llvm#160383. --------- Co-authored-by: Andy Kaylor <[email protected]>
1 parent 4e0f4eb commit 764c614

File tree

7 files changed

+290
-16
lines changed

7 files changed

+290
-16
lines changed

clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *e) {
8585
if (!requiresArrayCookie(e))
8686
return CharUnits::Zero();
8787

88-
cgm.errorNYI(e->getSourceRange(), "CIRGenCXXABI::getArrayCookieSize");
89-
return CharUnits::Zero();
88+
return getArrayCookieSizeImpl(e->getAllocatedType());
9089
}
9190

9291
bool CIRGenCXXABI::requiresArrayCookie(const CXXNewExpr *e) {

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,28 @@ class CIRGenCXXABI {
302302
/// - non-array allocations never need a cookie
303303
/// - calls to \::operator new(size_t, void*) never need a cookie
304304
///
305-
/// \param E - the new-expression being allocated.
305+
/// \param e - the new-expression being allocated.
306306
virtual CharUnits getArrayCookieSize(const CXXNewExpr *e);
307+
308+
/// Initialize the array cookie for the given allocation.
309+
///
310+
/// \param newPtr - a char* which is the presumed-non-null
311+
/// return value of the allocation function
312+
/// \param numElements - the computed number of elements,
313+
/// potentially collapsed from the multidimensional array case;
314+
/// always a size_t
315+
/// \param elementType - the base element allocated type,
316+
/// i.e. the allocated type after stripping all array types
317+
virtual Address initializeArrayCookie(CIRGenFunction &cgf, Address newPtr,
318+
mlir::Value numElements,
319+
const CXXNewExpr *e,
320+
QualType elementType) = 0;
321+
322+
protected:
323+
/// Returns the extra size required in order to store the array
324+
/// cookie for the given type. Assumes that an array cookie is
325+
/// required.
326+
virtual CharUnits getArrayCookieSizeImpl(QualType elementType) = 0;
307327
};
308328

309329
/// Creates and Itanium-family ABI

clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
306306
mlir::cast<cir::IntAttr>(constNumElements).getValue();
307307

308308
unsigned numElementsWidth = count.getBitWidth();
309+
bool hasAnyOverflow = false;
309310

310311
// The equivalent code in CodeGen/CGExprCXX.cpp handles these cases as
311312
// overflow, but that should never happen. The size argument is implicitly
@@ -336,11 +337,22 @@ static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
336337

337338
// Add in the cookie, and check whether it's overflowed.
338339
if (cookieSize != 0) {
339-
cgf.cgm.errorNYI(e->getSourceRange(),
340-
"emitCXXNewAllocSize: array cookie");
340+
// Save the current size without a cookie. This shouldn't be
341+
// used if there was overflow
342+
sizeWithoutCookie = cgf.getBuilder().getConstInt(
343+
loc, allocationSize.zextOrTrunc(sizeWidth));
344+
345+
allocationSize = allocationSize.uadd_ov(cookieSize, overflow);
346+
hasAnyOverflow |= overflow;
341347
}
342348

343-
size = cgf.getBuilder().getConstInt(loc, allocationSize);
349+
// On overflow, produce a -1 so operator new will fail
350+
if (hasAnyOverflow) {
351+
size =
352+
cgf.getBuilder().getConstInt(loc, llvm::APInt::getAllOnes(sizeWidth));
353+
} else {
354+
size = cgf.getBuilder().getConstInt(loc, allocationSize);
355+
}
344356
} else {
345357
// TODO: Handle the variable size case
346358
cgf.cgm.errorNYI(e->getSourceRange(),
@@ -390,7 +402,50 @@ void CIRGenFunction::emitNewArrayInitializer(
390402
if (!e->hasInitializer())
391403
return;
392404

393-
cgm.errorNYI(e->getSourceRange(), "emitNewArrayInitializer");
405+
unsigned initListElements = 0;
406+
407+
const Expr *init = e->getInitializer();
408+
const InitListExpr *ile = dyn_cast<InitListExpr>(init);
409+
if (ile) {
410+
cgm.errorNYI(ile->getSourceRange(), "emitNewArrayInitializer: init list");
411+
return;
412+
}
413+
414+
// If all elements have already been initialized, skip any further
415+
// initialization.
416+
auto constOp = mlir::dyn_cast<cir::ConstantOp>(numElements.getDefiningOp());
417+
if (constOp) {
418+
auto constIntAttr = mlir::dyn_cast<cir::IntAttr>(constOp.getValue());
419+
// Just skip out if the constant count is zero.
420+
if (constIntAttr && constIntAttr.getUInt() <= initListElements)
421+
return;
422+
}
423+
424+
assert(init && "have trailing elements to initialize but no initializer");
425+
426+
// If this is a constructor call, try to optimize it out, and failing that
427+
// emit a single loop to initialize all remaining elements.
428+
if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) {
429+
CXXConstructorDecl *ctor = cce->getConstructor();
430+
if (ctor->isTrivial()) {
431+
// If new expression did not specify value-initialization, then there
432+
// is no initialization.
433+
if (!cce->requiresZeroInitialization())
434+
return;
435+
436+
cgm.errorNYI(cce->getSourceRange(),
437+
"emitNewArrayInitializer: trivial ctor zero-init");
438+
return;
439+
}
440+
441+
cgm.errorNYI(cce->getSourceRange(),
442+
"emitNewArrayInitializer: ctor initializer");
443+
return;
444+
}
445+
446+
cgm.errorNYI(init->getSourceRange(),
447+
"emitNewArrayInitializer: unsupported initializer");
448+
return;
394449
}
395450

396451
static void emitNewInitializer(CIRGenFunction &cgf, const CXXNewExpr *e,
@@ -586,9 +641,6 @@ mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
586641

587642
// If there is a brace-initializer, cannot allocate fewer elements than inits.
588643
unsigned minElements = 0;
589-
if (e->isArray() && e->hasInitializer()) {
590-
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array initializer");
591-
}
592644

593645
mlir::Value numElements = nullptr;
594646
mlir::Value allocSizeWithoutCookie = nullptr;
@@ -667,8 +719,11 @@ mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
667719
!e->getOperatorDelete()->isReservedGlobalPlacementOperator())
668720
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: operator delete");
669721

670-
if (allocSize != allocSizeWithoutCookie)
671-
cgm.errorNYI(e->getSourceRange(), "emitCXXNewExpr: array with cookies");
722+
if (allocSize != allocSizeWithoutCookie) {
723+
assert(e->isArray());
724+
allocation = cgm.getCXXABI().initializeArrayCookie(
725+
*this, allocation, numElements, e, allocType);
726+
}
672727

673728
mlir::Type elementTy;
674729
if (e->isArray()) {

clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,14 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
135135
cir::PointerType destCIRTy, bool isRefCast,
136136
Address src) override;
137137

138-
/**************************** RTTI Uniqueness ******************************/
138+
Address initializeArrayCookie(CIRGenFunction &cgf, Address newPtr,
139+
mlir::Value numElements, const CXXNewExpr *e,
140+
QualType elementType) override;
141+
139142
protected:
143+
CharUnits getArrayCookieSizeImpl(QualType elementType) override;
144+
145+
/**************************** RTTI Uniqueness ******************************/
140146
/// Returns true if the ABI requires RTTI type_info objects to be unique
141147
/// across a program.
142148
virtual bool shouldRTTIBeUnique() const { return true; }
@@ -2003,3 +2009,70 @@ mlir::Value CIRGenItaniumCXXABI::emitDynamicCast(CIRGenFunction &cgf,
20032009
return cgf.getBuilder().createDynCast(loc, src.getPointer(), destCIRTy,
20042010
isRefCast, castInfo);
20052011
}
2012+
2013+
/************************** Array allocation cookies **************************/
2014+
2015+
CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
2016+
// The array cookie is a size_t; pad that up to the element alignment.
2017+
// The cookie is actually right-justified in that space.
2018+
return std::max(
2019+
cgm.getSizeSize(),
2020+
cgm.getASTContext().getPreferredTypeAlignInChars(elementType));
2021+
}
2022+
2023+
Address CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
2024+
Address newPtr,
2025+
mlir::Value numElements,
2026+
const CXXNewExpr *e,
2027+
QualType elementType) {
2028+
assert(requiresArrayCookie(e));
2029+
2030+
// TODO: When sanitizer support is implemented, we'll need to
2031+
// get the address space from `newPtr`.
2032+
assert(!cir::MissingFeatures::addressSpace());
2033+
assert(!cir::MissingFeatures::sanitizers());
2034+
2035+
ASTContext &ctx = cgm.getASTContext();
2036+
CharUnits sizeSize = cgf.getSizeSize();
2037+
mlir::Location loc = cgf.getLoc(e->getSourceRange());
2038+
2039+
// The size of the cookie.
2040+
CharUnits cookieSize =
2041+
std::max(sizeSize, ctx.getPreferredTypeAlignInChars(elementType));
2042+
assert(cookieSize == getArrayCookieSizeImpl(elementType));
2043+
2044+
cir::PointerType u8PtrTy = cgf.getBuilder().getUInt8PtrTy();
2045+
mlir::Value baseBytePtr =
2046+
cgf.getBuilder().createPtrBitcast(newPtr.getPointer(), u8PtrTy);
2047+
2048+
// Compute an offset to the cookie.
2049+
CharUnits cookieOffset = cookieSize - sizeSize;
2050+
mlir::Value cookiePtrValue = baseBytePtr;
2051+
if (!cookieOffset.isZero()) {
2052+
mlir::Value offsetOp = cgf.getBuilder().getSignedInt(
2053+
loc, cookieOffset.getQuantity(), /*width=*/32);
2054+
cookiePtrValue =
2055+
cgf.getBuilder().createPtrStride(loc, cookiePtrValue, offsetOp);
2056+
}
2057+
2058+
CharUnits baseAlignment = newPtr.getAlignment();
2059+
CharUnits cookiePtrAlignment = baseAlignment.alignmentAtOffset(cookieOffset);
2060+
Address cookiePtr(cookiePtrValue, u8PtrTy, cookiePtrAlignment);
2061+
2062+
// Write the number of elements into the appropriate slot.
2063+
Address numElementsPtr =
2064+
cookiePtr.withElementType(cgf.getBuilder(), cgf.SizeTy);
2065+
cgf.getBuilder().createStore(loc, numElements, numElementsPtr);
2066+
2067+
// Finally, compute a pointer to the actual data buffer by skipping
2068+
// over the cookie completely.
2069+
mlir::Value dataOffset =
2070+
cgf.getBuilder().getSignedInt(loc, cookieSize.getQuantity(),
2071+
/*width=*/32);
2072+
mlir::Value dataPtr =
2073+
cgf.getBuilder().createPtrStride(loc, baseBytePtr, dataOffset);
2074+
mlir::Value finalPtr =
2075+
cgf.getBuilder().createPtrBitcast(dataPtr, newPtr.getElementType());
2076+
CharUnits finalAlignment = baseAlignment.alignmentAtOffset(cookieSize);
2077+
return Address(finalPtr, newPtr.getElementType(), finalAlignment);
2078+
}

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
102102
// TODO(CIR): Should be updated once TypeSizeInfoAttr is upstreamed
103103
const unsigned sizeTypeSize =
104104
astContext.getTypeSize(astContext.getSignedSizeType());
105-
SizeAlignInBytes = astContext.toCharUnitsFromBits(sizeTypeSize).getQuantity();
105+
SizeSizeInBytes = astContext.toCharUnitsFromBits(sizeTypeSize).getQuantity();
106106
// In CIRGenTypeCache, UIntPtrTy and SizeType are fields of the same union
107107
UIntPtrTy =
108108
cir::IntType::get(&getMLIRContext(), sizeTypeSize, /*isSigned=*/false);

clang/lib/CIR/CodeGen/CIRGenTypeCache.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,17 @@ struct CIRGenTypeCache {
7474
unsigned char PointerSizeInBytes;
7575
};
7676

77-
/// The alignment of size_t.
78-
unsigned char SizeAlignInBytes;
77+
/// The size and alignment of size_t.
78+
union {
79+
unsigned char SizeSizeInBytes; // sizeof(size_t)
80+
unsigned char SizeAlignInBytes;
81+
};
7982

8083
cir::TargetAddressSpaceAttr cirAllocaAddressSpace;
8184

85+
clang::CharUnits getSizeSize() const {
86+
return clang::CharUnits::fromQuantity(SizeSizeInBytes);
87+
}
8288
clang::CharUnits getSizeAlign() const {
8389
return clang::CharUnits::fromQuantity(SizeAlignInBytes);
8490
}

clang/test/CIR/CodeGen/new.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,127 @@ void t_new_constant_size() {
208208
// OGCG: %[[CALL:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 128)
209209
// OGCG: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8
210210

211+
class C {
212+
public:
213+
~C();
214+
};
215+
216+
void t_constant_size_nontrivial() {
217+
auto p = new C[3];
218+
}
219+
220+
// CHECK: cir.func{{.*}} @_Z26t_constant_size_nontrivialv()
221+
// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>, ["p", init] {alignment = 8 : i64}
222+
// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<3> : !u64i
223+
// CHECK: %[[#SIZE_WITHOUT_COOKIE:]] = cir.const #cir.int<3> : !u64i
224+
// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<11> : !u64i
225+
// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void>
226+
// CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>>
227+
// CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i>
228+
// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i>
229+
// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<8> : !s32i
230+
// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>>
231+
// CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void>
232+
// CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_C>
233+
// CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_C>, !cir.ptr<!cir.ptr<!rec_C>>
234+
// CHECK: cir.return
235+
// CHECK: }
236+
237+
// LLVM: @_Z26t_constant_size_nontrivialv()
238+
// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
239+
// LLVM: %[[COOKIE_PTR:.*]] = call ptr @_Znam(i64 11)
240+
// LLVM: store i64 3, ptr %[[COOKIE_PTR]], align 8
241+
// LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[COOKIE_PTR]], i64 8
242+
// LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8
243+
244+
// OGCG: @_Z26t_constant_size_nontrivialv()
245+
// OGCG: %[[ALLOCA:.*]] = alloca ptr, align 8
246+
// OGCG: %[[COOKIE_PTR:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 11)
247+
// OGCG: store i64 3, ptr %[[COOKIE_PTR]], align 8
248+
// OGCG: %[[ALLOCATED_PTR:.*]] = getelementptr inbounds i8, ptr %[[COOKIE_PTR]], i64 8
249+
// OGCG: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8
250+
251+
class D {
252+
public:
253+
int x;
254+
~D();
255+
};
256+
257+
void t_constant_size_nontrivial2() {
258+
auto p = new D[3];
259+
}
260+
261+
// In this test SIZE_WITHOUT_COOKIE isn't used, but it would be if there were
262+
// an initializer.
263+
264+
// CHECK: cir.func{{.*}} @_Z27t_constant_size_nontrivial2v()
265+
// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_D>, !cir.ptr<!cir.ptr<!rec_D>>, ["p", init] {alignment = 8 : i64}
266+
// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<3> : !u64i
267+
// CHECK: %[[#SIZE_WITHOUT_COOKIE:]] = cir.const #cir.int<12> : !u64i
268+
// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<20> : !u64i
269+
// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void>
270+
// CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>>
271+
// CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i>
272+
// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i>
273+
// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<8> : !s32i
274+
// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>>
275+
// CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void>
276+
// CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_D>
277+
// CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_D>, !cir.ptr<!cir.ptr<!rec_D>>
278+
// CHECK: cir.return
279+
// CHECK: }
280+
281+
// LLVM: @_Z27t_constant_size_nontrivial2v()
282+
// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
283+
// LLVM: %[[COOKIE_PTR:.*]] = call ptr @_Znam(i64 20)
284+
// LLVM: store i64 3, ptr %[[COOKIE_PTR]], align 8
285+
// LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[COOKIE_PTR]], i64 8
286+
// LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8
287+
288+
struct alignas(16) E {
289+
int x;
290+
~E();
291+
};
292+
293+
void t_align16_nontrivial() {
294+
auto p = new E[2];
295+
}
296+
297+
// CHECK: cir.func{{.*}} @_Z20t_align16_nontrivialv()
298+
// CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr<!rec_E>, !cir.ptr<!cir.ptr<!rec_E>>, ["p", init] {alignment = 8 : i64}
299+
// CHECK: %[[#NUM_ELEMENTS:]] = cir.const #cir.int<2> : !u64i
300+
// CHECK: %[[#SIZE_WITHOUT_COOKIE:]] = cir.const #cir.int<32> : !u64i
301+
// CHECK: %[[#ALLOCATION_SIZE:]] = cir.const #cir.int<48> : !u64i
302+
// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[#ALLOCATION_SIZE]]) : (!u64i) -> !cir.ptr<!void>
303+
// CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!u8i>>
304+
// CHECK: %[[COOKIE_OFFSET:.*]] = cir.const #cir.int<8> : !s32i
305+
// CHECK: %[[COOKIE_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[COOKIE_OFFSET]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>>
306+
// CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!u64i>
307+
// CHECK: cir.store align(8) %[[#NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr<!u64i>
308+
// CHECK: %[[#COOKIE_SIZE:]] = cir.const #cir.int<16> : !s32i
309+
// CHECK: %[[DATA_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[#COOKIE_SIZE]] : (!cir.ptr<!cir.ptr<!u8i>>, !s32i) -> !cir.ptr<!cir.ptr<!u8i>>
310+
// CHECK: %[[DATA_PTR_VOID:.*]] = cir.cast bitcast %[[DATA_PTR_RAW]] : !cir.ptr<!cir.ptr<!u8i>> -> !cir.ptr<!void>
311+
// CHECK: %[[DATA_PTR:.*]] = cir.cast bitcast %[[DATA_PTR_VOID]] : !cir.ptr<!void> -> !cir.ptr<!rec_E>
312+
// CHECK: cir.store align(8) %[[DATA_PTR]], %[[P_ADDR]] : !cir.ptr<!rec_E>, !cir.ptr<!cir.ptr<!rec_E>>
313+
// CHECK: cir.return
314+
// CHECK: }
315+
316+
// LLVM: @_Z20t_align16_nontrivialv()
317+
// LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8
318+
// LLVM: %[[RAW_PTR:.*]] = call ptr @_Znam(i64 48)
319+
// LLVM: %[[COOKIE_PTR:.*]] = getelementptr ptr, ptr %[[RAW_PTR]], i64 8
320+
// LLVM: store i64 2, ptr %[[COOKIE_PTR]], align 8
321+
// LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[RAW_PTR]], i64 16
322+
// LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8
323+
324+
// OGCG: define{{.*}} void @_Z20t_align16_nontrivialv
325+
// OGCG: %[[ALLOCA:.*]] = alloca ptr, align 8
326+
// OGCG: %[[RAW_PTR:.*]] = call noalias noundef nonnull ptr @_Znam(i64 noundef 48)
327+
// OGCG: %[[COOKIE_PTR:.*]] = getelementptr inbounds i8, ptr %[[RAW_PTR]], i64 8
328+
// OGCG: store i64 2, ptr %[[COOKIE_PTR]], align 8
329+
// OGCG: %[[ALLOCATED_PTR:.*]] = getelementptr inbounds i8, ptr %[[RAW_PTR]], i64 16
330+
// OGCG: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8
331+
// OGCG: ret void
211332

212333
void t_new_multidim_constant_size() {
213334
auto p = new double[2][3][4];

0 commit comments

Comments
 (0)