Skip to content

Commit 78cf9b8

Browse files
authored
[clang][bytecode] Implement using operator new/operator delete (llvm#107679)
Reuse the __builtin_operator_{new,delete} implementations.
1 parent 7d4afba commit 78cf9b8

File tree

7 files changed

+43
-18
lines changed

7 files changed

+43
-18
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4070,18 +4070,18 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
40704070
}
40714071

40724072
template <class Emitter>
4073-
bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
4073+
bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
4074+
unsigned BuiltinID) {
40744075
const Function *Func = getFunction(E->getDirectCallee());
40754076
if (!Func)
40764077
return false;
40774078

40784079
// For these, we're expected to ultimately return an APValue pointing
40794080
// to the CallExpr. This is needed to get the correct codegen.
4080-
unsigned Builtin = E->getBuiltinCallee();
4081-
if (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
4082-
Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
4083-
Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
4084-
Builtin == Builtin::BI__builtin_function_start) {
4081+
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
4082+
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString ||
4083+
BuiltinID == Builtin::BI__builtin_ptrauth_sign_constant ||
4084+
BuiltinID == Builtin::BI__builtin_function_start) {
40854085
if (std::optional<unsigned> GlobalOffset = P.createGlobal(E)) {
40864086
if (!this->emitGetPtrGlobal(*GlobalOffset, E))
40874087
return false;
@@ -4113,7 +4113,7 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
41134113
}
41144114
}
41154115

4116-
if (!this->emitCallBI(Func, E, E))
4116+
if (!this->emitCallBI(Func, E, BuiltinID, E))
41174117
return false;
41184118

41194119
if (DiscardResult && !ReturnType->isVoidType()) {
@@ -4126,13 +4126,24 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
41264126

41274127
template <class Emitter>
41284128
bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
4129-
if (E->getBuiltinCallee())
4130-
return VisitBuiltinCallExpr(E);
4129+
if (unsigned BuiltinID = E->getBuiltinCallee())
4130+
return VisitBuiltinCallExpr(E, BuiltinID);
4131+
4132+
const FunctionDecl *FuncDecl = E->getDirectCallee();
4133+
// Calls to replaceable operator new/operator delete.
4134+
if (FuncDecl && FuncDecl->isReplaceableGlobalAllocationFunction()) {
4135+
if (FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_New ||
4136+
FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Array_New) {
4137+
return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new);
4138+
} else {
4139+
assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete);
4140+
return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete);
4141+
}
4142+
}
41314143

41324144
QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
41334145
std::optional<PrimType> T = classify(ReturnType);
41344146
bool HasRVO = !ReturnType->isVoidType() && !T;
4135-
const FunctionDecl *FuncDecl = E->getDirectCallee();
41364147

41374148
if (HasRVO) {
41384149
if (DiscardResult) {

clang/lib/AST/ByteCode/Compiler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
133133
bool VisitVectorBinOp(const BinaryOperator *E);
134134
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
135135
bool VisitCallExpr(const CallExpr *E);
136-
bool VisitBuiltinCallExpr(const CallExpr *E);
136+
bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);
137137
bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
138138
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
139139
bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,15 +1178,15 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
11781178
}
11791179

11801180
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
1181-
const CallExpr *CE) {
1181+
const CallExpr *CE, uint32_t BuiltinID) {
11821182
if (S.checkingPotentialConstantExpression())
11831183
return false;
11841184
auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
11851185

11861186
InterpFrame *FrameBefore = S.Current;
11871187
S.Current = NewFrame.get();
11881188

1189-
if (InterpretBuiltin(S, PC, Func, CE)) {
1189+
if (InterpretBuiltin(S, PC, Func, CE, BuiltinID)) {
11901190
NewFrame.release();
11911191
return true;
11921192
}

clang/lib/AST/ByteCode/Interp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
155155
bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
156156
uint32_t VarArgSize);
157157
bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
158-
const CallExpr *CE);
158+
const CallExpr *CE, uint32_t BuiltinID);
159159
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
160160
const CallExpr *CE);
161161

@@ -268,7 +268,7 @@ bool Interpret(InterpState &S, APValue &Result);
268268

269269
/// Interpret a builtin function.
270270
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
271-
const CallExpr *Call);
271+
const CallExpr *Call, uint32_t BuiltinID);
272272

273273
/// Interpret an offsetof operation.
274274
bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,13 +1395,13 @@ static bool interp__builtin_operator_delete(InterpState &S, CodePtr OpPC,
13951395
}
13961396

13971397
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
1398-
const CallExpr *Call) {
1398+
const CallExpr *Call, uint32_t BuiltinID) {
13991399
const InterpFrame *Frame = S.Current;
14001400
APValue Dummy;
14011401

14021402
std::optional<PrimType> ReturnT = S.getContext().classify(Call);
14031403

1404-
switch (F->getBuiltinID()) {
1404+
switch (BuiltinID) {
14051405
case Builtin::BI__builtin_is_constant_evaluated:
14061406
if (!interp__builtin_is_constant_evaluated(S, OpPC, Frame, Call))
14071407
return false;

clang/lib/AST/ByteCode/Opcodes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def CallVirt : Opcode {
202202
}
203203

204204
def CallBI : Opcode {
205-
let Args = [ArgFunction, ArgCallExpr];
205+
let Args = [ArgFunction, ArgCallExpr, ArgUint32];
206206
}
207207

208208
def CallPtr : Opcode {

clang/test/AST/ByteCode/new-delete.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,19 @@ namespace std {
601601
};
602602
}
603603

604+
/// Specialization for float, using operator new/delete.
605+
namespace std {
606+
using size_t = decltype(sizeof(0));
607+
template<> struct allocator<float> {
608+
constexpr float *allocate(size_t N) {
609+
return (float*)operator new (sizeof(float) * N);
610+
}
611+
constexpr void deallocate(void *p) {
612+
operator delete(p);
613+
}
614+
};
615+
}
616+
604617
namespace OperatorNewDelete {
605618

606619
constexpr bool mismatched(int alloc_kind, int dealloc_kind) {
@@ -696,6 +709,7 @@ namespace OperatorNewDelete {
696709
constexpr int no_deallocate_nullptr = (std::allocator<int>().deallocate(nullptr), 1); // both-error {{constant expression}} \
697710
// both-note {{in call}}
698711

712+
static_assert((std::allocator<float>().deallocate(std::allocator<float>().allocate(10)), 1) == 1);
699713
}
700714

701715
#else

0 commit comments

Comments
 (0)