clang: lib/AST/ByteCode/EvalEmitter.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

14

15using namespace clang;

17

20 : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {}

21

23 for (auto &V : Locals) {

24 Block *B = reinterpret_cast<Block *>(V.get());

27 }

28}

29

30

31

32

34

36 bool ConvertResultToRValue,

37 bool DestroyToplevelScope) {

39 this->ConvertResultToRValue = ConvertResultToRValue && isa<ConstantExpr>(E);

41 EvalResult.setSource(E);

42

43 if (!this->visitExpr(E, DestroyToplevelScope)) {

44

45

46 EvalResult.setInvalid();

47 }

48

49 return std::move(this->EvalResult);

50}

51

53 bool CheckFullyInitialized) {

54 assert(VD);

56 this->CheckFullyInitialized = CheckFullyInitialized;

57 S.EvaluatingDecl = VD;

59 EvalResult.setSource(VD);

60

62 this->ConvertResultToRValue = Init->isGLValue() && T->isPointerType() &&

63 T->isObjCObjectPointerType();

64 EvalResult.setSource(VD);

65

67 EvalResult.setInvalid();

68

69 S.EvaluatingDecl = nullptr;

70 updateGlobalTemporaries();

71 return std::move(this->EvalResult);

72}

73

76

78 this->ConvertResultToRValue = false;

79 this->CheckFullyInitialized = false;

80 this->PtrCB = PtrCB;

81 EvalResult.setSource(E);

82

83 if (!this->visitExpr(E, true)) {

84

85

86 EvalResult.setInvalid();

87 }

88

89 return std::move(this->EvalResult);

90}

91

93

94

96 this->Params.insert({PD, {0, false}});

97 }

98

99 return this->visitExpr(E, false);

100}

101

103

105

107

108 auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());

109 auto *B = new (Memory.get()) Block(Ctx.getEvalID(), D, false);

110 B->invokeCtor();

111

112

114 Desc.Desc = D;

121

122

123 unsigned Off = Locals.size();

124 Locals.push_back(std::move(Memory));

125 return {Off, D};

126}

127

130 if (S.Stk.pop<bool>())

131 ActiveLabel = Label;

132 }

133 return true;

134}

135

138 if (!S.Stk.pop<bool>())

139 ActiveLabel = Label;

140 }

141 return true;

142}

143

146 CurrentLabel = ActiveLabel = Label;

147 return true;

148}

149

152 ActiveLabel = Label;

153 CurrentLabel = Label;

154 return true;

155}

156

158 size_t StackSizeBefore = S.Stk.size();

160 if (!this->visit(Arg)) {

161 S.Stk.clearTo(StackSizeBefore);

162

163 if (S.inConstantContext() || Arg->HasSideEffects(S.getASTContext()))

164 return this->emitBool(false, E);

166 }

167

170 const auto &Ptr = S.Stk.pop<Pointer>();

172 }

173

174

175 if (!this->emitPop(T, E))

176 return false;

177 return this->emitBool(true, E);

178}

179

180template bool EvalEmitter::emitRet(SourceInfo Info) {

182 return true;

183

186 return true;

187}

188

189template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo Info) {

191 return true;

192

194

197 return true;

198 }

199

200

201 if (this->PtrCB)

202 return (*this->PtrCB)(Ptr);

203

205 return false;

207 return false;

208

209

210 if (ConvertResultToRValue) {

212 return false;

213

215 return false;

216

218 return false;

219

220

221

224 return false;

225

226 if (std::optional V =

228 EvalResult.takeValue(std::move(*V));

229 } else {

230 return false;

231 }

232 } else {

233

234

235

237 EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));

238 return true;

239 }

240

242 return false;

243

244 EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));

245 }

246

247 return true;

248}

249

250bool EvalEmitter::emitRetVoid(SourceInfo Info) {

251 EvalResult.setValid();

252 return true;

253}

254

255bool EvalEmitter::emitRetValue(SourceInfo Info) {

256 const auto &Ptr = S.Stk.pop<Pointer>();

257

258 if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))

259 return false;

260 if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))

261 return false;

262

263 if (std::optional APV =

264 Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {

265 EvalResult.takeValue(std::move(*APV));

266 return true;

267 }

268

269 EvalResult.setInvalid();

270 return false;

271}

