Skip to content

Commit e6f60a6

Browse files
[CIR] Add builtin operator new/delete (#168578)
This PR adds `__builtin_operator_new` and `__builtin_operator_delete`. The implementation is taken from clang code gen.
1 parent 8e2f544 commit e6f60a6

File tree

5 files changed

+89
-0
lines changed

5 files changed

+89
-0
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ struct MissingFeatures {
200200
static bool aggValueSlotMayOverlap() { return false; }
201201
static bool aggValueSlotVolatile() { return false; }
202202
static bool alignCXXRecordDecl() { return false; }
203+
static bool allocToken() { return false; }
203204
static bool appleKext() { return false; }
204205
static bool armComputeVolatileBitfields() { return false; }
205206
static bool asmGoto() { return false; }

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
#include "mlir/IR/BuiltinAttributes.h"
1919
#include "mlir/IR/Value.h"
2020
#include "mlir/Support/LLVM.h"
21+
#include "clang/AST/DeclBase.h"
2122
#include "clang/AST/Expr.h"
2223
#include "clang/AST/GlobalDecl.h"
2324
#include "clang/Basic/Builtins.h"
25+
#include "clang/Basic/OperatorKinds.h"
2426
#include "clang/CIR/Dialect/IR/CIRTypes.h"
2527
#include "clang/CIR/MissingFeatures.h"
2628
#include "llvm/Support/ErrorHandling.h"
@@ -1093,8 +1095,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
10931095
case Builtin::BI__addressof:
10941096
case Builtin::BI__builtin_addressof:
10951097
case Builtin::BI__builtin_function_start:
1098+
return errorBuiltinNYI(*this, e, builtinID);
10961099
case Builtin::BI__builtin_operator_new:
1100+
return emitNewOrDeleteBuiltinCall(
1101+
e->getCallee()->getType()->castAs<FunctionProtoType>(), e, OO_New);
10971102
case Builtin::BI__builtin_operator_delete:
1103+
emitNewOrDeleteBuiltinCall(
1104+
e->getCallee()->getType()->castAs<FunctionProtoType>(), e, OO_Delete);
1105+
return RValue::get(nullptr);
10981106
case Builtin::BI__builtin_is_aligned:
10991107
case Builtin::BI__builtin_align_up:
11001108
case Builtin::BI__builtin_align_down:

clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "clang/AST/DeclCXX.h"
1818
#include "clang/AST/ExprCXX.h"
19+
#include "clang/Basic/OperatorKinds.h"
1920
#include "clang/CIR/MissingFeatures.h"
2021

2122
using namespace clang;
@@ -648,6 +649,36 @@ static RValue emitNewDeleteCall(CIRGenFunction &cgf,
648649
return rv;
649650
}
650651

652+
RValue CIRGenFunction::emitNewOrDeleteBuiltinCall(const FunctionProtoType *type,
653+
const CallExpr *callExpr,
654+
OverloadedOperatorKind op) {
655+
CallArgList args;
656+
emitCallArgs(args, type, callExpr->arguments());
657+
// Find the allocation or deallocation function that we're calling.
658+
ASTContext &astContext = getContext();
659+
assert(op == OO_New || op == OO_Delete);
660+
DeclarationName name = astContext.DeclarationNames.getCXXOperatorName(op);
661+
662+
clang::DeclContextLookupResult lookupResult =
663+
astContext.getTranslationUnitDecl()->lookup(name);
664+
for (const auto *decl : lookupResult) {
665+
if (const auto *funcDecl = dyn_cast<FunctionDecl>(decl)) {
666+
if (astContext.hasSameType(funcDecl->getType(), QualType(type, 0))) {
667+
if (sanOpts.has(SanitizerKind::AllocToken)) {
668+
// TODO: Set !alloc_token metadata.
669+
assert(!cir::MissingFeatures::allocToken());
670+
cgm.errorNYI("Alloc token sanitizer not yet supported!");
671+
}
672+
673+
// Emit the call to operator new/delete.
674+
return emitNewDeleteCall(*this, funcDecl, type, args);
675+
}
676+
}
677+
}
678+
679+
llvm_unreachable("predeclared global operator new/delete is missing");
680+
}
681+
651682
namespace {
652683
/// Calls the given 'operator delete' on a single object.
653684
struct CallObjectDelete final : EHScopeStack::Cleanup {

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "clang/AST/ExprCXX.h"
3131
#include "clang/AST/Stmt.h"
3232
#include "clang/AST/Type.h"
33+
#include "clang/Basic/OperatorKinds.h"
3334
#include "clang/CIR/Dialect/IR/CIRDialect.h"
3435
#include "clang/CIR/MissingFeatures.h"
3536
#include "clang/CIR/TypeEvaluationKind.h"
@@ -1487,6 +1488,10 @@ class CIRGenFunction : public CIRGenTypeCache {
14871488

14881489
RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);
14891490

1491+
RValue emitNewOrDeleteBuiltinCall(const FunctionProtoType *type,
1492+
const CallExpr *callExpr,
1493+
OverloadedOperatorKind op);
1494+
14901495
void emitCXXTemporary(const CXXTemporary *temporary, QualType tempType,
14911496
Address ptr);
14921497

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
5+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
7+
8+
9+
void test_builtins_basic() {
10+
__builtin_operator_delete(__builtin_operator_new(4));
11+
// CIR-LABEL: test_builtins_basic
12+
// CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) : (!u64i) -> !cir.ptr<!void>
13+
// CIR: cir.call @_ZdlPv([[P]]) {{.*}}: (!cir.ptr<!void>) -> ()
14+
// CIR: cir.return
15+
16+
// LLVM-LABEL: test_builtins_basic
17+
// LLVM: [[P:%.*]] = call ptr @_Znwm(i64 4)
18+
// LLVM: call void @_ZdlPv(ptr [[P]])
19+
// LLVM: ret void
20+
21+
// OGCG-LABEL: test_builtins_basic
22+
// OGCG: [[P:%.*]] = call {{.*}} ptr @_Znwm(i64 {{.*}} 4)
23+
// OGCG: call void @_ZdlPv(ptr {{.*}} [[P]])
24+
// OGCG: ret void
25+
}
26+
27+
void test_sized_delete() {
28+
__builtin_operator_delete(__builtin_operator_new(4), 4);
29+
30+
// CIR-LABEL: test_sized_delete
31+
// CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) : (!u64i) -> !cir.ptr<!void>
32+
// CIR: cir.call @_ZdlPvm([[P]], {{%.*}}) {{.*}}: (!cir.ptr<!void>, !u64i) -> ()
33+
// CIR: cir.return
34+
35+
// LLVM-LABEL: test_sized_delete
36+
// LLVM: [[P:%.*]] = call ptr @_Znwm(i64 4)
37+
// LLVM: call void @_ZdlPvm(ptr [[P]], i64 4)
38+
// LLVM: ret void
39+
40+
// OGCG-LABEL: test_sized_delete
41+
// OGCG: [[P:%.*]] = call {{.*}} ptr @_Znwm(i64 {{.*}} 4)
42+
// OGCG: call void @_ZdlPvm(ptr {{.*}} [[P]], i64 {{.*}} 4)
43+
// OGCG: ret void
44+
}

0 commit comments

Comments
 (0)