[clang] [CIR] Upstream reserved placement new handling (PR #169436)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 24 17:00:31 PST 2025
https://github.com/andykaylor created https://github.com/llvm/llvm-project/pull/169436
This upstreams the code to support reserved placement new calls.
>From 884f4e5a09d6c28ae84eb95764acd61154d69f56 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Mon, 24 Nov 2025 16:57:55 -0800
Subject: [PATCH] [CIR] Upstream reserved placement new handling
This upstreams the code to support reserved placement new calls.
---
clang/lib/CIR/CodeGen/Address.h | 6 ++++
clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 23 ++++++++++++--
clang/test/CIR/CodeGen/placement-new.cpp | 40 ++++++++++++++++++++++++
3 files changed, 67 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/placement-new.cpp
diff --git a/clang/lib/CIR/CodeGen/Address.h b/clang/lib/CIR/CodeGen/Address.h
index c8ce530a7b0d3..a425eebe99082 100644
--- a/clang/lib/CIR/CodeGen/Address.h
+++ b/clang/lib/CIR/CodeGen/Address.h
@@ -77,6 +77,12 @@ class Address {
return Address(newPtr, getElementType(), getAlignment());
}
+ /// Return address with different alignment, but same pointer and element
+ /// type.
+ Address withAlignment(clang::CharUnits newAlignment) const {
+ return Address(getPointer(), getElementType(), newAlignment);
+ }
+
/// Return address with different element type, a bitcast pointer, and
/// the same alignment.
Address withElementType(CIRGenBuilderTy &builder, mlir::Type ElemTy) const;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index dbf20db8bfb8d..81fd8ee106107 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -806,8 +806,27 @@ mlir::Value CIRGenFunction::emitCXXNewExpr(const CXXNewExpr *e) {
Address allocation = Address::invalid();
CallArgList allocatorArgs;
if (allocator->isReservedGlobalPlacementOperator()) {
- cgm.errorNYI(e->getSourceRange(),
- "emitCXXNewExpr: reserved global placement operator");
+ // If the allocator is a global placement operator, just
+ // "inline" it directly.
+ assert(e->getNumPlacementArgs() == 1);
+ const Expr *arg = *e->placement_arguments().begin();
+
+ LValueBaseInfo baseInfo;
+ allocation = emitPointerWithAlignment(arg, &baseInfo);
+
+ // The pointer expression will, in many cases, be an opaque void*.
+ // In these cases, discard the computed alignment and use the
+ // formal alignment of the allocated type.
+ if (baseInfo.getAlignmentSource() != AlignmentSource::Decl)
+ allocation = allocation.withAlignment(allocAlign);
+
+ // Set up allocatorArgs for the call to operator delete if it's not
+ // the reserved global operator.
+ if (e->getOperatorDelete() &&
+ !e->getOperatorDelete()->isReservedGlobalPlacementOperator()) {
+ cgm.errorNYI(e->getSourceRange(),
+ "emitCXXNewExpr: reserved placement new with delete");
+ }
} else {
const FunctionProtoType *allocatorType =
allocator->getType()->castAs<FunctionProtoType>();
diff --git a/clang/test/CIR/CodeGen/placement-new.cpp b/clang/test/CIR/CodeGen/placement-new.cpp
new file mode 100644
index 0000000000000..7ceaa0a359e1f
--- /dev/null
+++ b/clang/test/CIR/CodeGen/placement-new.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu %s -fclangir -emit-cir -o %t.cir
+// RUN: FileCheck --input-file=%t.cir -check-prefix=CIR %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu %s -fclangir -emit-llvm -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll -check-prefix=LLVM %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu %s -emit-llvm -o %t.ll
+// RUN: FileCheck --input-file=%t.ll -check-prefix=OGCG %s
+
+typedef __typeof__(sizeof(0)) size_t;
+
+// Declare the reserved placement operators.
+void *operator new(size_t, void*) throw();
+
+struct A { A(); ~A(); };
+
+void test_reserved_placement_new(void *p) {
+ new (p) A();
+}
+
+// CIR-LABEL: cir.func dso_local @_Z27test_reserved_placement_newPv(
+// CIR-SAME: %[[ARG0:.*]]: !cir.ptr<!void>
+// CIR: %[[P:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["p", init]
+// CIR: cir.store %[[ARG0]], %[[P]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
+// CIR: %[[SIZE:.*]] = cir.const #cir.int<1> : !u64i
+// CIR: %[[PTR:.*]] = cir.load{{.*}} %[[P]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+// CIR: %[[PTR_A:.*]] = cir.cast bitcast %[[PTR]] : !cir.ptr<!void> -> !cir.ptr<!rec_A>
+// CIR: cir.call @_ZN1AC1Ev(%[[PTR_A]]) : (!cir.ptr<!rec_A>) -> ()
+
+// LLVM-LABEL: define dso_local void @_Z27test_reserved_placement_newPv(
+// LLVM-SAME: ptr %[[ARG0:.*]]
+// LLVM: %[[P:.*]] = alloca ptr
+// LLVM: store ptr %[[ARG0:.*]], ptr %[[P]]
+// LLVM: %[[PTR:.*]] = load ptr, ptr %[[P]]
+// LLVM: call void @_ZN1AC1Ev(ptr %[[PTR]])
+
+// OGCG-LABEL: define dso_local void @_Z27test_reserved_placement_newPv(
+// OGCG-SAME: ptr {{.*}} %[[ARG0:.*]]
+// OGCG: %[[P:.*]] = alloca ptr
+// OGCG: store ptr %[[ARG0:.*]], ptr %[[P]]
+// OGCG: %[[PTR:.*]] = load ptr, ptr %[[P]]
+// OGCG: call void @_ZN1AC1Ev(ptr {{.*}} %[[PTR]])
More information about the cfe-commits
mailing list