272

273bool EvalEmitter::emitGetPtrLocal(uint32_t I, SourceInfo Info) {

275 return true;

276

277 Block *B = getLocal(I);

278 S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));

279 return true;

280}

281

282template

283bool EvalEmitter::emitGetLocal(uint32_t I, SourceInfo Info) {

285 return true;

286

287 using T = typename PrimConv::T;

288

289 Block *B = getLocal(I);

290

292 return false;

293

294 S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));

295 return true;

296}

297

298template

299bool EvalEmitter::emitSetLocal(uint32_t I, SourceInfo Info) {

301 return true;

302

303 using T = typename PrimConv::T;

304

305 Block *B = getLocal(I);

306 *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();

307 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());

308 Desc.IsInitialized = true;

309

310 return true;

311}

312

313bool EvalEmitter::emitDestroy(uint32_t I, SourceInfo Info) {

315 return true;

316

319 S.deallocate(B);

320 }

321

322 return true;

323}

324

325bool EvalEmitter::emitGetLocalEnabled(uint32_t I, SourceInfo Info) {

327 return true;

328

329 Block *B = getLocal(I);

330 const InlineDescriptor &Desc =

331 *reinterpret_cast<InlineDescriptor *>(B->rawData());

332

333 S.Stk.push<bool>(Desc.IsActive);

334 return true;

335}

336

337bool EvalEmitter::emitEnableLocal(uint32_t I, SourceInfo Info) {

339 return true;

340

341

342

343

344

345

346 Block *B = getLocal(I);

347 InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());

349 return true;

350}

351

352

353

354

355

356

357void EvalEmitter::updateGlobalTemporaries() {

358 for (const auto &[E, Temp] : S.SeenGlobalTemporaries) {

359 UnsignedOrNone GlobalIndex = P.getGlobal(E);

360 assert(GlobalIndex);

361 const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);

362 APValue *Cached = Temp->getOrCreateValue(true);

363 if (OptPrimType T = Ctx.classify(E->getType())) {

365 { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); });

366 } else {

367 if (std::optional APV =

368 Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType()))

369 *Cached = *APV;

370 }

371 }

372 S.SeenGlobalTemporaries.clear();

373}

374

375

376

377

378

379#define GET_EVAL_IMPL

380#include "Opcodes.inc"

381#undef GET_EVAL_IMPL

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, const APValue &Value)

Check that this evaluated value is fully-initialized and can be loaded by an lvalue-to-rvalue convers...

#define TYPE_SWITCH(Expr, B)

CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).

Expr * getArg(unsigned Arg)

getArg - Return the specified argument.

SourceLocation getLocation() const

This represents one expression.

bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const

HasSideEffects - This routine returns true for all those expressions which have any effect other than...

SourceLocation getExprLoc() const LLVM_READONLY

getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...

Represents a function declaration or definition.

ArrayRef< ParmVarDecl * > parameters() const

Represents a parameter to a function.

A (possibly-)qualified type.

Represents a variable declaration or definition.

A memory block, either on the stack or in the heap.

void invokeDtor()

Invokes the Destructor.

std::byte * data()

Returns a pointer to the stored data.

bool isStatic() const

Checks if the block has static storage duration.

std::byte * rawData()

Returns a pointer to the raw data, including metadata.

bool isInitialized() const

Returns whether the data of this block has been initialized via invoking the Ctor func.

unsigned getEvalID() const

The Evaluation ID this block was created in.

Holds all information required to evaluate constexpr code in a module.

ASTContext & getASTContext() const

Returns the AST context.

unsigned getEvalID() const

bool jump(const LabelTy &Label)

Definition EvalEmitter.cpp:144

EvaluationResult interpretDecl(const VarDecl *VD, const Expr *Init, bool CheckFullyInitialized)

Definition EvalEmitter.cpp:52

EvaluationResult interpretExpr(const Expr *E, bool ConvertResultToRValue=false, bool DestroyToplevelScope=false)

Definition EvalEmitter.cpp:35

bool jumpFalse(const LabelTy &Label)

Definition EvalEmitter.cpp:136

virtual bool visit(const Expr *E)=0

