forked from OSchip/llvm-project
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:
parent
08d84943af
commit
760520bcb7
|
@ -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
|
||||
----------------------------------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {{.*[}]}}
|
||||
|
||||
|
|
|
@ -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++}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue