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