[clang][bytecode] Implement using operator new/operator delete (#107679)
Reuse the __builtin_operator_{new,delete} implementations.
This commit is contained in:
parent
7d4afba831
commit
78cf9b830c
@ -4070,18 +4070,18 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
|
||||
}
|
||||
|
||||
template <class Emitter>
|
||||
bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
|
||||
bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
|
||||
unsigned BuiltinID) {
|
||||
const Function *Func = getFunction(E->getDirectCallee());
|
||||
if (!Func)
|
||||
return false;
|
||||
|
||||
// For these, we're expected to ultimately return an APValue pointing
|
||||
// to the CallExpr. This is needed to get the correct codegen.
|
||||
unsigned Builtin = E->getBuiltinCallee();
|
||||
if (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
|
||||
Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
|
||||
Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
|
||||
Builtin == Builtin::BI__builtin_function_start) {
|
||||
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
|
||||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString ||
|
||||
BuiltinID == Builtin::BI__builtin_ptrauth_sign_constant ||
|
||||
BuiltinID == Builtin::BI__builtin_function_start) {
|
||||
if (std::optional<unsigned> GlobalOffset = P.createGlobal(E)) {
|
||||
if (!this->emitGetPtrGlobal(*GlobalOffset, E))
|
||||
return false;
|
||||
@ -4113,7 +4113,7 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->emitCallBI(Func, E, E))
|
||||
if (!this->emitCallBI(Func, E, BuiltinID, E))
|
||||
return false;
|
||||
|
||||
if (DiscardResult && !ReturnType->isVoidType()) {
|
||||
@ -4126,13 +4126,24 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
|
||||
|
||||
template <class Emitter>
|
||||
bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
|
||||
if (E->getBuiltinCallee())
|
||||
return VisitBuiltinCallExpr(E);
|
||||
if (unsigned BuiltinID = E->getBuiltinCallee())
|
||||
return VisitBuiltinCallExpr(E, BuiltinID);
|
||||
|
||||
const FunctionDecl *FuncDecl = E->getDirectCallee();
|
||||
// Calls to replaceable operator new/operator delete.
|
||||
if (FuncDecl && FuncDecl->isReplaceableGlobalAllocationFunction()) {
|
||||
if (FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_New ||
|
||||
FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Array_New) {
|
||||
return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new);
|
||||
} else {
|
||||
assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete);
|
||||
return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete);
|
||||
}
|
||||
}
|
||||
|
||||
QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
|
||||
std::optional<PrimType> T = classify(ReturnType);
|
||||
bool HasRVO = !ReturnType->isVoidType() && !T;
|
||||
const FunctionDecl *FuncDecl = E->getDirectCallee();
|
||||
|
||||
if (HasRVO) {
|
||||
if (DiscardResult) {
|
||||
|
||||
@ -133,7 +133,7 @@ public:
|
||||
bool VisitVectorBinOp(const BinaryOperator *E);
|
||||
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
|
||||
bool VisitCallExpr(const CallExpr *E);
|
||||
bool VisitBuiltinCallExpr(const CallExpr *E);
|
||||
bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);
|
||||
bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
|
||||
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
|
||||
bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
|
||||
|
||||
@ -1178,7 +1178,7 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
|
||||
}
|
||||
|
||||
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
|
||||
const CallExpr *CE) {
|
||||
const CallExpr *CE, uint32_t BuiltinID) {
|
||||
if (S.checkingPotentialConstantExpression())
|
||||
return false;
|
||||
auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
|
||||
@ -1186,7 +1186,7 @@ bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
|
||||
InterpFrame *FrameBefore = S.Current;
|
||||
S.Current = NewFrame.get();
|
||||
|
||||
if (InterpretBuiltin(S, PC, Func, CE)) {
|
||||
if (InterpretBuiltin(S, PC, Func, CE, BuiltinID)) {
|
||||
NewFrame.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -155,7 +155,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
|
||||
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
|
||||
uint32_t VarArgSize);
|
||||
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
|
||||
const CallExpr *CE);
|
||||
const CallExpr *CE, uint32_t BuiltinID);
|
||||
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
|
||||
const CallExpr *CE);
|
||||
|
||||
@ -268,7 +268,7 @@ bool Interpret(InterpState &S, APValue &Result);
|
||||
|
||||
/// Interpret a builtin function.
|
||||
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
|
||||
const CallExpr *Call);
|
||||
const CallExpr *Call, uint32_t BuiltinID);
|
||||
|
||||
/// Interpret an offsetof operation.
|
||||
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
|
||||
|
||||
@ -1395,13 +1395,13 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
|
||||
}
|
||||
|
||||
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
|
||||
const CallExpr *Call) {
|
||||
const CallExpr *Call, uint32_t BuiltinID) {
|
||||
const InterpFrame *Frame = S.Current;
|
||||
APValue Dummy;
|
||||
|
||||
std::optional<PrimType> ReturnT = S.getContext().classify(Call);
|
||||
|
||||
switch (F->getBuiltinID()) {
|
||||
switch (BuiltinID) {
|
||||
case Builtin::BI__builtin_is_constant_evaluated:
|
||||
if (!interp__builtin_is_constant_evaluated(S, OpPC, Frame, Call))
|
||||
return false;
|
||||
|
||||
@ -202,7 +202,7 @@ def CallVirt : Opcode {
|
||||
}
|
||||
|
||||
def CallBI : Opcode {
|
||||
let Args = [ArgFunction, ArgCallExpr];
|
||||
let Args = [ArgFunction, ArgCallExpr, ArgUint32];
|
||||
}
|
||||
|
||||
def CallPtr : Opcode {
|
||||
|
||||
@ -601,6 +601,19 @@ namespace std {
|
||||
};
|
||||
}
|
||||
|
||||
/// Specialization for float, using operator new/delete.
|
||||
namespace std {
|
||||
using size_t = decltype(sizeof(0));
|
||||
template<> struct allocator<float> {
|
||||
constexpr float *allocate(size_t N) {
|
||||
return (float*)operator new (sizeof(float) * N);
|
||||
}
|
||||
constexpr void deallocate(void *p) {
|
||||
operator delete(p);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace OperatorNewDelete {
|
||||
|
||||
constexpr bool mismatched(int alloc_kind, int dealloc_kind) {
|
||||
@ -696,6 +709,7 @@ namespace OperatorNewDelete {
|
||||
constexpr int no_deallocate_nullptr = (std::allocator<int>().deallocate(nullptr), 1); // both-error {{constant expression}} \
|
||||
// both-note {{in call}}
|
||||
|
||||
static_assert((std::allocator<float>().deallocate(std::allocator<float>().allocate(10)), 1) == 1);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user