From: Richard Smith Date: Tue, 3 Jun 2014 23:27:44 +0000 (+0000) Subject: Add __builtin_operator_new and __builtin_operator_delete, which act like calls X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb9e1524b7c546b1e88647eef43f5fbc7906ab79;p=clang Add __builtin_operator_new and __builtin_operator_delete, which act like calls to the normal non-placement ::operator new and ::operator delete, but allow optimizations like new-expressions and delete-expressions do. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@210137 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst index 4e38a16ba1..2de18ce885 100644 --- a/docs/LanguageExtensions.rst +++ b/docs/LanguageExtensions.rst @@ -1446,6 +1446,24 @@ object that overloads ``operator&``. return __builtin_addressof(value); } +``__builtin_operator_new`` and ``__builtin_operator_delete`` +------------------------------------------------------------ + +``__builtin_operator_new`` allocates memory just like a non-placement non-class +*new-expression*. This is exactly like directly calling the normal +non-placement ``::operator new``, except that it allows certain optimizations +that the C++ standard does not permit for a direct function call to +``::operator new`` (in particular, removing ``new`` / ``delete`` pairs and +merging allocations). + +Likewise, ``__builtin_operator_delete`` deallocates memory just like a +non-class *delete-expression*, and is exactly like directly calling the normal +``::operator delete``, except that it permits optimizations. Only the unsized +form of ``__builtin_operator_delete`` is currently available. + +These builtins are intended for use in the implementation of ``std::allocator`` +and other similar allocation libraries, and are only available in C++. + Multiprecision Arithmetic Builtins ---------------------------------- diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 3a1c58f431..4c356f1c75 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -73,7 +73,7 @@ // be followed by ':headername:' to state which header this function // comes from. // i -> this is a runtime library implemented function without the -// '__builtin_' prefix. It will be implemented in compiter-rt or libgcc. +// '__builtin_' prefix. It will be implemented in compiler-rt or libgcc. // p:N: -> this is a printf-like function whose Nth argument is the format // string. // P:N: -> similar to the p:N: attribute, but the function is like vprintf @@ -1204,6 +1204,8 @@ BUILTIN(__builtin_smulll_overflow, "bSLLiCSLLiCSLLi*", "n") // Clang builtins (not available in GCC). BUILTIN(__builtin_addressof, "v*v&", "nct") +BUILTIN(__builtin_operator_new, "v*z", "c") +BUILTIN(__builtin_operator_delete, "vv*", "n") #undef BUILTIN #undef LIBBUILTIN diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 9c648e88a9..28273caa6c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6682,6 +6682,7 @@ def err_argument_invalid_range : Error< def err_builtin_longjmp_invalid_val : Error< "argument to __builtin_longjmp must be a constant 1">; +def err_builtin_requires_language : Error<"'%0' is only available in %1">; def err_constant_integer_arg_type : Error< "argument to %0 must be a constant integer">; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 8b62ef0ced..f705ed80c1 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1508,6 +1508,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_addressof: return RValue::get(EmitLValue(E->getArg(0)).getAddress()); + case Builtin::BI__builtin_operator_new: + return EmitBuiltinNewDeleteCall(FD->getType()->castAs(), + E->getArg(0), false); + case Builtin::BI__builtin_operator_delete: + return EmitBuiltinNewDeleteCall(FD->getType()->castAs(), + E->getArg(0), true); case Builtin::BI__noop: return RValue::get(nullptr); case Builtin::BI_InterlockedCompareExchange: { diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 762d8e2959..0492813f8f 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -1029,6 +1029,23 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF, return RV; } +RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type, + const Expr *Arg, + bool IsDelete) { + CallArgList Args; + const Stmt *ArgS = Arg; + EmitCallArgs(Args, *Type->param_type_begin(), + ConstExprIterator(&ArgS), ConstExprIterator(&ArgS + 1)); + // Find the allocation or deallocation function that we're calling. + ASTContext &Ctx = getContext(); + DeclarationName Name = Ctx.DeclarationNames + .getCXXOperatorName(IsDelete ? OO_Delete : OO_New); + for (auto *Decl : Ctx.getTranslationUnitDecl()->lookup(Name)) + if (Ctx.hasSameType(cast(Decl)->getType(), QualType(Type, 0))) + return EmitNewDeleteCall(*this, cast(Decl), Type, Args); + llvm_unreachable("predeclared global operator new/delete is missing"); +} + namespace { /// A cleanup to call the given 'operator delete' function upon /// abnormal exit from a new expression. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index d1e63a710b..b6c58e0ee1 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1659,6 +1659,9 @@ public: void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr, QualType DeleteTy); + RValue EmitBuiltinNewDeleteCall(const FunctionProtoType *Type, + const Expr *Arg, bool IsDelete); + llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E); llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE); llvm::Value* EmitCXXUuidofExpr(const CXXUuidofExpr *E); @@ -2641,7 +2644,8 @@ public: void EmitCallArgs(CallArgList &Args, ArrayRef ArgTypes, CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd, bool ForceColumnInfo); + CallExpr::const_arg_iterator ArgEnd, + bool ForceColumnInfo = false); private: const TargetCodeGenInfo &getTargetHooks() const { diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 60514efd55..916ce7d985 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -296,8 +296,22 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinAddressof(*this, TheCall)) return ExprError(); break; + case Builtin::BI__builtin_operator_new: + case Builtin::BI__builtin_operator_delete: + if (!getLangOpts().CPlusPlus) { + Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) + << (BuiltinID == Builtin::BI__builtin_operator_new + ? "__builtin_operator_new" + : "__builtin_operator_delete") + << "C++"; + return ExprError(); + } + // CodeGen assumes it can find the global new and delete to call, + // so ensure that they are declared. + DeclareGlobalNewDelete(); + break; } - + // Since the target specific builtins for each arch overlap, only check those // of the arch we are compiling for. if (BuiltinID >= Builtin::FirstTSBuiltin) { diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp index 26db84225f..d8aa258cbb 100644 --- a/test/CodeGenCXX/new.cpp +++ b/test/CodeGenCXX/new.cpp @@ -326,6 +326,15 @@ namespace N3664 { } } +namespace builtins { + // CHECK-LABEL: define void @_ZN8builtins1fEv + void f() { + // CHECK: call noalias i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW]] + // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE]] + __builtin_operator_delete(__builtin_operator_new(4)); + } +} + // CHECK-DAG: attributes [[ATTR_NOBUILTIN]] = {{[{].*}} nobuiltin {{.*[}]}} // CHECK-DAG: attributes [[ATTR_NOBUILTIN_NOUNWIND]] = {{[{].*}} nobuiltin nounwind {{.*[}]}} diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c index 8ca33c8e75..7647100bc2 100644 --- a/test/Sema/builtins.c +++ b/test/Sema/builtins.c @@ -197,3 +197,8 @@ void no_ms_builtins() { __noop(1); // expected-warning {{implicit declaration}} __debugbreak(); // expected-warning {{implicit declaration}} } + +void unavailable() { + __builtin_operator_new(0); // expected-error {{'__builtin_operator_new' is only available in C++}} + __builtin_operator_delete(0); // expected-error {{'__builtin_operator_delete' is only available in C++}} +}