bool speculate(const CallExpr *E, const LabelTy &EndLabel)

Speculative execution.

Definition EvalEmitter.cpp:157

Local createLocal(Descriptor *D)

Callback for registering a local.

Definition EvalEmitter.cpp:106

bool interpretCall(const FunctionDecl *FD, const Expr *E)

Interpret the given expression as if it was in the body of the given function, i.e.

Definition EvalEmitter.cpp:92

llvm::function_ref< bool(const Pointer &)> PtrCallback

void emitLabel(LabelTy Label)

Define a label.

Definition EvalEmitter.cpp:102

bool isActive() const

Since expressions can only jump forward, predicated execution is used to deal with if-else statements...

virtual bool visitExpr(const Expr *E, bool DestroyToplevelScope)=0

Methods implemented by the compiler.

bool fallthrough(const LabelTy &Label)

Definition EvalEmitter.cpp:150

virtual bool visitDeclAndReturn(const VarDecl *VD, const Expr *Init, bool ConstantContext)=0

void cleanup()

Clean up all resources.

Definition EvalEmitter.cpp:33

LabelTy getLabel()

Create a label.

Definition EvalEmitter.cpp:104

EvaluationResult interpretAsPointer(const Expr *E, PtrCallback PtrCB)

Interpret the given Expr to a Pointer.

Definition EvalEmitter.cpp:74

EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk)

Definition EvalEmitter.cpp:18

llvm::DenseMap< const ParmVarDecl *, ParamOffset > Params

Parameter indices.

virtual bool emitBool(bool V, const Expr *E)=0

virtual ~EvalEmitter()

Definition EvalEmitter.cpp:22

llvm::SmallVector< SmallVector< Local, 8 >, 2 > Descriptors

Local descriptors.

bool jumpTrue(const LabelTy &Label)

Emits jumps.

Definition EvalEmitter.cpp:128

Defines the result of an evaluation.

QualType getSourceType() const

bool checkReturnValue(InterpState &S, const Context &Ctx, const Pointer &Ptr, const SourceInfo &Info)

Check that none of the blocks the given pointer (transitively) points to are dynamically allocated.

bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const

Check that all subobjects of the given pointer have been initialized.

Stack frame storing temporaries and parameters.

T pop()

Returns the value from the top of the stack and removes it.

InterpStack & Stk

Temporary stack.

A pointer to a memory block, live or dead.

bool isConst() const

Checks if an object or a subfield is mutable.

T & deref() const

Dereferences the pointer, if it's live.

bool pointsToStringLiteral() const

bool isArrayRoot() const

Whether this array refers to an array, but not to the first element.

bool isLive() const

Checks if the pointer is live.

bool isZero() const

Checks if the pointer is null.

APValue toAPValue(const ASTContext &ASTCtx) const

Converts the pointer to an APValue.

bool isDereferencable() const

Whether this block can be read from at all.

bool isBlockPointer() const

std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const

Converts the pointer to an APValue that is an rvalue.

bool isTemporary() const

Checks if the storage is temporary.

const Block * block() const

bool isFunctionPointer() const

The program contains and links the bytecode for all functions.

Describes the statement/declaration an opcode was generated from.

Interface for the VM to interact with the AST walker's context.

bool CheckBCPResult(InterpState &S, const Pointer &Ptr)

bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr)

This is not used by any of the opcodes directly.

PrimType

Enumeration of the primitive types of the VM.

bool Init(InterpState &S, CodePtr OpPC)

bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B)

The JSON file list parser is used to communicate input to InstallAPI.

bool isa(CodeGen::Address addr)

const FunctionProtoType * T

Describes a memory block created by an allocation site.

unsigned getAllocSize() const

Returns the allocated size, including metadata.

Inline descriptor embedded in structures and arrays.

unsigned IsActive

Flag indicating if the field is the active member of a union.

unsigned IsBase

Flag indicating if the field is an embedded base class.

unsigned Offset

Offset inside the structure/array.

unsigned IsInitialized

For primitive fields, it indicates if the field was initialized.

unsigned IsConst

Flag indicating if the storage is constant or not.

unsigned IsFieldMutable

Flag indicating if the field is mutable (if in a record).

Mapping from primitive types to their representation.

Information about a local's storage.