Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Context.cpp
213799 views
1
//===--- Context.cpp - Context for the constexpr VM -------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "Context.h"
10
#include "ByteCodeEmitter.h"
11
#include "Compiler.h"
12
#include "EvalEmitter.h"
13
#include "Interp.h"
14
#include "InterpFrame.h"
15
#include "InterpStack.h"
16
#include "PrimType.h"
17
#include "Program.h"
18
#include "clang/AST/Expr.h"
19
#include "clang/Basic/TargetInfo.h"
20
21
using namespace clang;
22
using namespace clang::interp;
23
24
Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {
25
this->ShortWidth = Ctx.getTargetInfo().getShortWidth();
26
this->IntWidth = Ctx.getTargetInfo().getIntWidth();
27
this->LongWidth = Ctx.getTargetInfo().getLongWidth();
28
this->LongLongWidth = Ctx.getTargetInfo().getLongLongWidth();
29
assert(Ctx.getTargetInfo().getCharWidth() == 8 &&
30
"We're assuming 8 bit chars");
31
}
32
33
Context::~Context() {}
34
35
bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
36
assert(Stk.empty());
37
38
// Get a function handle.
39
const Function *Func = getOrCreateFunction(FD);
40
if (!Func)
41
return false;
42
43
// Compile the function.
44
Compiler<ByteCodeEmitter>(*this, *P).compileFunc(
45
FD, const_cast<Function *>(Func));
46
47
++EvalID;
48
// And run it.
49
if (!Run(Parent, Func))
50
return false;
51
52
return Func->isValid();
53
}
54
55
bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
56
++EvalID;
57
bool Recursing = !Stk.empty();
58
size_t StackSizeBefore = Stk.size();
59
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
60
61
auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());
62
63
if (Res.isInvalid()) {
64
C.cleanup();
65
Stk.clearTo(StackSizeBefore);
66
return false;
67
}
68
69
if (!Recursing) {
70
// We *can* actually get here with a non-empty stack, since
71
// things like InterpState::noteSideEffect() exist.
72
C.cleanup();
73
#ifndef NDEBUG
74
// Make sure we don't rely on some value being still alive in
75
// InterpStack memory.
76
Stk.clearTo(StackSizeBefore);
77
#endif
78
}
79
80
Result = Res.toAPValue();
81
82
return true;
83
}
84
85
bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
86
ConstantExprKind Kind) {
87
++EvalID;
88
bool Recursing = !Stk.empty();
89
size_t StackSizeBefore = Stk.size();
90
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
91
92
auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,
93
/*DestroyToplevelScope=*/true);
94
if (Res.isInvalid()) {
95
C.cleanup();
96
Stk.clearTo(StackSizeBefore);
97
return false;
98
}
99
100
if (!Recursing) {
101
assert(Stk.empty());
102
C.cleanup();
103
#ifndef NDEBUG
104
// Make sure we don't rely on some value being still alive in
105
// InterpStack memory.
106
Stk.clearTo(StackSizeBefore);
107
#endif
108
}
109
110
Result = Res.toAPValue();
111
return true;
112
}
113
114
bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
115
APValue &Result) {
116
++EvalID;
117
bool Recursing = !Stk.empty();
118
size_t StackSizeBefore = Stk.size();
119
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
120
121
bool CheckGlobalInitialized =
122
shouldBeGloballyIndexed(VD) &&
123
(VD->getType()->isRecordType() || VD->getType()->isArrayType());
124
auto Res = C.interpretDecl(VD, CheckGlobalInitialized);
125
if (Res.isInvalid()) {
126
C.cleanup();
127
Stk.clearTo(StackSizeBefore);
128
129
return false;
130
}
131
132
if (!Recursing) {
133
assert(Stk.empty());
134
C.cleanup();
135
#ifndef NDEBUG
136
// Make sure we don't rely on some value being still alive in
137
// InterpStack memory.
138
Stk.clearTo(StackSizeBefore);
139
#endif
140
}
141
142
Result = Res.toAPValue();
143
return true;
144
}
145
146
template <typename ResultT>
147
bool Context::evaluateStringRepr(State &Parent, const Expr *SizeExpr,
148
const Expr *PtrExpr, ResultT &Result) {
149
assert(Stk.empty());
150
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
151
152
// Evaluate size value.
153
APValue SizeValue;
154
if (!evaluateAsRValue(Parent, SizeExpr, SizeValue))
155
return false;
156
157
if (!SizeValue.isInt())
158
return false;
159
uint64_t Size = SizeValue.getInt().getZExtValue();
160
161
auto PtrRes = C.interpretAsPointer(PtrExpr, [&](const Pointer &Ptr) {
162
if (Size == 0) {
163
if constexpr (std::is_same_v<ResultT, APValue>)
164
Result = APValue(APValue::UninitArray{}, 0, 0);
165
return true;
166
}
167
168
if (!Ptr.isLive() || !Ptr.getFieldDesc()->isPrimitiveArray())
169
return false;
170
171
// Must be char.
172
if (Ptr.getFieldDesc()->getElemSize() != 1 /*bytes*/)
173
return false;
174
175
if (Size > Ptr.getNumElems()) {
176
Parent.FFDiag(SizeExpr, diag::note_constexpr_access_past_end) << AK_Read;
177
Size = Ptr.getNumElems();
178
}
179
180
if constexpr (std::is_same_v<ResultT, APValue>) {
181
QualType CharTy = PtrExpr->getType()->getPointeeType();
182
Result = APValue(APValue::UninitArray{}, Size, Size);
183
for (uint64_t I = 0; I != Size; ++I) {
184
if (std::optional<APValue> ElemVal =
185
Ptr.atIndex(I).toRValue(*this, CharTy))
186
Result.getArrayInitializedElt(I) = *ElemVal;
187
else
188
return false;
189
}
190
} else {
191
assert((std::is_same_v<ResultT, std::string>));
192
if (Size < Result.max_size())
193
Result.resize(Size);
194
Result.assign(reinterpret_cast<const char *>(Ptr.getRawAddress()), Size);
195
}
196
197
return true;
198
});
199
200
if (PtrRes.isInvalid()) {
201
C.cleanup();
202
Stk.clear();
203
return false;
204
}
205
206
return true;
207
}
208
209
bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,
210
const Expr *PtrExpr, APValue &Result) {
211
assert(SizeExpr);
212
assert(PtrExpr);
213
214
return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);
215
}
216
217
bool Context::evaluateCharRange(State &Parent, const Expr *SizeExpr,
218
const Expr *PtrExpr, std::string &Result) {
219
assert(SizeExpr);
220
assert(PtrExpr);
221
222
return evaluateStringRepr(Parent, SizeExpr, PtrExpr, Result);
223
}
224
225
const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
226
227
static PrimType integralTypeToPrimTypeS(unsigned BitWidth) {
228
switch (BitWidth) {
229
case 64:
230
return PT_Sint64;
231
case 32:
232
return PT_Sint32;
233
case 16:
234
return PT_Sint16;
235
case 8:
236
return PT_Sint8;
237
default:
238
return PT_IntAPS;
239
}
240
llvm_unreachable("Unhandled BitWidth");
241
}
242
243
static PrimType integralTypeToPrimTypeU(unsigned BitWidth) {
244
switch (BitWidth) {
245
case 64:
246
return PT_Uint64;
247
case 32:
248
return PT_Uint32;
249
case 16:
250
return PT_Uint16;
251
case 8:
252
return PT_Uint8;
253
default:
254
return PT_IntAP;
255
}
256
llvm_unreachable("Unhandled BitWidth");
257
}
258
259
std::optional<PrimType> Context::classify(QualType T) const {
260
261
if (const auto *BT = dyn_cast<BuiltinType>(T.getCanonicalType())) {
262
auto Kind = BT->getKind();
263
if (Kind == BuiltinType::Bool)
264
return PT_Bool;
265
if (Kind == BuiltinType::NullPtr)
266
return PT_Ptr;
267
if (Kind == BuiltinType::BoundMember)
268
return PT_MemberPtr;
269
270
// Just trying to avoid the ASTContext::getIntWidth call below.
271
if (Kind == BuiltinType::Short)
272
return integralTypeToPrimTypeS(this->ShortWidth);
273
if (Kind == BuiltinType::UShort)
274
return integralTypeToPrimTypeU(this->ShortWidth);
275
276
if (Kind == BuiltinType::Int)
277
return integralTypeToPrimTypeS(this->IntWidth);
278
if (Kind == BuiltinType::UInt)
279
return integralTypeToPrimTypeU(this->IntWidth);
280
if (Kind == BuiltinType::Long)
281
return integralTypeToPrimTypeS(this->LongWidth);
282
if (Kind == BuiltinType::ULong)
283
return integralTypeToPrimTypeU(this->LongWidth);
284
if (Kind == BuiltinType::LongLong)
285
return integralTypeToPrimTypeS(this->LongLongWidth);
286
if (Kind == BuiltinType::ULongLong)
287
return integralTypeToPrimTypeU(this->LongLongWidth);
288
289
if (Kind == BuiltinType::SChar || Kind == BuiltinType::Char_S)
290
return integralTypeToPrimTypeS(8);
291
if (Kind == BuiltinType::UChar || Kind == BuiltinType::Char_U ||
292
Kind == BuiltinType::Char8)
293
return integralTypeToPrimTypeU(8);
294
295
if (BT->isSignedInteger())
296
return integralTypeToPrimTypeS(Ctx.getIntWidth(T));
297
if (BT->isUnsignedInteger())
298
return integralTypeToPrimTypeU(Ctx.getIntWidth(T));
299
300
if (BT->isFloatingPoint())
301
return PT_Float;
302
}
303
304
if (T->isPointerOrReferenceType())
305
return PT_Ptr;
306
307
if (T->isMemberPointerType())
308
return PT_MemberPtr;
309
310
if (const auto *BT = T->getAs<BitIntType>()) {
311
if (BT->isSigned())
312
return integralTypeToPrimTypeS(BT->getNumBits());
313
return integralTypeToPrimTypeU(BT->getNumBits());
314
}
315
316
if (const auto *ET = T->getAs<EnumType>()) {
317
const auto *D = ET->getDecl();
318
if (!D->isComplete())
319
return std::nullopt;
320
return classify(D->getIntegerType());
321
}
322
323
if (const auto *AT = T->getAs<AtomicType>())
324
return classify(AT->getValueType());
325
326
if (const auto *DT = dyn_cast<DecltypeType>(T))
327
return classify(DT->getUnderlyingType());
328
329
if (T->isObjCObjectPointerType() || T->isBlockPointerType())
330
return PT_Ptr;
331
332
if (T->isFixedPointType())
333
return PT_FixedPoint;
334
335
// Vector and complex types get here.
336
return std::nullopt;
337
}
338
339
unsigned Context::getCharBit() const {
340
return Ctx.getTargetInfo().getCharWidth();
341
}
342
343
/// Simple wrapper around getFloatTypeSemantics() to make code a
344
/// little shorter.
345
const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
346
return Ctx.getFloatTypeSemantics(T);
347
}
348
349
bool Context::Run(State &Parent, const Function *Func) {
350
351
{
352
InterpState State(Parent, *P, Stk, *this, Func);
353
if (Interpret(State)) {
354
assert(Stk.empty());
355
return true;
356
}
357
// State gets destroyed here, so the Stk.clear() below doesn't accidentally
358
// remove values the State's destructor might access.
359
}
360
361
Stk.clear();
362
return false;
363
}
364
365
// TODO: Virtual bases?
366
const CXXMethodDecl *
367
Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,
368
const CXXRecordDecl *StaticDecl,
369
const CXXMethodDecl *InitialFunction) const {
370
assert(DynamicDecl);
371
assert(StaticDecl);
372
assert(InitialFunction);
373
374
const CXXRecordDecl *CurRecord = DynamicDecl;
375
const CXXMethodDecl *FoundFunction = InitialFunction;
376
for (;;) {
377
const CXXMethodDecl *Overrider =
378
FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false);
379
if (Overrider)
380
return Overrider;
381
382
// Common case of only one base class.
383
if (CurRecord->getNumBases() == 1) {
384
CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl();
385
continue;
386
}
387
388
// Otherwise, go to the base class that will lead to the StaticDecl.
389
for (const CXXBaseSpecifier &Spec : CurRecord->bases()) {
390
const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();
391
if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {
392
CurRecord = Base;
393
break;
394
}
395
}
396
}
397
398
llvm_unreachable(
399
"Couldn't find an overriding function in the class hierarchy?");
400
return nullptr;
401
}
402
403
const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) {
404
assert(FuncDecl);
405
FuncDecl = FuncDecl->getMostRecentDecl();
406
407
if (const Function *Func = P->getFunction(FuncDecl))
408
return Func;
409
410
// Manually created functions that haven't been assigned proper
411
// parameters yet.
412
if (!FuncDecl->param_empty() && !FuncDecl->param_begin())
413
return nullptr;
414
415
bool IsLambdaStaticInvoker = false;
416
if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);
417
MD && MD->isLambdaStaticInvoker()) {
418
// For a lambda static invoker, we might have to pick a specialized
419
// version if the lambda is generic. In that case, the picked function
420
// will *NOT* be a static invoker anymore. However, it will still
421
// be a non-static member function, this (usually) requiring an
422
// instance pointer. We suppress that later in this function.
423
IsLambdaStaticInvoker = true;
424
425
const CXXRecordDecl *ClosureClass = MD->getParent();
426
assert(ClosureClass->captures_begin() == ClosureClass->captures_end());
427
if (ClosureClass->isGenericLambda()) {
428
const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator();
429
assert(MD->isFunctionTemplateSpecialization() &&
430
"A generic lambda's static-invoker function must be a "
431
"template specialization");
432
const TemplateArgumentList *TAL = MD->getTemplateSpecializationArgs();
433
FunctionTemplateDecl *CallOpTemplate =
434
LambdaCallOp->getDescribedFunctionTemplate();
435
void *InsertPos = nullptr;
436
const FunctionDecl *CorrespondingCallOpSpecialization =
437
CallOpTemplate->findSpecialization(TAL->asArray(), InsertPos);
438
assert(CorrespondingCallOpSpecialization);
439
FuncDecl = CorrespondingCallOpSpecialization;
440
}
441
}
442
// Set up argument indices.
443
unsigned ParamOffset = 0;
444
SmallVector<PrimType, 8> ParamTypes;
445
SmallVector<unsigned, 8> ParamOffsets;
446
llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
447
448
// If the return is not a primitive, a pointer to the storage where the
449
// value is initialized in is passed as the first argument. See 'RVO'
450
// elsewhere in the code.
451
QualType Ty = FuncDecl->getReturnType();
452
bool HasRVO = false;
453
if (!Ty->isVoidType() && !classify(Ty)) {
454
HasRVO = true;
455
ParamTypes.push_back(PT_Ptr);
456
ParamOffsets.push_back(ParamOffset);
457
ParamOffset += align(primSize(PT_Ptr));
458
}
459
460
// If the function decl is a member decl, the next parameter is
461
// the 'this' pointer. This parameter is pop()ed from the
462
// InterpStack when calling the function.
463
bool HasThisPointer = false;
464
if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl)) {
465
if (!IsLambdaStaticInvoker) {
466
HasThisPointer = MD->isInstance();
467
if (MD->isImplicitObjectMemberFunction()) {
468
ParamTypes.push_back(PT_Ptr);
469
ParamOffsets.push_back(ParamOffset);
470
ParamOffset += align(primSize(PT_Ptr));
471
}
472
}
473
474
if (isLambdaCallOperator(MD)) {
475
// The parent record needs to be complete, we need to know about all
476
// the lambda captures.
477
if (!MD->getParent()->isCompleteDefinition())
478
return nullptr;
479
llvm::DenseMap<const ValueDecl *, FieldDecl *> LC;
480
FieldDecl *LTC;
481
482
MD->getParent()->getCaptureFields(LC, LTC);
483
484
if (MD->isStatic() && !LC.empty()) {
485
// Static lambdas cannot have any captures. If this one does,
486
// it has already been diagnosed and we can only ignore it.
487
return nullptr;
488
}
489
}
490
}
491
492
// Assign descriptors to all parameters.
493
// Composite objects are lowered to pointers.
494
for (const ParmVarDecl *PD : FuncDecl->parameters()) {
495
std::optional<PrimType> T = classify(PD->getType());
496
PrimType PT = T.value_or(PT_Ptr);
497
Descriptor *Desc = P->createDescriptor(PD, PT);
498
ParamDescriptors.insert({ParamOffset, {PT, Desc}});
499
ParamOffsets.push_back(ParamOffset);
500
ParamOffset += align(primSize(PT));
501
ParamTypes.push_back(PT);
502
}
503
504
// Create a handle over the emitted code.
505
assert(!P->getFunction(FuncDecl));
506
const Function *Func = P->createFunction(
507
FuncDecl, ParamOffset, std::move(ParamTypes), std::move(ParamDescriptors),
508
std::move(ParamOffsets), HasThisPointer, HasRVO, IsLambdaStaticInvoker);
509
return Func;
510
}
511
512
const Function *Context::getOrCreateObjCBlock(const BlockExpr *E) {
513
const BlockDecl *BD = E->getBlockDecl();
514
// Set up argument indices.
515
unsigned ParamOffset = 0;
516
SmallVector<PrimType, 8> ParamTypes;
517
SmallVector<unsigned, 8> ParamOffsets;
518
llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
519
520
// Assign descriptors to all parameters.
521
// Composite objects are lowered to pointers.
522
for (const ParmVarDecl *PD : BD->parameters()) {
523
std::optional<PrimType> T = classify(PD->getType());
524
PrimType PT = T.value_or(PT_Ptr);
525
Descriptor *Desc = P->createDescriptor(PD, PT);
526
ParamDescriptors.insert({ParamOffset, {PT, Desc}});
527
ParamOffsets.push_back(ParamOffset);
528
ParamOffset += align(primSize(PT));
529
ParamTypes.push_back(PT);
530
}
531
532
if (BD->hasCaptures())
533
return nullptr;
534
535
// Create a handle over the emitted code.
536
Function *Func =
537
P->createFunction(E, ParamOffset, std::move(ParamTypes),
538
std::move(ParamDescriptors), std::move(ParamOffsets),
539
/*HasThisPointer=*/false, /*HasRVO=*/false,
540
/*IsLambdaStaticInvoker=*/false);
541
542
assert(Func);
543
Func->setDefined(true);
544
// We don't compile the BlockDecl code at all right now.
545
Func->setIsFullyCompiled(true);
546
return Func;
547
}
548
549
unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,
550
const RecordDecl *DerivedDecl) const {
551
assert(BaseDecl);
552
assert(DerivedDecl);
553
const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);
554
const RecordDecl *CurDecl = DerivedDecl;
555
const Record *CurRecord = P->getOrCreateRecord(CurDecl);
556
assert(CurDecl && FinalDecl);
557
558
unsigned OffsetSum = 0;
559
for (;;) {
560
assert(CurRecord->getNumBases() > 0);
561
// One level up
562
for (const Record::Base &B : CurRecord->bases()) {
563
const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);
564
565
if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {
566
OffsetSum += B.Offset;
567
CurRecord = B.R;
568
CurDecl = BaseDecl;
569
break;
570
}
571
}
572
if (CurDecl == FinalDecl)
573
break;
574
}
575
576
assert(OffsetSum > 0);
577
return OffsetSum;
578
}
579
580
const Record *Context::getRecord(const RecordDecl *D) const {
581
return P->getOrCreateRecord(D);
582
}
583
584
bool Context::isUnevaluatedBuiltin(unsigned ID) {
585
return ID == Builtin::BI__builtin_classify_type ||
586
ID == Builtin::BI__builtin_os_log_format_buffer_size ||
587
ID == Builtin::BI__builtin_constant_p || ID == Builtin::BI__noop;
588
}
589
590