[clang] [clang][bytecode] Implement using operator new/operator delete (PR #107679)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 7 01:55:44 PDT 2024


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/107679

Reuse the __builtin_operator_{new,delete} implementations.

>From 654bc52d1e947d52942878a6a50c73053814d565 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 7 Sep 2024 10:52:40 +0200
Subject: [PATCH] [clang][bytecode] Implement using operator new/operator
 delete

Reuse the __builtin_operator_{new,delete} implementations.
---
 clang/lib/AST/ByteCode/Compiler.cpp      | 31 ++++++++++++++++--------
 clang/lib/AST/ByteCode/Compiler.h        |  2 +-
 clang/lib/AST/ByteCode/Interp.cpp        |  4 +--
 clang/lib/AST/ByteCode/Interp.h          |  4 +--
 clang/lib/AST/ByteCode/InterpBuiltin.cpp |  4 +--
 clang/lib/AST/ByteCode/Opcodes.td        |  2 +-
 clang/test/AST/ByteCode/new-delete.cpp   | 14 +++++++++++
 7 files changed, 43 insertions(+), 18 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index bada8621b9681f..115b0aa7dd29c9 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -4070,18 +4070,18 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
 }
 
 template <class Emitter>
-bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
+bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
+                                             unsigned BuiltinID) {
   const Function *Func = getFunction(E->getDirectCallee());
   if (!Func)
     return false;
 
   // For these, we're expected to ultimately return an APValue pointing
   // to the CallExpr. This is needed to get the correct codegen.
-  unsigned Builtin = E->getBuiltinCallee();
-  if (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
-      Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
-      Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
-      Builtin == Builtin::BI__builtin_function_start) {
+  if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
+      BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString ||
+      BuiltinID == Builtin::BI__builtin_ptrauth_sign_constant ||
+      BuiltinID == Builtin::BI__builtin_function_start) {
     if (std::optional<unsigned> GlobalOffset = P.createGlobal(E)) {
       if (!this->emitGetPtrGlobal(*GlobalOffset, E))
         return false;
@@ -4113,7 +4113,7 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
     }
   }
 
-  if (!this->emitCallBI(Func, E, E))
+  if (!this->emitCallBI(Func, E, BuiltinID, E))
     return false;
 
   if (DiscardResult && !ReturnType->isVoidType()) {
@@ -4126,13 +4126,24 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
 
 template <class Emitter>
 bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
-  if (E->getBuiltinCallee())
-    return VisitBuiltinCallExpr(E);
+  if (unsigned BuiltinID = E->getBuiltinCallee())
+    return VisitBuiltinCallExpr(E, BuiltinID);
+
+  const FunctionDecl *FuncDecl = E->getDirectCallee();
+  // Calls to replaceable operator new/operator delete.
+  if (FuncDecl && FuncDecl->isReplaceableGlobalAllocationFunction()) {
+    if (FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_New ||
+        FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Array_New) {
+      return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new);
+    } else {
+      assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete);
+      return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete);
+    }
+  }
 
   QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
   std::optional<PrimType> T = classify(ReturnType);
   bool HasRVO = !ReturnType->isVoidType() && !T;
-  const FunctionDecl *FuncDecl = E->getDirectCallee();
 
   if (HasRVO) {
     if (DiscardResult) {
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index eb1252fec054bb..39c0736cb4e27e 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -133,7 +133,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
   bool VisitVectorBinOp(const BinaryOperator *E);
   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
   bool VisitCallExpr(const CallExpr *E);
-  bool VisitBuiltinCallExpr(const CallExpr *E);
+  bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);
   bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 99d01ca52645e0..ac02bd6d033487 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1178,7 +1178,7 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
 }
 
 bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
-            const CallExpr *CE) {
+            const CallExpr *CE, uint32_t BuiltinID) {
   if (S.checkingPotentialConstantExpression())
     return false;
   auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
@@ -1186,7 +1186,7 @@ bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
   InterpFrame *FrameBefore = S.Current;
   S.Current = NewFrame.get();
 
-  if (InterpretBuiltin(S, PC, Func, CE)) {
+  if (InterpretBuiltin(S, PC, Func, CE, BuiltinID)) {
     NewFrame.release();
     return true;
   }
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 4ca0e05d67c7c3..7a0011b9606976 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -155,7 +155,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
 bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
               uint32_t VarArgSize);
 bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
-            const CallExpr *CE);
+            const CallExpr *CE, uint32_t BuiltinID);
 bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
              const CallExpr *CE);
 
@@ -268,7 +268,7 @@ bool Interpret(InterpState &S, APValue &Result);
 
 /// Interpret a builtin function.
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
-                      const CallExpr *Call);
+                      const CallExpr *Call, uint32_t BuiltinID);
 
 /// Interpret an offsetof operation.
 bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 49fbaa3cbcb316..51c77b7da1a655 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -1395,13 +1395,13 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
 }
 
 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
-                      const CallExpr *Call) {
+                      const CallExpr *Call, uint32_t BuiltinID) {
   const InterpFrame *Frame = S.Current;
   APValue Dummy;
 
   std::optional<PrimType> ReturnT = S.getContext().classify(Call);
 
-  switch (F->getBuiltinID()) {
+  switch (BuiltinID) {
   case Builtin::BI__builtin_is_constant_evaluated:
     if (!interp__builtin_is_constant_evaluated(S, OpPC, Frame, Call))
       return false;
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 5d7a6e94f6e228..e3a88c069847b8 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -202,7 +202,7 @@ def CallVirt : Opcode {
 }
 
 def CallBI : Opcode {
-  let Args = [ArgFunction, ArgCallExpr];
+  let Args = [ArgFunction, ArgCallExpr, ArgUint32];
 }
 
 def CallPtr : Opcode {
diff --git a/clang/test/AST/ByteCode/new-delete.cpp b/clang/test/AST/ByteCode/new-delete.cpp
index 556efa65ae1181..902ab4aab10fb5 100644
--- a/clang/test/AST/ByteCode/new-delete.cpp
+++ b/clang/test/AST/ByteCode/new-delete.cpp
@@ -601,6 +601,19 @@ namespace std {
   };
 }
 
+/// Specialization for float, using operator new/delete.
+namespace std {
+  using size_t = decltype(sizeof(0));
+  template<> struct allocator<float> {
+    constexpr float *allocate(size_t N) {
+      return (float*)operator new (sizeof(float) * N);
+    }
+    constexpr void deallocate(void *p) {
+      operator delete(p);
+    }
+  };
+}
+
 namespace OperatorNewDelete {
 
   constexpr bool mismatched(int alloc_kind, int dealloc_kind) {
@@ -696,6 +709,7 @@ namespace OperatorNewDelete {
   constexpr int no_deallocate_nullptr = (std::allocator<int>().deallocate(nullptr), 1); // both-error {{constant expression}} \
                                                                                         // both-note {{in call}}
 
+  static_assert((std::allocator<float>().deallocate(std::allocator<float>().allocate(10)), 1) == 1);
 }
 
 #else



More information about the cfe-commits mailing list