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.

llvm-svn: 210137
This commit is contained in:
Richard Smith 2014-06-03 23:27:44 +00:00
parent 08d84943af
commit 760520bcb7
9 changed files with 79 additions and 3 deletions

View File

@ -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
----------------------------------

View File

@ -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

View File

@ -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">;

View File

@ -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<FunctionProtoType>(),
E->getArg(0), false);
case Builtin::BI__builtin_operator_delete:
return EmitBuiltinNewDeleteCall(FD->getType()->castAs<FunctionProtoType>(),
E->getArg(0), true);
case Builtin::BI__noop:
return RValue::get(nullptr);
case Builtin::BI_InterlockedCompareExchange: {

View File

@ -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<FunctionDecl>(Decl)->getType(), QualType(Type, 0)))
return EmitNewDeleteCall(*this, cast<FunctionDecl>(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.

View File

@ -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<QualType> 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 {

View File

@ -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) {

View File

@ -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 {{.*[}]}}

View File

@ -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++}}
}