1e5dd7070Spatrick //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Definition of the interpreter state and entry point.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick
13e5dd7070Spatrick #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14e5dd7070Spatrick #define LLVM_CLANG_AST_INTERP_INTERP_H
15e5dd7070Spatrick
16*12c85518Srobert #include "Boolean.h"
17e5dd7070Spatrick #include "Function.h"
18e5dd7070Spatrick #include "InterpFrame.h"
19e5dd7070Spatrick #include "InterpStack.h"
20e5dd7070Spatrick #include "InterpState.h"
21e5dd7070Spatrick #include "Opcode.h"
22e5dd7070Spatrick #include "PrimType.h"
23e5dd7070Spatrick #include "Program.h"
24e5dd7070Spatrick #include "State.h"
25e5dd7070Spatrick #include "clang/AST/ASTContext.h"
26e5dd7070Spatrick #include "clang/AST/ASTDiagnostic.h"
27e5dd7070Spatrick #include "clang/AST/CXXInheritance.h"
28e5dd7070Spatrick #include "clang/AST/Expr.h"
29e5dd7070Spatrick #include "llvm/ADT/APFloat.h"
30e5dd7070Spatrick #include "llvm/ADT/APSInt.h"
31e5dd7070Spatrick #include "llvm/Support/Endian.h"
32*12c85518Srobert #include <limits>
33*12c85518Srobert #include <type_traits>
34e5dd7070Spatrick
35e5dd7070Spatrick namespace clang {
36e5dd7070Spatrick namespace interp {
37e5dd7070Spatrick
38e5dd7070Spatrick using APInt = llvm::APInt;
39e5dd7070Spatrick using APSInt = llvm::APSInt;
40e5dd7070Spatrick
41*12c85518Srobert /// Convert a value to an APValue.
ReturnValue(const T & V,APValue & R)42e5dd7070Spatrick template <typename T> bool ReturnValue(const T &V, APValue &R) {
43e5dd7070Spatrick R = V.toAPValue();
44e5dd7070Spatrick return true;
45e5dd7070Spatrick }
46e5dd7070Spatrick
47e5dd7070Spatrick /// Checks if the variable has externally defined storage.
48e5dd7070Spatrick bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
49e5dd7070Spatrick
50e5dd7070Spatrick /// Checks if the array is offsetable.
51e5dd7070Spatrick bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
52e5dd7070Spatrick
53*12c85518Srobert /// Checks if a pointer is live and accessible.
54e5dd7070Spatrick bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
55e5dd7070Spatrick AccessKinds AK);
56e5dd7070Spatrick /// Checks if a pointer is null.
57e5dd7070Spatrick bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
58e5dd7070Spatrick CheckSubobjectKind CSK);
59e5dd7070Spatrick
60e5dd7070Spatrick /// Checks if a pointer is in range.
61e5dd7070Spatrick bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
62e5dd7070Spatrick AccessKinds AK);
63e5dd7070Spatrick
64e5dd7070Spatrick /// Checks if a field from which a pointer is going to be derived is valid.
65e5dd7070Spatrick bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
66e5dd7070Spatrick CheckSubobjectKind CSK);
67e5dd7070Spatrick
68e5dd7070Spatrick /// Checks if a pointer points to const storage.
69e5dd7070Spatrick bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
70e5dd7070Spatrick
71e5dd7070Spatrick /// Checks if a pointer points to a mutable field.
72e5dd7070Spatrick bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
73e5dd7070Spatrick
74e5dd7070Spatrick /// Checks if a value can be loaded from a block.
75e5dd7070Spatrick bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
76e5dd7070Spatrick
77e5dd7070Spatrick /// Checks if a value can be stored in a block.
78e5dd7070Spatrick bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79e5dd7070Spatrick
80e5dd7070Spatrick /// Checks if a method can be invoked on an object.
81e5dd7070Spatrick bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
82e5dd7070Spatrick
83e5dd7070Spatrick /// Checks if a value can be initialized.
84e5dd7070Spatrick bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85e5dd7070Spatrick
86e5dd7070Spatrick /// Checks if a method can be called.
87*12c85518Srobert bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
88e5dd7070Spatrick
89e5dd7070Spatrick /// Checks the 'this' pointer.
90e5dd7070Spatrick bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
91e5dd7070Spatrick
92e5dd7070Spatrick /// Checks if a method is pure virtual.
93e5dd7070Spatrick bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
94e5dd7070Spatrick
95*12c85518Srobert /// Checks that all fields are initialized after a constructor call.
96*12c85518Srobert bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
97*12c85518Srobert
98*12c85518Srobert /// Checks if the shift operation is legal.
99*12c85518Srobert template <typename RT>
CheckShift(InterpState & S,CodePtr OpPC,const RT & RHS,unsigned Bits)100*12c85518Srobert bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
101*12c85518Srobert if (RHS.isNegative()) {
102*12c85518Srobert const SourceInfo &Loc = S.Current->getSource(OpPC);
103*12c85518Srobert S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
104*12c85518Srobert return false;
105*12c85518Srobert }
106*12c85518Srobert
107*12c85518Srobert // C++11 [expr.shift]p1: Shift width must be less than the bit width of
108*12c85518Srobert // the shifted type.
109*12c85518Srobert if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
110*12c85518Srobert const Expr *E = S.Current->getExpr(OpPC);
111*12c85518Srobert const APSInt Val = RHS.toAPSInt();
112*12c85518Srobert QualType Ty = E->getType();
113*12c85518Srobert S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
114*12c85518Srobert return false;
115*12c85518Srobert }
116*12c85518Srobert return true;
117*12c85518Srobert }
118*12c85518Srobert
119*12c85518Srobert /// Checks if Div/Rem operation on LHS and RHS is valid.
120*12c85518Srobert template <typename T>
CheckDivRem(InterpState & S,CodePtr OpPC,const T & LHS,const T & RHS)121*12c85518Srobert bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
122*12c85518Srobert if (RHS.isZero()) {
123*12c85518Srobert const SourceInfo &Loc = S.Current->getSource(OpPC);
124*12c85518Srobert S.FFDiag(Loc, diag::note_expr_divide_by_zero);
125*12c85518Srobert return false;
126*12c85518Srobert }
127*12c85518Srobert
128*12c85518Srobert if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
129*12c85518Srobert APSInt LHSInt = LHS.toAPSInt();
130*12c85518Srobert SmallString<32> Trunc;
131*12c85518Srobert (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
132*12c85518Srobert const SourceInfo &Loc = S.Current->getSource(OpPC);
133*12c85518Srobert const Expr *E = S.Current->getExpr(OpPC);
134*12c85518Srobert S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
135*12c85518Srobert return false;
136*12c85518Srobert }
137*12c85518Srobert return true;
138*12c85518Srobert }
139*12c85518Srobert
140*12c85518Srobert /// Interpreter entry point.
141*12c85518Srobert bool Interpret(InterpState &S, APValue &Result);
142e5dd7070Spatrick
143e5dd7070Spatrick //===----------------------------------------------------------------------===//
144e5dd7070Spatrick // Add, Sub, Mul
145e5dd7070Spatrick //===----------------------------------------------------------------------===//
146e5dd7070Spatrick
147e5dd7070Spatrick template <typename T, bool (*OpFW)(T, T, unsigned, T *),
148e5dd7070Spatrick template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)149e5dd7070Spatrick bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
150e5dd7070Spatrick const T &RHS) {
151e5dd7070Spatrick // Fast path - add the numbers with fixed width.
152e5dd7070Spatrick T Result;
153e5dd7070Spatrick if (!OpFW(LHS, RHS, Bits, &Result)) {
154e5dd7070Spatrick S.Stk.push<T>(Result);
155e5dd7070Spatrick return true;
156e5dd7070Spatrick }
157e5dd7070Spatrick
158e5dd7070Spatrick // If for some reason evaluation continues, use the truncated results.
159e5dd7070Spatrick S.Stk.push<T>(Result);
160e5dd7070Spatrick
161e5dd7070Spatrick // Slow path - compute the result using another bit of precision.
162e5dd7070Spatrick APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
163e5dd7070Spatrick
164e5dd7070Spatrick // Report undefined behaviour, stopping if required.
165e5dd7070Spatrick const Expr *E = S.Current->getExpr(OpPC);
166e5dd7070Spatrick QualType Type = E->getType();
167e5dd7070Spatrick if (S.checkingForUndefinedBehavior()) {
168a9ac8606Spatrick SmallString<32> Trunc;
169a9ac8606Spatrick Value.trunc(Result.bitWidth()).toString(Trunc, 10);
170e5dd7070Spatrick auto Loc = E->getExprLoc();
171e5dd7070Spatrick S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
172e5dd7070Spatrick return true;
173e5dd7070Spatrick } else {
174e5dd7070Spatrick S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
175e5dd7070Spatrick return S.noteUndefinedBehavior();
176e5dd7070Spatrick }
177e5dd7070Spatrick }
178e5dd7070Spatrick
179e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)180e5dd7070Spatrick bool Add(InterpState &S, CodePtr OpPC) {
181e5dd7070Spatrick const T &RHS = S.Stk.pop<T>();
182e5dd7070Spatrick const T &LHS = S.Stk.pop<T>();
183e5dd7070Spatrick const unsigned Bits = RHS.bitWidth() + 1;
184e5dd7070Spatrick return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
185e5dd7070Spatrick }
186e5dd7070Spatrick
187e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)188e5dd7070Spatrick bool Sub(InterpState &S, CodePtr OpPC) {
189e5dd7070Spatrick const T &RHS = S.Stk.pop<T>();
190e5dd7070Spatrick const T &LHS = S.Stk.pop<T>();
191e5dd7070Spatrick const unsigned Bits = RHS.bitWidth() + 1;
192e5dd7070Spatrick return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
193e5dd7070Spatrick }
194e5dd7070Spatrick
195e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)196e5dd7070Spatrick bool Mul(InterpState &S, CodePtr OpPC) {
197e5dd7070Spatrick const T &RHS = S.Stk.pop<T>();
198e5dd7070Spatrick const T &LHS = S.Stk.pop<T>();
199e5dd7070Spatrick const unsigned Bits = RHS.bitWidth() * 2;
200e5dd7070Spatrick return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
201e5dd7070Spatrick }
202e5dd7070Spatrick
203*12c85518Srobert /// 1) Pops the RHS from the stack.
204*12c85518Srobert /// 2) Pops the LHS from the stack.
205*12c85518Srobert /// 3) Pushes 'LHS & RHS' on the stack
206*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
BitAnd(InterpState & S,CodePtr OpPC)207*12c85518Srobert bool BitAnd(InterpState &S, CodePtr OpPC) {
208*12c85518Srobert const T &RHS = S.Stk.pop<T>();
209*12c85518Srobert const T &LHS = S.Stk.pop<T>();
210*12c85518Srobert
211*12c85518Srobert unsigned Bits = RHS.bitWidth();
212*12c85518Srobert T Result;
213*12c85518Srobert if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
214*12c85518Srobert S.Stk.push<T>(Result);
215*12c85518Srobert return true;
216*12c85518Srobert }
217*12c85518Srobert return false;
218*12c85518Srobert }
219*12c85518Srobert
220*12c85518Srobert /// 1) Pops the RHS from the stack.
221*12c85518Srobert /// 2) Pops the LHS from the stack.
222*12c85518Srobert /// 3) Pushes 'LHS | RHS' on the stack
223*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
BitOr(InterpState & S,CodePtr OpPC)224*12c85518Srobert bool BitOr(InterpState &S, CodePtr OpPC) {
225*12c85518Srobert const T &RHS = S.Stk.pop<T>();
226*12c85518Srobert const T &LHS = S.Stk.pop<T>();
227*12c85518Srobert
228*12c85518Srobert unsigned Bits = RHS.bitWidth();
229*12c85518Srobert T Result;
230*12c85518Srobert if (!T::bitOr(LHS, RHS, Bits, &Result)) {
231*12c85518Srobert S.Stk.push<T>(Result);
232*12c85518Srobert return true;
233*12c85518Srobert }
234*12c85518Srobert return false;
235*12c85518Srobert }
236*12c85518Srobert
237*12c85518Srobert /// 1) Pops the RHS from the stack.
238*12c85518Srobert /// 2) Pops the LHS from the stack.
239*12c85518Srobert /// 3) Pushes 'LHS ^ RHS' on the stack
240*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
BitXor(InterpState & S,CodePtr OpPC)241*12c85518Srobert bool BitXor(InterpState &S, CodePtr OpPC) {
242*12c85518Srobert const T &RHS = S.Stk.pop<T>();
243*12c85518Srobert const T &LHS = S.Stk.pop<T>();
244*12c85518Srobert
245*12c85518Srobert unsigned Bits = RHS.bitWidth();
246*12c85518Srobert T Result;
247*12c85518Srobert if (!T::bitXor(LHS, RHS, Bits, &Result)) {
248*12c85518Srobert S.Stk.push<T>(Result);
249*12c85518Srobert return true;
250*12c85518Srobert }
251*12c85518Srobert return false;
252*12c85518Srobert }
253*12c85518Srobert
254*12c85518Srobert /// 1) Pops the RHS from the stack.
255*12c85518Srobert /// 2) Pops the LHS from the stack.
256*12c85518Srobert /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
257*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Rem(InterpState & S,CodePtr OpPC)258*12c85518Srobert bool Rem(InterpState &S, CodePtr OpPC) {
259*12c85518Srobert const T &RHS = S.Stk.pop<T>();
260*12c85518Srobert const T &LHS = S.Stk.pop<T>();
261*12c85518Srobert
262*12c85518Srobert if (!CheckDivRem(S, OpPC, LHS, RHS))
263*12c85518Srobert return false;
264*12c85518Srobert
265*12c85518Srobert const unsigned Bits = RHS.bitWidth() * 2;
266*12c85518Srobert T Result;
267*12c85518Srobert if (!T::rem(LHS, RHS, Bits, &Result)) {
268*12c85518Srobert S.Stk.push<T>(Result);
269*12c85518Srobert return true;
270*12c85518Srobert }
271*12c85518Srobert return false;
272*12c85518Srobert }
273*12c85518Srobert
274*12c85518Srobert /// 1) Pops the RHS from the stack.
275*12c85518Srobert /// 2) Pops the LHS from the stack.
276*12c85518Srobert /// 3) Pushes 'LHS / RHS' on the stack
277*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Div(InterpState & S,CodePtr OpPC)278*12c85518Srobert bool Div(InterpState &S, CodePtr OpPC) {
279*12c85518Srobert const T &RHS = S.Stk.pop<T>();
280*12c85518Srobert const T &LHS = S.Stk.pop<T>();
281*12c85518Srobert
282*12c85518Srobert if (!CheckDivRem(S, OpPC, LHS, RHS))
283*12c85518Srobert return false;
284*12c85518Srobert
285*12c85518Srobert const unsigned Bits = RHS.bitWidth() * 2;
286*12c85518Srobert T Result;
287*12c85518Srobert if (!T::div(LHS, RHS, Bits, &Result)) {
288*12c85518Srobert S.Stk.push<T>(Result);
289*12c85518Srobert return true;
290*12c85518Srobert }
291*12c85518Srobert return false;
292*12c85518Srobert }
293*12c85518Srobert
294*12c85518Srobert //===----------------------------------------------------------------------===//
295*12c85518Srobert // Inv
296*12c85518Srobert //===----------------------------------------------------------------------===//
297*12c85518Srobert
298*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Inv(InterpState & S,CodePtr OpPC)299*12c85518Srobert bool Inv(InterpState &S, CodePtr OpPC) {
300*12c85518Srobert using BoolT = PrimConv<PT_Bool>::T;
301*12c85518Srobert const T &Val = S.Stk.pop<T>();
302*12c85518Srobert const unsigned Bits = Val.bitWidth();
303*12c85518Srobert Boolean R;
304*12c85518Srobert Boolean::inv(BoolT::from(Val, Bits), &R);
305*12c85518Srobert
306*12c85518Srobert S.Stk.push<BoolT>(R);
307*12c85518Srobert return true;
308*12c85518Srobert }
309*12c85518Srobert
310*12c85518Srobert //===----------------------------------------------------------------------===//
311*12c85518Srobert // Neg
312*12c85518Srobert //===----------------------------------------------------------------------===//
313*12c85518Srobert
314*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Neg(InterpState & S,CodePtr OpPC)315*12c85518Srobert bool Neg(InterpState &S, CodePtr OpPC) {
316*12c85518Srobert const T &Val = S.Stk.pop<T>();
317*12c85518Srobert T Result;
318*12c85518Srobert T::neg(Val, &Result);
319*12c85518Srobert
320*12c85518Srobert S.Stk.push<T>(Result);
321*12c85518Srobert return true;
322*12c85518Srobert }
323*12c85518Srobert
324*12c85518Srobert enum class PushVal : bool {
325*12c85518Srobert No,
326*12c85518Srobert Yes,
327*12c85518Srobert };
328*12c85518Srobert enum class IncDecOp {
329*12c85518Srobert Inc,
330*12c85518Srobert Dec,
331*12c85518Srobert };
332*12c85518Srobert
333*12c85518Srobert template <typename T, IncDecOp Op, PushVal DoPush>
IncDecHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)334*12c85518Srobert bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
335*12c85518Srobert T Value = Ptr.deref<T>();
336*12c85518Srobert T Result;
337*12c85518Srobert
338*12c85518Srobert if constexpr (DoPush == PushVal::Yes)
339*12c85518Srobert S.Stk.push<T>(Result);
340*12c85518Srobert
341*12c85518Srobert if constexpr (Op == IncDecOp::Inc) {
342*12c85518Srobert if (!T::increment(Value, &Result)) {
343*12c85518Srobert Ptr.deref<T>() = Result;
344*12c85518Srobert return true;
345*12c85518Srobert }
346*12c85518Srobert } else {
347*12c85518Srobert if (!T::decrement(Value, &Result)) {
348*12c85518Srobert Ptr.deref<T>() = Result;
349*12c85518Srobert return true;
350*12c85518Srobert }
351*12c85518Srobert }
352*12c85518Srobert
353*12c85518Srobert // Something went wrong with the previous operation. Compute the
354*12c85518Srobert // result with another bit of precision.
355*12c85518Srobert unsigned Bits = Value.bitWidth() + 1;
356*12c85518Srobert APSInt APResult;
357*12c85518Srobert if constexpr (Op == IncDecOp::Inc)
358*12c85518Srobert APResult = ++Value.toAPSInt(Bits);
359*12c85518Srobert else
360*12c85518Srobert APResult = --Value.toAPSInt(Bits);
361*12c85518Srobert
362*12c85518Srobert // Report undefined behaviour, stopping if required.
363*12c85518Srobert const Expr *E = S.Current->getExpr(OpPC);
364*12c85518Srobert QualType Type = E->getType();
365*12c85518Srobert if (S.checkingForUndefinedBehavior()) {
366*12c85518Srobert SmallString<32> Trunc;
367*12c85518Srobert APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
368*12c85518Srobert auto Loc = E->getExprLoc();
369*12c85518Srobert S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
370*12c85518Srobert return true;
371*12c85518Srobert }
372*12c85518Srobert
373*12c85518Srobert S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
374*12c85518Srobert return S.noteUndefinedBehavior();
375*12c85518Srobert }
376*12c85518Srobert
377*12c85518Srobert /// 1) Pops a pointer from the stack
378*12c85518Srobert /// 2) Load the value from the pointer
379*12c85518Srobert /// 3) Writes the value increased by one back to the pointer
380*12c85518Srobert /// 4) Pushes the original (pre-inc) value on the stack.
381*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Inc(InterpState & S,CodePtr OpPC)382*12c85518Srobert bool Inc(InterpState &S, CodePtr OpPC) {
383*12c85518Srobert // FIXME: Check initialization of Ptr
384*12c85518Srobert const Pointer &Ptr = S.Stk.pop<Pointer>();
385*12c85518Srobert
386*12c85518Srobert return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
387*12c85518Srobert }
388*12c85518Srobert
389*12c85518Srobert /// 1) Pops a pointer from the stack
390*12c85518Srobert /// 2) Load the value from the pointer
391*12c85518Srobert /// 3) Writes the value increased by one back to the pointer
392*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
IncPop(InterpState & S,CodePtr OpPC)393*12c85518Srobert bool IncPop(InterpState &S, CodePtr OpPC) {
394*12c85518Srobert // FIXME: Check initialization of Ptr
395*12c85518Srobert const Pointer &Ptr = S.Stk.pop<Pointer>();
396*12c85518Srobert
397*12c85518Srobert return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
398*12c85518Srobert }
399*12c85518Srobert
400*12c85518Srobert /// 1) Pops a pointer from the stack
401*12c85518Srobert /// 2) Load the value from the pointer
402*12c85518Srobert /// 3) Writes the value decreased by one back to the pointer
403*12c85518Srobert /// 4) Pushes the original (pre-dec) value on the stack.
404*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Dec(InterpState & S,CodePtr OpPC)405*12c85518Srobert bool Dec(InterpState &S, CodePtr OpPC) {
406*12c85518Srobert // FIXME: Check initialization of Ptr
407*12c85518Srobert const Pointer &Ptr = S.Stk.pop<Pointer>();
408*12c85518Srobert
409*12c85518Srobert return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
410*12c85518Srobert }
411*12c85518Srobert
412*12c85518Srobert /// 1) Pops a pointer from the stack
413*12c85518Srobert /// 2) Load the value from the pointer
414*12c85518Srobert /// 3) Writes the value decreased by one back to the pointer
415*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
DecPop(InterpState & S,CodePtr OpPC)416*12c85518Srobert bool DecPop(InterpState &S, CodePtr OpPC) {
417*12c85518Srobert // FIXME: Check initialization of Ptr
418*12c85518Srobert const Pointer &Ptr = S.Stk.pop<Pointer>();
419*12c85518Srobert
420*12c85518Srobert return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
421*12c85518Srobert }
422*12c85518Srobert
423*12c85518Srobert /// 1) Pops the value from the stack.
424*12c85518Srobert /// 2) Pushes the bitwise complemented value on the stack (~V).
425*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Comp(InterpState & S,CodePtr OpPC)426*12c85518Srobert bool Comp(InterpState &S, CodePtr OpPC) {
427*12c85518Srobert const T &Val = S.Stk.pop<T>();
428*12c85518Srobert T Result;
429*12c85518Srobert if (!T::comp(Val, &Result)) {
430*12c85518Srobert S.Stk.push<T>(Result);
431*12c85518Srobert return true;
432*12c85518Srobert }
433*12c85518Srobert
434*12c85518Srobert return false;
435*12c85518Srobert }
436*12c85518Srobert
437e5dd7070Spatrick //===----------------------------------------------------------------------===//
438e5dd7070Spatrick // EQ, NE, GT, GE, LT, LE
439e5dd7070Spatrick //===----------------------------------------------------------------------===//
440e5dd7070Spatrick
441e5dd7070Spatrick using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
442e5dd7070Spatrick
443e5dd7070Spatrick template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)444e5dd7070Spatrick bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
445e5dd7070Spatrick using BoolT = PrimConv<PT_Bool>::T;
446e5dd7070Spatrick const T &RHS = S.Stk.pop<T>();
447e5dd7070Spatrick const T &LHS = S.Stk.pop<T>();
448e5dd7070Spatrick S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
449e5dd7070Spatrick return true;
450e5dd7070Spatrick }
451e5dd7070Spatrick
452e5dd7070Spatrick template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)453e5dd7070Spatrick bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
454e5dd7070Spatrick return CmpHelper<T>(S, OpPC, Fn);
455e5dd7070Spatrick }
456e5dd7070Spatrick
457e5dd7070Spatrick template <>
458e5dd7070Spatrick inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
459e5dd7070Spatrick using BoolT = PrimConv<PT_Bool>::T;
460e5dd7070Spatrick const Pointer &RHS = S.Stk.pop<Pointer>();
461e5dd7070Spatrick const Pointer &LHS = S.Stk.pop<Pointer>();
462e5dd7070Spatrick
463e5dd7070Spatrick if (!Pointer::hasSameBase(LHS, RHS)) {
464e5dd7070Spatrick const SourceInfo &Loc = S.Current->getSource(OpPC);
465e5dd7070Spatrick S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
466e5dd7070Spatrick return false;
467e5dd7070Spatrick } else {
468e5dd7070Spatrick unsigned VL = LHS.getByteOffset();
469e5dd7070Spatrick unsigned VR = RHS.getByteOffset();
470e5dd7070Spatrick S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
471e5dd7070Spatrick return true;
472e5dd7070Spatrick }
473e5dd7070Spatrick }
474e5dd7070Spatrick
475e5dd7070Spatrick template <>
476e5dd7070Spatrick inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
477e5dd7070Spatrick using BoolT = PrimConv<PT_Bool>::T;
478e5dd7070Spatrick const Pointer &RHS = S.Stk.pop<Pointer>();
479e5dd7070Spatrick const Pointer &LHS = S.Stk.pop<Pointer>();
480e5dd7070Spatrick
481e5dd7070Spatrick if (LHS.isZero() && RHS.isZero()) {
482e5dd7070Spatrick S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
483e5dd7070Spatrick return true;
484e5dd7070Spatrick }
485e5dd7070Spatrick
486e5dd7070Spatrick if (!Pointer::hasSameBase(LHS, RHS)) {
487e5dd7070Spatrick S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
488e5dd7070Spatrick return true;
489e5dd7070Spatrick } else {
490e5dd7070Spatrick unsigned VL = LHS.getByteOffset();
491e5dd7070Spatrick unsigned VR = RHS.getByteOffset();
492*12c85518Srobert
493*12c85518Srobert // In our Pointer class, a pointer to an array and a pointer to the first
494*12c85518Srobert // element in the same array are NOT equal. They have the same Base value,
495*12c85518Srobert // but a different Offset. This is a pretty rare case, so we fix this here
496*12c85518Srobert // by comparing pointers to the first elements.
497*12c85518Srobert if (LHS.inArray() && LHS.isRoot())
498*12c85518Srobert VL = LHS.atIndex(0).getByteOffset();
499*12c85518Srobert if (RHS.inArray() && RHS.isRoot())
500*12c85518Srobert VR = RHS.atIndex(0).getByteOffset();
501*12c85518Srobert
502e5dd7070Spatrick S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
503e5dd7070Spatrick return true;
504e5dd7070Spatrick }
505e5dd7070Spatrick }
506e5dd7070Spatrick
507e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)508e5dd7070Spatrick bool EQ(InterpState &S, CodePtr OpPC) {
509e5dd7070Spatrick return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
510e5dd7070Spatrick return R == ComparisonCategoryResult::Equal;
511e5dd7070Spatrick });
512e5dd7070Spatrick }
513e5dd7070Spatrick
514e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)515e5dd7070Spatrick bool NE(InterpState &S, CodePtr OpPC) {
516e5dd7070Spatrick return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
517e5dd7070Spatrick return R != ComparisonCategoryResult::Equal;
518e5dd7070Spatrick });
519e5dd7070Spatrick }
520e5dd7070Spatrick
521e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)522e5dd7070Spatrick bool LT(InterpState &S, CodePtr OpPC) {
523e5dd7070Spatrick return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
524e5dd7070Spatrick return R == ComparisonCategoryResult::Less;
525e5dd7070Spatrick });
526e5dd7070Spatrick }
527e5dd7070Spatrick
528e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)529e5dd7070Spatrick bool LE(InterpState &S, CodePtr OpPC) {
530e5dd7070Spatrick return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
531e5dd7070Spatrick return R == ComparisonCategoryResult::Less ||
532e5dd7070Spatrick R == ComparisonCategoryResult::Equal;
533e5dd7070Spatrick });
534e5dd7070Spatrick }
535e5dd7070Spatrick
536e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)537e5dd7070Spatrick bool GT(InterpState &S, CodePtr OpPC) {
538e5dd7070Spatrick return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
539e5dd7070Spatrick return R == ComparisonCategoryResult::Greater;
540e5dd7070Spatrick });
541e5dd7070Spatrick }
542e5dd7070Spatrick
543e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)544e5dd7070Spatrick bool GE(InterpState &S, CodePtr OpPC) {
545e5dd7070Spatrick return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
546e5dd7070Spatrick return R == ComparisonCategoryResult::Greater ||
547e5dd7070Spatrick R == ComparisonCategoryResult::Equal;
548e5dd7070Spatrick });
549e5dd7070Spatrick }
550e5dd7070Spatrick
551e5dd7070Spatrick //===----------------------------------------------------------------------===//
552e5dd7070Spatrick // InRange
553e5dd7070Spatrick //===----------------------------------------------------------------------===//
554e5dd7070Spatrick
555e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InRange(InterpState & S,CodePtr OpPC)556e5dd7070Spatrick bool InRange(InterpState &S, CodePtr OpPC) {
557e5dd7070Spatrick const T RHS = S.Stk.pop<T>();
558e5dd7070Spatrick const T LHS = S.Stk.pop<T>();
559e5dd7070Spatrick const T Value = S.Stk.pop<T>();
560e5dd7070Spatrick
561e5dd7070Spatrick S.Stk.push<bool>(LHS <= Value && Value <= RHS);
562e5dd7070Spatrick return true;
563e5dd7070Spatrick }
564e5dd7070Spatrick
565e5dd7070Spatrick //===----------------------------------------------------------------------===//
566e5dd7070Spatrick // Dup, Pop, Test
567e5dd7070Spatrick //===----------------------------------------------------------------------===//
568e5dd7070Spatrick
569e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)570e5dd7070Spatrick bool Dup(InterpState &S, CodePtr OpPC) {
571e5dd7070Spatrick S.Stk.push<T>(S.Stk.peek<T>());
572e5dd7070Spatrick return true;
573e5dd7070Spatrick }
574e5dd7070Spatrick
575e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)576e5dd7070Spatrick bool Pop(InterpState &S, CodePtr OpPC) {
577e5dd7070Spatrick S.Stk.pop<T>();
578e5dd7070Spatrick return true;
579e5dd7070Spatrick }
580e5dd7070Spatrick
581e5dd7070Spatrick //===----------------------------------------------------------------------===//
582e5dd7070Spatrick // Const
583e5dd7070Spatrick //===----------------------------------------------------------------------===//
584e5dd7070Spatrick
585e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)586e5dd7070Spatrick bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
587e5dd7070Spatrick S.Stk.push<T>(Arg);
588e5dd7070Spatrick return true;
589e5dd7070Spatrick }
590e5dd7070Spatrick
591e5dd7070Spatrick //===----------------------------------------------------------------------===//
592e5dd7070Spatrick // Get/Set Local/Param/Global/This
593e5dd7070Spatrick //===----------------------------------------------------------------------===//
594e5dd7070Spatrick
595e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)596e5dd7070Spatrick bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
597*12c85518Srobert const Pointer &Ptr = S.Current->getLocalPointer(I);
598*12c85518Srobert if (!CheckLoad(S, OpPC, Ptr))
599*12c85518Srobert return false;
600*12c85518Srobert S.Stk.push<T>(Ptr.deref<T>());
601e5dd7070Spatrick return true;
602e5dd7070Spatrick }
603e5dd7070Spatrick
604e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)605e5dd7070Spatrick bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
606e5dd7070Spatrick S.Current->setLocal<T>(I, S.Stk.pop<T>());
607e5dd7070Spatrick return true;
608e5dd7070Spatrick }
609e5dd7070Spatrick
610e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)611e5dd7070Spatrick bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
612e5dd7070Spatrick if (S.checkingPotentialConstantExpression()) {
613e5dd7070Spatrick return false;
614e5dd7070Spatrick }
615e5dd7070Spatrick S.Stk.push<T>(S.Current->getParam<T>(I));
616e5dd7070Spatrick return true;
617e5dd7070Spatrick }
618e5dd7070Spatrick
619e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)620e5dd7070Spatrick bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
621e5dd7070Spatrick S.Current->setParam<T>(I, S.Stk.pop<T>());
622e5dd7070Spatrick return true;
623e5dd7070Spatrick }
624e5dd7070Spatrick
625*12c85518Srobert /// 1) Peeks a pointer on the stack
626*12c85518Srobert /// 2) Pushes the value of the pointer's field on the stack
627e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)628e5dd7070Spatrick bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
629e5dd7070Spatrick const Pointer &Obj = S.Stk.peek<Pointer>();
630e5dd7070Spatrick if (!CheckNull(S, OpPC, Obj, CSK_Field))
631e5dd7070Spatrick return false;
632e5dd7070Spatrick if (!CheckRange(S, OpPC, Obj, CSK_Field))
633e5dd7070Spatrick return false;
634e5dd7070Spatrick const Pointer &Field = Obj.atField(I);
635e5dd7070Spatrick if (!CheckLoad(S, OpPC, Field))
636e5dd7070Spatrick return false;
637e5dd7070Spatrick S.Stk.push<T>(Field.deref<T>());
638e5dd7070Spatrick return true;
639e5dd7070Spatrick }
640e5dd7070Spatrick
641e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)642e5dd7070Spatrick bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
643e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
644e5dd7070Spatrick const Pointer &Obj = S.Stk.peek<Pointer>();
645e5dd7070Spatrick if (!CheckNull(S, OpPC, Obj, CSK_Field))
646e5dd7070Spatrick return false;
647e5dd7070Spatrick if (!CheckRange(S, OpPC, Obj, CSK_Field))
648e5dd7070Spatrick return false;
649e5dd7070Spatrick const Pointer &Field = Obj.atField(I);
650e5dd7070Spatrick if (!CheckStore(S, OpPC, Field))
651e5dd7070Spatrick return false;
652e5dd7070Spatrick Field.deref<T>() = Value;
653e5dd7070Spatrick return true;
654e5dd7070Spatrick }
655e5dd7070Spatrick
656*12c85518Srobert /// 1) Pops a pointer from the stack
657*12c85518Srobert /// 2) Pushes the value of the pointer's field on the stack
658e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)659e5dd7070Spatrick bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
660e5dd7070Spatrick const Pointer &Obj = S.Stk.pop<Pointer>();
661e5dd7070Spatrick if (!CheckNull(S, OpPC, Obj, CSK_Field))
662e5dd7070Spatrick return false;
663e5dd7070Spatrick if (!CheckRange(S, OpPC, Obj, CSK_Field))
664e5dd7070Spatrick return false;
665e5dd7070Spatrick const Pointer &Field = Obj.atField(I);
666e5dd7070Spatrick if (!CheckLoad(S, OpPC, Field))
667e5dd7070Spatrick return false;
668e5dd7070Spatrick S.Stk.push<T>(Field.deref<T>());
669e5dd7070Spatrick return true;
670e5dd7070Spatrick }
671e5dd7070Spatrick
672e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)673e5dd7070Spatrick bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
674e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
675e5dd7070Spatrick return false;
676e5dd7070Spatrick const Pointer &This = S.Current->getThis();
677e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
678e5dd7070Spatrick return false;
679e5dd7070Spatrick const Pointer &Field = This.atField(I);
680e5dd7070Spatrick if (!CheckLoad(S, OpPC, Field))
681e5dd7070Spatrick return false;
682e5dd7070Spatrick S.Stk.push<T>(Field.deref<T>());
683e5dd7070Spatrick return true;
684e5dd7070Spatrick }
685e5dd7070Spatrick
686e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)687e5dd7070Spatrick bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
688e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
689e5dd7070Spatrick return false;
690e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
691e5dd7070Spatrick const Pointer &This = S.Current->getThis();
692e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
693e5dd7070Spatrick return false;
694e5dd7070Spatrick const Pointer &Field = This.atField(I);
695e5dd7070Spatrick if (!CheckStore(S, OpPC, Field))
696e5dd7070Spatrick return false;
697e5dd7070Spatrick Field.deref<T>() = Value;
698e5dd7070Spatrick return true;
699e5dd7070Spatrick }
700e5dd7070Spatrick
701e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)702e5dd7070Spatrick bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
703e5dd7070Spatrick auto *B = S.P.getGlobal(I);
704e5dd7070Spatrick if (B->isExtern())
705e5dd7070Spatrick return false;
706e5dd7070Spatrick S.Stk.push<T>(B->deref<T>());
707e5dd7070Spatrick return true;
708e5dd7070Spatrick }
709e5dd7070Spatrick
710e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)711e5dd7070Spatrick bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
712e5dd7070Spatrick // TODO: emit warning.
713e5dd7070Spatrick return false;
714e5dd7070Spatrick }
715e5dd7070Spatrick
716e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)717e5dd7070Spatrick bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
718e5dd7070Spatrick S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
719e5dd7070Spatrick return true;
720e5dd7070Spatrick }
721e5dd7070Spatrick
722e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)723e5dd7070Spatrick bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
724e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
725e5dd7070Spatrick return false;
726e5dd7070Spatrick const Pointer &This = S.Current->getThis();
727e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
728e5dd7070Spatrick return false;
729e5dd7070Spatrick const Pointer &Field = This.atField(I);
730e5dd7070Spatrick Field.deref<T>() = S.Stk.pop<T>();
731e5dd7070Spatrick Field.initialize();
732e5dd7070Spatrick return true;
733e5dd7070Spatrick }
734e5dd7070Spatrick
735e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)736e5dd7070Spatrick bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
737e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
738e5dd7070Spatrick return false;
739e5dd7070Spatrick const Pointer &This = S.Current->getThis();
740e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
741e5dd7070Spatrick return false;
742e5dd7070Spatrick const Pointer &Field = This.atField(F->Offset);
743e5dd7070Spatrick const auto &Value = S.Stk.pop<T>();
744e5dd7070Spatrick Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
745e5dd7070Spatrick Field.initialize();
746e5dd7070Spatrick return true;
747e5dd7070Spatrick }
748e5dd7070Spatrick
749e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)750e5dd7070Spatrick bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
751e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
752e5dd7070Spatrick return false;
753e5dd7070Spatrick const Pointer &This = S.Current->getThis();
754e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
755e5dd7070Spatrick return false;
756e5dd7070Spatrick const Pointer &Field = This.atField(I);
757e5dd7070Spatrick Field.deref<T>() = S.Stk.pop<T>();
758e5dd7070Spatrick Field.activate();
759e5dd7070Spatrick Field.initialize();
760e5dd7070Spatrick return true;
761e5dd7070Spatrick }
762e5dd7070Spatrick
763*12c85518Srobert /// 1) Pops the value from the stack
764*12c85518Srobert /// 2) Peeks a pointer from the stack
765*12c85518Srobert /// 3) Pushes the value to field I of the pointer on the stack
766e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)767e5dd7070Spatrick bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
768e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
769*12c85518Srobert const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
770e5dd7070Spatrick Field.deref<T>() = Value;
771e5dd7070Spatrick Field.activate();
772e5dd7070Spatrick Field.initialize();
773e5dd7070Spatrick return true;
774e5dd7070Spatrick }
775e5dd7070Spatrick
776e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)777e5dd7070Spatrick bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
778e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
779e5dd7070Spatrick const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
780e5dd7070Spatrick Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
781e5dd7070Spatrick Field.activate();
782e5dd7070Spatrick Field.initialize();
783e5dd7070Spatrick return true;
784e5dd7070Spatrick }
785e5dd7070Spatrick
786e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)787e5dd7070Spatrick bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
788e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
789e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
790e5dd7070Spatrick const Pointer &Field = Ptr.atField(I);
791e5dd7070Spatrick Field.deref<T>() = Value;
792e5dd7070Spatrick Field.activate();
793e5dd7070Spatrick Field.initialize();
794e5dd7070Spatrick return true;
795e5dd7070Spatrick }
796e5dd7070Spatrick
797e5dd7070Spatrick //===----------------------------------------------------------------------===//
798e5dd7070Spatrick // GetPtr Local/Param/Global/Field/This
799e5dd7070Spatrick //===----------------------------------------------------------------------===//
800e5dd7070Spatrick
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)801e5dd7070Spatrick inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
802e5dd7070Spatrick S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
803e5dd7070Spatrick return true;
804e5dd7070Spatrick }
805e5dd7070Spatrick
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)806e5dd7070Spatrick inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
807e5dd7070Spatrick if (S.checkingPotentialConstantExpression()) {
808e5dd7070Spatrick return false;
809e5dd7070Spatrick }
810e5dd7070Spatrick S.Stk.push<Pointer>(S.Current->getParamPointer(I));
811e5dd7070Spatrick return true;
812e5dd7070Spatrick }
813e5dd7070Spatrick
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)814e5dd7070Spatrick inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
815e5dd7070Spatrick S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
816e5dd7070Spatrick return true;
817e5dd7070Spatrick }
818e5dd7070Spatrick
819*12c85518Srobert /// 1) Pops a Pointer from the stack
820*12c85518Srobert /// 2) Pushes Pointer.atField(Off) on the stack
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)821e5dd7070Spatrick inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
822e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
823e5dd7070Spatrick if (!CheckNull(S, OpPC, Ptr, CSK_Field))
824e5dd7070Spatrick return false;
825e5dd7070Spatrick if (!CheckExtern(S, OpPC, Ptr))
826e5dd7070Spatrick return false;
827e5dd7070Spatrick if (!CheckRange(S, OpPC, Ptr, CSK_Field))
828e5dd7070Spatrick return false;
829e5dd7070Spatrick S.Stk.push<Pointer>(Ptr.atField(Off));
830e5dd7070Spatrick return true;
831e5dd7070Spatrick }
832e5dd7070Spatrick
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)833e5dd7070Spatrick inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
834e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
835e5dd7070Spatrick return false;
836e5dd7070Spatrick const Pointer &This = S.Current->getThis();
837e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
838e5dd7070Spatrick return false;
839e5dd7070Spatrick S.Stk.push<Pointer>(This.atField(Off));
840e5dd7070Spatrick return true;
841e5dd7070Spatrick }
842e5dd7070Spatrick
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)843e5dd7070Spatrick inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
844e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
845e5dd7070Spatrick if (!CheckNull(S, OpPC, Ptr, CSK_Field))
846e5dd7070Spatrick return false;
847e5dd7070Spatrick if (!CheckRange(S, OpPC, Ptr, CSK_Field))
848e5dd7070Spatrick return false;
849e5dd7070Spatrick Pointer Field = Ptr.atField(Off);
850e5dd7070Spatrick Ptr.deactivate();
851e5dd7070Spatrick Field.activate();
852e5dd7070Spatrick S.Stk.push<Pointer>(std::move(Field));
853e5dd7070Spatrick return true;
854e5dd7070Spatrick }
855e5dd7070Spatrick
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)856e5dd7070Spatrick inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
857e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
858e5dd7070Spatrick return false;
859e5dd7070Spatrick const Pointer &This = S.Current->getThis();
860e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
861e5dd7070Spatrick return false;
862e5dd7070Spatrick Pointer Field = This.atField(Off);
863e5dd7070Spatrick This.deactivate();
864e5dd7070Spatrick Field.activate();
865e5dd7070Spatrick S.Stk.push<Pointer>(std::move(Field));
866e5dd7070Spatrick return true;
867e5dd7070Spatrick }
868e5dd7070Spatrick
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)869e5dd7070Spatrick inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
870e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
871e5dd7070Spatrick if (!CheckNull(S, OpPC, Ptr, CSK_Base))
872e5dd7070Spatrick return false;
873e5dd7070Spatrick S.Stk.push<Pointer>(Ptr.atField(Off));
874e5dd7070Spatrick return true;
875e5dd7070Spatrick }
876e5dd7070Spatrick
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)877e5dd7070Spatrick inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
878e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
879e5dd7070Spatrick return false;
880e5dd7070Spatrick const Pointer &This = S.Current->getThis();
881e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
882e5dd7070Spatrick return false;
883e5dd7070Spatrick S.Stk.push<Pointer>(This.atField(Off));
884e5dd7070Spatrick return true;
885e5dd7070Spatrick }
886e5dd7070Spatrick
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)887e5dd7070Spatrick inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
888e5dd7070Spatrick const Pointer &Ptr) {
889e5dd7070Spatrick Pointer Base = Ptr;
890e5dd7070Spatrick while (Base.isBaseClass())
891e5dd7070Spatrick Base = Base.getBase();
892e5dd7070Spatrick
893e5dd7070Spatrick auto *Field = Base.getRecord()->getVirtualBase(Decl);
894e5dd7070Spatrick S.Stk.push<Pointer>(Base.atField(Field->Offset));
895e5dd7070Spatrick return true;
896e5dd7070Spatrick }
897e5dd7070Spatrick
GetPtrVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)898e5dd7070Spatrick inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
899e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
900e5dd7070Spatrick if (!CheckNull(S, OpPC, Ptr, CSK_Base))
901e5dd7070Spatrick return false;
902e5dd7070Spatrick return VirtBaseHelper(S, OpPC, D, Ptr);
903e5dd7070Spatrick }
904e5dd7070Spatrick
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)905e5dd7070Spatrick inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
906e5dd7070Spatrick const RecordDecl *D) {
907e5dd7070Spatrick if (S.checkingPotentialConstantExpression())
908e5dd7070Spatrick return false;
909e5dd7070Spatrick const Pointer &This = S.Current->getThis();
910e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
911e5dd7070Spatrick return false;
912e5dd7070Spatrick return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
913e5dd7070Spatrick }
914e5dd7070Spatrick
915e5dd7070Spatrick //===----------------------------------------------------------------------===//
916e5dd7070Spatrick // Load, Store, Init
917e5dd7070Spatrick //===----------------------------------------------------------------------===//
918e5dd7070Spatrick
919e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)920e5dd7070Spatrick bool Load(InterpState &S, CodePtr OpPC) {
921e5dd7070Spatrick const Pointer &Ptr = S.Stk.peek<Pointer>();
922e5dd7070Spatrick if (!CheckLoad(S, OpPC, Ptr))
923e5dd7070Spatrick return false;
924e5dd7070Spatrick S.Stk.push<T>(Ptr.deref<T>());
925e5dd7070Spatrick return true;
926e5dd7070Spatrick }
927e5dd7070Spatrick
928e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)929e5dd7070Spatrick bool LoadPop(InterpState &S, CodePtr OpPC) {
930e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
931e5dd7070Spatrick if (!CheckLoad(S, OpPC, Ptr))
932e5dd7070Spatrick return false;
933e5dd7070Spatrick S.Stk.push<T>(Ptr.deref<T>());
934e5dd7070Spatrick return true;
935e5dd7070Spatrick }
936e5dd7070Spatrick
937e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)938e5dd7070Spatrick bool Store(InterpState &S, CodePtr OpPC) {
939e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
940e5dd7070Spatrick const Pointer &Ptr = S.Stk.peek<Pointer>();
941e5dd7070Spatrick if (!CheckStore(S, OpPC, Ptr))
942e5dd7070Spatrick return false;
943*12c85518Srobert if (!Ptr.isRoot())
944*12c85518Srobert Ptr.initialize();
945e5dd7070Spatrick Ptr.deref<T>() = Value;
946e5dd7070Spatrick return true;
947e5dd7070Spatrick }
948e5dd7070Spatrick
949e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)950e5dd7070Spatrick bool StorePop(InterpState &S, CodePtr OpPC) {
951e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
952e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
953e5dd7070Spatrick if (!CheckStore(S, OpPC, Ptr))
954e5dd7070Spatrick return false;
955*12c85518Srobert if (!Ptr.isRoot())
956*12c85518Srobert Ptr.initialize();
957e5dd7070Spatrick Ptr.deref<T>() = Value;
958e5dd7070Spatrick return true;
959e5dd7070Spatrick }
960e5dd7070Spatrick
961e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)962e5dd7070Spatrick bool StoreBitField(InterpState &S, CodePtr OpPC) {
963e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
964e5dd7070Spatrick const Pointer &Ptr = S.Stk.peek<Pointer>();
965e5dd7070Spatrick if (!CheckStore(S, OpPC, Ptr))
966e5dd7070Spatrick return false;
967*12c85518Srobert if (!Ptr.isRoot())
968*12c85518Srobert Ptr.initialize();
969e5dd7070Spatrick if (auto *FD = Ptr.getField()) {
970e5dd7070Spatrick Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
971e5dd7070Spatrick } else {
972e5dd7070Spatrick Ptr.deref<T>() = Value;
973e5dd7070Spatrick }
974e5dd7070Spatrick return true;
975e5dd7070Spatrick }
976e5dd7070Spatrick
977e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)978e5dd7070Spatrick bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
979e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
980e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
981e5dd7070Spatrick if (!CheckStore(S, OpPC, Ptr))
982e5dd7070Spatrick return false;
983*12c85518Srobert if (!Ptr.isRoot())
984*12c85518Srobert Ptr.initialize();
985e5dd7070Spatrick if (auto *FD = Ptr.getField()) {
986e5dd7070Spatrick Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
987e5dd7070Spatrick } else {
988e5dd7070Spatrick Ptr.deref<T>() = Value;
989e5dd7070Spatrick }
990e5dd7070Spatrick return true;
991e5dd7070Spatrick }
992e5dd7070Spatrick
993e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)994e5dd7070Spatrick bool InitPop(InterpState &S, CodePtr OpPC) {
995e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
996e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
997e5dd7070Spatrick if (!CheckInit(S, OpPC, Ptr))
998e5dd7070Spatrick return false;
999e5dd7070Spatrick Ptr.initialize();
1000e5dd7070Spatrick new (&Ptr.deref<T>()) T(Value);
1001e5dd7070Spatrick return true;
1002e5dd7070Spatrick }
1003e5dd7070Spatrick
1004*12c85518Srobert /// 1) Pops the value from the stack
1005*12c85518Srobert /// 2) Peeks a pointer and gets its index \Idx
1006*12c85518Srobert /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1007e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)1008e5dd7070Spatrick bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1009e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
1010e5dd7070Spatrick const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1011e5dd7070Spatrick if (!CheckInit(S, OpPC, Ptr))
1012e5dd7070Spatrick return false;
1013e5dd7070Spatrick Ptr.initialize();
1014e5dd7070Spatrick new (&Ptr.deref<T>()) T(Value);
1015e5dd7070Spatrick return true;
1016e5dd7070Spatrick }
1017e5dd7070Spatrick
1018*12c85518Srobert /// The same as InitElem, but pops the pointer as well.
1019e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)1020e5dd7070Spatrick bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1021e5dd7070Spatrick const T &Value = S.Stk.pop<T>();
1022e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1023e5dd7070Spatrick if (!CheckInit(S, OpPC, Ptr))
1024e5dd7070Spatrick return false;
1025e5dd7070Spatrick Ptr.initialize();
1026e5dd7070Spatrick new (&Ptr.deref<T>()) T(Value);
1027e5dd7070Spatrick return true;
1028e5dd7070Spatrick }
1029e5dd7070Spatrick
1030e5dd7070Spatrick //===----------------------------------------------------------------------===//
1031e5dd7070Spatrick // AddOffset, SubOffset
1032e5dd7070Spatrick //===----------------------------------------------------------------------===//
1033e5dd7070Spatrick
OffsetHelper(InterpState & S,CodePtr OpPC)1034e5dd7070Spatrick template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
1035e5dd7070Spatrick // Fetch the pointer and the offset.
1036e5dd7070Spatrick const T &Offset = S.Stk.pop<T>();
1037e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
1038*12c85518Srobert
1039e5dd7070Spatrick if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1040e5dd7070Spatrick return false;
1041e5dd7070Spatrick
1042*12c85518Srobert // A zero offset does not change the pointer.
1043e5dd7070Spatrick if (Offset.isZero()) {
1044*12c85518Srobert S.Stk.push<Pointer>(Ptr);
1045e5dd7070Spatrick return true;
1046e5dd7070Spatrick }
1047*12c85518Srobert
1048*12c85518Srobert if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1049*12c85518Srobert return false;
1050*12c85518Srobert
1051e5dd7070Spatrick // Arrays of unknown bounds cannot have pointers into them.
1052e5dd7070Spatrick if (!CheckArray(S, OpPC, Ptr))
1053e5dd7070Spatrick return false;
1054e5dd7070Spatrick
1055*12c85518Srobert // Get a version of the index comparable to the type.
1056*12c85518Srobert T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1057e5dd7070Spatrick // Compute the largest index into the array.
1058e5dd7070Spatrick unsigned MaxIndex = Ptr.getNumElems();
1059e5dd7070Spatrick
1060e5dd7070Spatrick // Helper to report an invalid offset, computed as APSInt.
1061e5dd7070Spatrick auto InvalidOffset = [&]() {
1062e5dd7070Spatrick const unsigned Bits = Offset.bitWidth();
1063e5dd7070Spatrick APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1064e5dd7070Spatrick APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1065e5dd7070Spatrick APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
1066e5dd7070Spatrick S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1067e5dd7070Spatrick << NewIndex
1068e5dd7070Spatrick << /*array*/ static_cast<int>(!Ptr.inArray())
1069e5dd7070Spatrick << static_cast<unsigned>(MaxIndex);
1070e5dd7070Spatrick return false;
1071e5dd7070Spatrick };
1072e5dd7070Spatrick
1073*12c85518Srobert unsigned MaxOffset = MaxIndex - Ptr.getIndex();
1074*12c85518Srobert if constexpr (Add) {
1075e5dd7070Spatrick // If the new offset would be negative, bail out.
1076*12c85518Srobert if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1077e5dd7070Spatrick return InvalidOffset();
1078e5dd7070Spatrick
1079e5dd7070Spatrick // If the new offset would be out of bounds, bail out.
1080*12c85518Srobert if (Offset.isPositive() && Offset > MaxOffset)
1081e5dd7070Spatrick return InvalidOffset();
1082*12c85518Srobert } else {
1083*12c85518Srobert // If the new offset would be negative, bail out.
1084*12c85518Srobert if (Offset.isPositive() && Index < Offset)
1085e5dd7070Spatrick return InvalidOffset();
1086e5dd7070Spatrick
1087*12c85518Srobert // If the new offset would be out of bounds, bail out.
1088*12c85518Srobert if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1089*12c85518Srobert return InvalidOffset();
1090*12c85518Srobert }
1091*12c85518Srobert
1092e5dd7070Spatrick // Offset is valid - compute it on unsigned.
1093e5dd7070Spatrick int64_t WideIndex = static_cast<int64_t>(Index);
1094e5dd7070Spatrick int64_t WideOffset = static_cast<int64_t>(Offset);
1095*12c85518Srobert int64_t Result;
1096*12c85518Srobert if constexpr (Add)
1097*12c85518Srobert Result = WideIndex + WideOffset;
1098*12c85518Srobert else
1099*12c85518Srobert Result = WideIndex - WideOffset;
1100*12c85518Srobert
1101e5dd7070Spatrick S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1102e5dd7070Spatrick return true;
1103e5dd7070Spatrick }
1104e5dd7070Spatrick
1105e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)1106e5dd7070Spatrick bool AddOffset(InterpState &S, CodePtr OpPC) {
1107e5dd7070Spatrick return OffsetHelper<T, true>(S, OpPC);
1108e5dd7070Spatrick }
1109e5dd7070Spatrick
1110e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)1111e5dd7070Spatrick bool SubOffset(InterpState &S, CodePtr OpPC) {
1112e5dd7070Spatrick return OffsetHelper<T, false>(S, OpPC);
1113e5dd7070Spatrick }
1114e5dd7070Spatrick
1115*12c85518Srobert /// 1) Pops a Pointer from the stack.
1116*12c85518Srobert /// 2) Pops another Pointer from the stack.
1117*12c85518Srobert /// 3) Pushes the different of the indices of the two pointers on the stack.
1118*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
SubPtr(InterpState & S,CodePtr OpPC)1119*12c85518Srobert inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1120*12c85518Srobert const Pointer &LHS = S.Stk.pop<Pointer>();
1121*12c85518Srobert const Pointer &RHS = S.Stk.pop<Pointer>();
1122*12c85518Srobert
1123*12c85518Srobert if (!Pointer::hasSameArray(LHS, RHS)) {
1124*12c85518Srobert // TODO: Diagnose.
1125*12c85518Srobert return false;
1126*12c85518Srobert }
1127*12c85518Srobert
1128*12c85518Srobert T A = T::from(LHS.getIndex());
1129*12c85518Srobert T B = T::from(RHS.getIndex());
1130*12c85518Srobert return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1131*12c85518Srobert }
1132e5dd7070Spatrick
1133e5dd7070Spatrick //===----------------------------------------------------------------------===//
1134e5dd7070Spatrick // Destroy
1135e5dd7070Spatrick //===----------------------------------------------------------------------===//
1136e5dd7070Spatrick
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)1137e5dd7070Spatrick inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1138e5dd7070Spatrick S.Current->destroy(I);
1139e5dd7070Spatrick return true;
1140e5dd7070Spatrick }
1141e5dd7070Spatrick
1142e5dd7070Spatrick //===----------------------------------------------------------------------===//
1143e5dd7070Spatrick // Cast, CastFP
1144e5dd7070Spatrick //===----------------------------------------------------------------------===//
1145e5dd7070Spatrick
Cast(InterpState & S,CodePtr OpPC)1146e5dd7070Spatrick template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1147e5dd7070Spatrick using T = typename PrimConv<TIn>::T;
1148e5dd7070Spatrick using U = typename PrimConv<TOut>::T;
1149e5dd7070Spatrick S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1150e5dd7070Spatrick return true;
1151e5dd7070Spatrick }
1152e5dd7070Spatrick
1153e5dd7070Spatrick //===----------------------------------------------------------------------===//
1154e5dd7070Spatrick // Zero, Nullptr
1155e5dd7070Spatrick //===----------------------------------------------------------------------===//
1156e5dd7070Spatrick
1157e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)1158e5dd7070Spatrick bool Zero(InterpState &S, CodePtr OpPC) {
1159e5dd7070Spatrick S.Stk.push<T>(T::zero());
1160e5dd7070Spatrick return true;
1161e5dd7070Spatrick }
1162e5dd7070Spatrick
1163e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC)1164e5dd7070Spatrick inline bool Null(InterpState &S, CodePtr OpPC) {
1165e5dd7070Spatrick S.Stk.push<T>();
1166e5dd7070Spatrick return true;
1167e5dd7070Spatrick }
1168e5dd7070Spatrick
1169e5dd7070Spatrick //===----------------------------------------------------------------------===//
1170e5dd7070Spatrick // This, ImplicitThis
1171e5dd7070Spatrick //===----------------------------------------------------------------------===//
1172e5dd7070Spatrick
This(InterpState & S,CodePtr OpPC)1173e5dd7070Spatrick inline bool This(InterpState &S, CodePtr OpPC) {
1174e5dd7070Spatrick // Cannot read 'this' in this mode.
1175e5dd7070Spatrick if (S.checkingPotentialConstantExpression()) {
1176e5dd7070Spatrick return false;
1177e5dd7070Spatrick }
1178e5dd7070Spatrick
1179e5dd7070Spatrick const Pointer &This = S.Current->getThis();
1180e5dd7070Spatrick if (!CheckThis(S, OpPC, This))
1181e5dd7070Spatrick return false;
1182e5dd7070Spatrick
1183e5dd7070Spatrick S.Stk.push<Pointer>(This);
1184e5dd7070Spatrick return true;
1185e5dd7070Spatrick }
1186e5dd7070Spatrick
RVOPtr(InterpState & S,CodePtr OpPC)1187*12c85518Srobert inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1188*12c85518Srobert assert(S.Current->getFunction()->hasRVO());
1189*12c85518Srobert S.Stk.push<Pointer>(S.Current->getRVOPtr());
1190*12c85518Srobert return true;
1191*12c85518Srobert }
1192*12c85518Srobert
1193e5dd7070Spatrick //===----------------------------------------------------------------------===//
1194e5dd7070Spatrick // Shr, Shl
1195e5dd7070Spatrick //===----------------------------------------------------------------------===//
1196e5dd7070Spatrick
1197*12c85518Srobert template <PrimType NameL, PrimType NameR>
Shr(InterpState & S,CodePtr OpPC)1198e5dd7070Spatrick inline bool Shr(InterpState &S, CodePtr OpPC) {
1199*12c85518Srobert using LT = typename PrimConv<NameL>::T;
1200*12c85518Srobert using RT = typename PrimConv<NameR>::T;
1201*12c85518Srobert const auto &RHS = S.Stk.pop<RT>();
1202*12c85518Srobert const auto &LHS = S.Stk.pop<LT>();
1203e5dd7070Spatrick const unsigned Bits = LHS.bitWidth();
1204e5dd7070Spatrick
1205*12c85518Srobert if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1206*12c85518Srobert return false;
1207*12c85518Srobert
1208*12c85518Srobert unsigned URHS = static_cast<unsigned>(RHS);
1209*12c85518Srobert S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth()));
1210*12c85518Srobert return true;
1211e5dd7070Spatrick }
1212e5dd7070Spatrick
1213*12c85518Srobert template <PrimType NameL, PrimType NameR>
Shl(InterpState & S,CodePtr OpPC)1214e5dd7070Spatrick inline bool Shl(InterpState &S, CodePtr OpPC) {
1215*12c85518Srobert using LT = typename PrimConv<NameL>::T;
1216*12c85518Srobert using RT = typename PrimConv<NameR>::T;
1217*12c85518Srobert const auto &RHS = S.Stk.pop<RT>();
1218*12c85518Srobert const auto &LHS = S.Stk.pop<LT>();
1219e5dd7070Spatrick const unsigned Bits = LHS.bitWidth();
1220e5dd7070Spatrick
1221*12c85518Srobert if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1222*12c85518Srobert return false;
1223*12c85518Srobert
1224*12c85518Srobert unsigned URHS = static_cast<unsigned>(RHS);
1225*12c85518Srobert S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth()));
1226*12c85518Srobert
1227*12c85518Srobert return true;
1228e5dd7070Spatrick }
1229e5dd7070Spatrick
1230e5dd7070Spatrick //===----------------------------------------------------------------------===//
1231e5dd7070Spatrick // NoRet
1232e5dd7070Spatrick //===----------------------------------------------------------------------===//
1233e5dd7070Spatrick
NoRet(InterpState & S,CodePtr OpPC)1234e5dd7070Spatrick inline bool NoRet(InterpState &S, CodePtr OpPC) {
1235e5dd7070Spatrick SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1236e5dd7070Spatrick S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1237e5dd7070Spatrick return false;
1238e5dd7070Spatrick }
1239e5dd7070Spatrick
1240e5dd7070Spatrick //===----------------------------------------------------------------------===//
1241e5dd7070Spatrick // NarrowPtr, ExpandPtr
1242e5dd7070Spatrick //===----------------------------------------------------------------------===//
1243e5dd7070Spatrick
NarrowPtr(InterpState & S,CodePtr OpPC)1244e5dd7070Spatrick inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1245e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
1246e5dd7070Spatrick S.Stk.push<Pointer>(Ptr.narrow());
1247e5dd7070Spatrick return true;
1248e5dd7070Spatrick }
1249e5dd7070Spatrick
ExpandPtr(InterpState & S,CodePtr OpPC)1250e5dd7070Spatrick inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1251e5dd7070Spatrick const Pointer &Ptr = S.Stk.pop<Pointer>();
1252e5dd7070Spatrick S.Stk.push<Pointer>(Ptr.expand());
1253e5dd7070Spatrick return true;
1254e5dd7070Spatrick }
1255e5dd7070Spatrick
Call(InterpState & S,CodePtr & PC,const Function * Func)1256*12c85518Srobert inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
1257*12c85518Srobert auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1258*12c85518Srobert Pointer ThisPtr;
1259*12c85518Srobert if (Func->hasThisPointer()) {
1260*12c85518Srobert ThisPtr = NewFrame->getThis();
1261*12c85518Srobert if (!CheckInvoke(S, PC, ThisPtr)) {
1262*12c85518Srobert return false;
1263*12c85518Srobert }
1264*12c85518Srobert }
1265*12c85518Srobert
1266*12c85518Srobert if (!CheckCallable(S, PC, Func))
1267*12c85518Srobert return false;
1268*12c85518Srobert
1269*12c85518Srobert InterpFrame *FrameBefore = S.Current;
1270*12c85518Srobert S.Current = NewFrame.get();
1271*12c85518Srobert
1272*12c85518Srobert APValue CallResult;
1273*12c85518Srobert // Note that we cannot assert(CallResult.hasValue()) here since
1274*12c85518Srobert // Ret() above only sets the APValue if the curent frame doesn't
1275*12c85518Srobert // have a caller set.
1276*12c85518Srobert if (Interpret(S, CallResult)) {
1277*12c85518Srobert NewFrame.release(); // Frame was delete'd already.
1278*12c85518Srobert assert(S.Current == FrameBefore);
1279*12c85518Srobert
1280*12c85518Srobert // For constructors, check that all fields have been initialized.
1281*12c85518Srobert if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr))
1282*12c85518Srobert return false;
1283*12c85518Srobert
1284*12c85518Srobert return true;
1285*12c85518Srobert }
1286*12c85518Srobert
1287*12c85518Srobert // Interpreting the function failed somehow. Reset to
1288*12c85518Srobert // previous state.
1289*12c85518Srobert S.Current = FrameBefore;
1290*12c85518Srobert return false;
1291*12c85518Srobert }
1292*12c85518Srobert
1293*12c85518Srobert //===----------------------------------------------------------------------===//
1294*12c85518Srobert // Read opcode arguments
1295*12c85518Srobert //===----------------------------------------------------------------------===//
1296*12c85518Srobert
ReadArg(InterpState & S,CodePtr & OpPC)1297*12c85518Srobert template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
1298*12c85518Srobert if constexpr (std::is_pointer<T>::value) {
1299*12c85518Srobert uint32_t ID = OpPC.read<uint32_t>();
1300*12c85518Srobert return reinterpret_cast<T>(S.P.getNativePointer(ID));
1301*12c85518Srobert } else {
1302*12c85518Srobert return OpPC.read<T>();
1303*12c85518Srobert }
1304*12c85518Srobert }
1305e5dd7070Spatrick
1306e5dd7070Spatrick } // namespace interp
1307e5dd7070Spatrick } // namespace clang
1308e5dd7070Spatrick
1309e5dd7070Spatrick #endif
1310