diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 2ecde9aa5d56d..c99fd6f0bfcc4 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -200,6 +200,7 @@ struct MissingFeatures { static bool aggValueSlotMayOverlap() { return false; } static bool aggValueSlotVolatile() { return false; } static bool alignCXXRecordDecl() { return false; } + static bool allocToken() { return false; } static bool appleKext() { return false; } static bool armComputeVolatileBitfields() { return false; } static bool asmGoto() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index f5c5dcbaf034b..e0b5a028e9d58 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -18,9 +18,11 @@ #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Value.h" #include "mlir/Support/LLVM.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/Expr.h" #include "clang/AST/GlobalDecl.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" #include "llvm/Support/ErrorHandling.h" @@ -511,6 +513,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, cir::PrefetchOp::create(builder, loc, address, locality, isWrite); return RValue::get(nullptr); } + case Builtin::BI__builtin_operator_new: + return emitNewOrDeleteBuiltinCall( + e->getCallee()->getType()->castAs(), e, OO_New); + case Builtin::BI__builtin_operator_delete: + emitNewOrDeleteBuiltinCall( + e->getCallee()->getType()->castAs(), e, OO_Delete); + return RValue::get(nullptr); case Builtin::BI__builtin_readcyclecounter: case Builtin::BI__builtin_readsteadycounter: case Builtin::BI__builtin___clear_cache: diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 28a42121052e2..a7cb7abf50761 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -16,6 +16,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/CIR/MissingFeatures.h" using namespace clang; @@ -648,6 +649,36 @@ static RValue emitNewDeleteCall(CIRGenFunction &cgf, return rv; } +RValue CIRGenFunction::emitNewOrDeleteBuiltinCall(const FunctionProtoType *type, + const CallExpr *callExpr, + OverloadedOperatorKind op) { + CallArgList args; + emitCallArgs(args, type, callExpr->arguments()); + // Find the allocation or deallocation function that we're calling. + ASTContext &astContext = getContext(); + assert(op == OO_New || op == OO_Delete); + DeclarationName name = astContext.DeclarationNames.getCXXOperatorName(op); + + clang::DeclContextLookupResult lookupResult = + astContext.getTranslationUnitDecl()->lookup(name); + for (const auto *decl : lookupResult) { + if (const auto *funcDecl = dyn_cast(decl)) { + if (astContext.hasSameType(funcDecl->getType(), QualType(type, 0))) { + if (sanOpts.has(SanitizerKind::AllocToken)) { + // TODO: Set !alloc_token metadata. + assert(!cir::MissingFeatures::allocToken()); + cgm.errorNYI("Alloc token sanitizer not yet supported!"); + } + + // Emit the call to operator new/delete. + return emitNewDeleteCall(*this, funcDecl, type, args); + } + } + } + + llvm_unreachable("predeclared global operator new/delete is missing"); +} + namespace { /// Calls the given 'operator delete' on a single object. struct CallObjectDelete final : EHScopeStack::Cleanup { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index b426f3389ff1b..a3a7b4a207a81 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -30,6 +30,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/Stmt.h" #include "clang/AST/Type.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/CIR/Dialect/IR/CIRDialect.h" #include "clang/CIR/MissingFeatures.h" #include "clang/CIR/TypeEvaluationKind.h" @@ -1487,6 +1488,10 @@ class CIRGenFunction : public CIRGenTypeCache { RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr); + RValue emitNewOrDeleteBuiltinCall(const FunctionProtoType *type, + const CallExpr *callExpr, + OverloadedOperatorKind op); + void emitCXXTemporary(const CXXTemporary *temporary, QualType tempType, Address ptr); diff --git a/clang/test/CIR/CodeGen/builtin_new_delete.cpp b/clang/test/CIR/CodeGen/builtin_new_delete.cpp new file mode 100644 index 0000000000000..d540bfcf8a36d --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin_new_delete.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + + +void test_builtins_basic() { + __builtin_operator_delete(__builtin_operator_new(4)); + // CIR-LABEL: test_builtins_basic + // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) : (!u64i) -> !cir.ptr + // CIR: cir.call @_ZdlPv([[P]]) {{.*}}: (!cir.ptr) -> () + // CIR: cir.return + + // LLVM-LABEL: test_builtins_basic + // LLVM: [[P:%.*]] = call ptr @_Znwm(i64 4) + // LLVM: call void @_ZdlPv(ptr [[P]]) + // LLVM: ret void + + // OGCG-LABEL: test_builtins_basic + // OGCG: [[P:%.*]] = call {{.*}} ptr @_Znwm(i64 {{.*}} 4) + // OGCG: call void @_ZdlPv(ptr {{.*}} [[P]]) + // OGCG: ret void +} + +void test_sized_delete() { + __builtin_operator_delete(__builtin_operator_new(4), 4); + + // CIR-LABEL: test_sized_delete + // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) : (!u64i) -> !cir.ptr + // CIR: cir.call @_ZdlPvm([[P]], {{%.*}}) {{.*}}: (!cir.ptr, !u64i) -> () + // CIR: cir.return + + // LLVM-LABEL: test_sized_delete + // LLVM: [[P:%.*]] = call ptr @_Znwm(i64 4) + // LLVM: call void @_ZdlPvm(ptr [[P]], i64 4) + // LLVM: ret void + + // OGCG-LABEL: test_sized_delete + // OGCG: [[P:%.*]] = call {{.*}} ptr @_Znwm(i64 {{.*}} 4) + // OGCG: call void @_ZdlPvm(ptr {{.*}} [[P]], i64 {{.*}} 4) + // OGCG: ret void +}