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 
16bdd1243dSDimitry Andric #include "Boolean.h"
17*06c3fb27SDimitry Andric #include "Floating.h"
18a7dea167SDimitry Andric #include "Function.h"
19*06c3fb27SDimitry Andric #include "FunctionPointer.h"
20a7dea167SDimitry Andric #include "InterpFrame.h"
21a7dea167SDimitry Andric #include "InterpStack.h"
22a7dea167SDimitry Andric #include "InterpState.h"
23a7dea167SDimitry Andric #include "Opcode.h"
24a7dea167SDimitry Andric #include "PrimType.h"
25a7dea167SDimitry Andric #include "Program.h"
26a7dea167SDimitry Andric #include "State.h"
27a7dea167SDimitry Andric #include "clang/AST/ASTContext.h"
28a7dea167SDimitry Andric #include "clang/AST/ASTDiagnostic.h"
29a7dea167SDimitry Andric #include "clang/AST/CXXInheritance.h"
30a7dea167SDimitry Andric #include "clang/AST/Expr.h"
31a7dea167SDimitry Andric #include "llvm/ADT/APFloat.h"
32a7dea167SDimitry Andric #include "llvm/ADT/APSInt.h"
33a7dea167SDimitry Andric #include "llvm/Support/Endian.h"
34349cc55cSDimitry Andric #include <limits>
35349cc55cSDimitry Andric #include <type_traits>
36a7dea167SDimitry Andric 
37a7dea167SDimitry Andric namespace clang {
38a7dea167SDimitry Andric namespace interp {
39a7dea167SDimitry Andric 
40a7dea167SDimitry Andric using APInt = llvm::APInt;
41a7dea167SDimitry Andric using APSInt = llvm::APSInt;
42a7dea167SDimitry Andric 
43349cc55cSDimitry Andric /// Convert a value to an APValue.
44a7dea167SDimitry Andric template <typename T> bool ReturnValue(const T &V, APValue &R) {
45a7dea167SDimitry Andric   R = V.toAPValue();
46a7dea167SDimitry Andric   return true;
47a7dea167SDimitry Andric }
48a7dea167SDimitry Andric 
49a7dea167SDimitry Andric /// Checks if the variable has externally defined storage.
50a7dea167SDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
51a7dea167SDimitry Andric 
52a7dea167SDimitry Andric /// Checks if the array is offsetable.
53a7dea167SDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
54a7dea167SDimitry Andric 
55349cc55cSDimitry Andric /// Checks if a pointer is live and accessible.
56a7dea167SDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57a7dea167SDimitry Andric                AccessKinds AK);
58a7dea167SDimitry Andric /// Checks if a pointer is null.
59a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60a7dea167SDimitry Andric                CheckSubobjectKind CSK);
61a7dea167SDimitry Andric 
62a7dea167SDimitry Andric /// Checks if a pointer is in range.
63a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64a7dea167SDimitry Andric                 AccessKinds AK);
65a7dea167SDimitry Andric 
66a7dea167SDimitry Andric /// Checks if a field from which a pointer is going to be derived is valid.
67a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68a7dea167SDimitry Andric                 CheckSubobjectKind CSK);
69a7dea167SDimitry Andric 
70a7dea167SDimitry Andric /// Checks if a pointer points to const storage.
71a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
72a7dea167SDimitry Andric 
73a7dea167SDimitry Andric /// Checks if a pointer points to a mutable field.
74a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
75a7dea167SDimitry Andric 
76a7dea167SDimitry Andric /// Checks if a value can be loaded from a block.
77a7dea167SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
78a7dea167SDimitry Andric 
79*06c3fb27SDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
80*06c3fb27SDimitry Andric                       AccessKinds AK);
81*06c3fb27SDimitry Andric 
82a7dea167SDimitry Andric /// Checks if a value can be stored in a block.
83a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
84a7dea167SDimitry Andric 
85a7dea167SDimitry Andric /// Checks if a method can be invoked on an object.
86a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
87a7dea167SDimitry Andric 
88a7dea167SDimitry Andric /// Checks if a value can be initialized.
89a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
90a7dea167SDimitry Andric 
91a7dea167SDimitry Andric /// Checks if a method can be called.
92bdd1243dSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
93a7dea167SDimitry Andric 
94*06c3fb27SDimitry Andric /// Checks if calling the currently active function would exceed
95*06c3fb27SDimitry Andric /// the allowed call depth.
96*06c3fb27SDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC);
97*06c3fb27SDimitry Andric 
98a7dea167SDimitry Andric /// Checks the 'this' pointer.
99a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
100a7dea167SDimitry Andric 
101a7dea167SDimitry Andric /// Checks if a method is pure virtual.
102a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
103a7dea167SDimitry Andric 
104bdd1243dSDimitry Andric /// Checks that all fields are initialized after a constructor call.
105bdd1243dSDimitry Andric bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
106bdd1243dSDimitry Andric 
107bdd1243dSDimitry Andric /// Checks if the shift operation is legal.
108*06c3fb27SDimitry Andric template <typename LT, typename RT>
109*06c3fb27SDimitry Andric bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
110*06c3fb27SDimitry Andric                 unsigned Bits) {
111bdd1243dSDimitry Andric   if (RHS.isNegative()) {
112bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
113bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
114bdd1243dSDimitry Andric     return false;
115bdd1243dSDimitry Andric   }
116bdd1243dSDimitry Andric 
117bdd1243dSDimitry Andric   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
118bdd1243dSDimitry Andric   // the shifted type.
119bdd1243dSDimitry Andric   if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
120bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
121bdd1243dSDimitry Andric     const APSInt Val = RHS.toAPSInt();
122bdd1243dSDimitry Andric     QualType Ty = E->getType();
123bdd1243dSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
124bdd1243dSDimitry Andric     return false;
125bdd1243dSDimitry Andric   }
126*06c3fb27SDimitry Andric 
127*06c3fb27SDimitry Andric   if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
128*06c3fb27SDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
129*06c3fb27SDimitry Andric     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
130*06c3fb27SDimitry Andric     // operand, and must not overflow the corresponding unsigned type.
131*06c3fb27SDimitry Andric     if (LHS.isNegative())
132*06c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
133*06c3fb27SDimitry Andric     else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
134*06c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_discards);
135*06c3fb27SDimitry Andric   }
136*06c3fb27SDimitry Andric 
137*06c3fb27SDimitry Andric   // C++2a [expr.shift]p2: [P0907R4]:
138*06c3fb27SDimitry Andric   //    E1 << E2 is the unique value congruent to
139*06c3fb27SDimitry Andric   //    E1 x 2^E2 module 2^N.
140bdd1243dSDimitry Andric   return true;
141bdd1243dSDimitry Andric }
142bdd1243dSDimitry Andric 
143bdd1243dSDimitry Andric /// Checks if Div/Rem operation on LHS and RHS is valid.
144bdd1243dSDimitry Andric template <typename T>
145bdd1243dSDimitry Andric bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
146bdd1243dSDimitry Andric   if (RHS.isZero()) {
147bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
148bdd1243dSDimitry Andric     S.FFDiag(Loc, diag::note_expr_divide_by_zero);
149bdd1243dSDimitry Andric     return false;
150bdd1243dSDimitry Andric   }
151bdd1243dSDimitry Andric 
152bdd1243dSDimitry Andric   if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
153bdd1243dSDimitry Andric     APSInt LHSInt = LHS.toAPSInt();
154bdd1243dSDimitry Andric     SmallString<32> Trunc;
155bdd1243dSDimitry Andric     (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
156bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
157bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
158bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
159bdd1243dSDimitry Andric     return false;
160bdd1243dSDimitry Andric   }
161bdd1243dSDimitry Andric   return true;
162bdd1243dSDimitry Andric }
163bdd1243dSDimitry Andric 
164*06c3fb27SDimitry Andric /// Checks if the result is a floating-point operation is valid
165*06c3fb27SDimitry Andric /// in the current context.
166*06c3fb27SDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
167*06c3fb27SDimitry Andric 
168bdd1243dSDimitry Andric /// Interpreter entry point.
169bdd1243dSDimitry Andric bool Interpret(InterpState &S, APValue &Result);
170a7dea167SDimitry Andric 
171*06c3fb27SDimitry Andric /// Interpret a builtin function.
172*06c3fb27SDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F);
173*06c3fb27SDimitry Andric 
174*06c3fb27SDimitry Andric enum class ArithOp { Add, Sub };
175*06c3fb27SDimitry Andric 
176*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
177*06c3fb27SDimitry Andric // Returning values
178*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
179*06c3fb27SDimitry Andric 
180*06c3fb27SDimitry Andric template <PrimType Name, bool Builtin = false,
181*06c3fb27SDimitry Andric           class T = typename PrimConv<Name>::T>
182*06c3fb27SDimitry Andric bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
183*06c3fb27SDimitry Andric   const T &Ret = S.Stk.pop<T>();
184*06c3fb27SDimitry Andric 
185*06c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
186*06c3fb27SDimitry Andric   if (Builtin || !S.checkingPotentialConstantExpression())
187*06c3fb27SDimitry Andric     S.Current->popArgs();
188*06c3fb27SDimitry Andric 
189*06c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
190*06c3fb27SDimitry Andric     PC = S.Current->getRetPC();
191*06c3fb27SDimitry Andric     delete S.Current;
192*06c3fb27SDimitry Andric     S.Current = Caller;
193*06c3fb27SDimitry Andric     S.Stk.push<T>(Ret);
194*06c3fb27SDimitry Andric   } else {
195*06c3fb27SDimitry Andric     delete S.Current;
196*06c3fb27SDimitry Andric     S.Current = nullptr;
197*06c3fb27SDimitry Andric     if (!ReturnValue<T>(Ret, Result))
198*06c3fb27SDimitry Andric       return false;
199*06c3fb27SDimitry Andric   }
200*06c3fb27SDimitry Andric   return true;
201*06c3fb27SDimitry Andric }
202*06c3fb27SDimitry Andric 
203*06c3fb27SDimitry Andric template <bool Builtin = false>
204*06c3fb27SDimitry Andric inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
205*06c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
206*06c3fb27SDimitry Andric   if (Builtin || !S.checkingPotentialConstantExpression())
207*06c3fb27SDimitry Andric     S.Current->popArgs();
208*06c3fb27SDimitry Andric 
209*06c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
210*06c3fb27SDimitry Andric     PC = S.Current->getRetPC();
211*06c3fb27SDimitry Andric     delete S.Current;
212*06c3fb27SDimitry Andric     S.Current = Caller;
213*06c3fb27SDimitry Andric   } else {
214*06c3fb27SDimitry Andric     delete S.Current;
215*06c3fb27SDimitry Andric     S.Current = nullptr;
216*06c3fb27SDimitry Andric   }
217*06c3fb27SDimitry Andric   return true;
218*06c3fb27SDimitry Andric }
219*06c3fb27SDimitry Andric 
220a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
221a7dea167SDimitry Andric // Add, Sub, Mul
222a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
223a7dea167SDimitry Andric 
224a7dea167SDimitry Andric template <typename T, bool (*OpFW)(T, T, unsigned, T *),
225a7dea167SDimitry Andric           template <typename U> class OpAP>
226a7dea167SDimitry Andric bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
227a7dea167SDimitry Andric                      const T &RHS) {
228a7dea167SDimitry Andric   // Fast path - add the numbers with fixed width.
229a7dea167SDimitry Andric   T Result;
230a7dea167SDimitry Andric   if (!OpFW(LHS, RHS, Bits, &Result)) {
231a7dea167SDimitry Andric     S.Stk.push<T>(Result);
232a7dea167SDimitry Andric     return true;
233a7dea167SDimitry Andric   }
234a7dea167SDimitry Andric 
235a7dea167SDimitry Andric   // If for some reason evaluation continues, use the truncated results.
236a7dea167SDimitry Andric   S.Stk.push<T>(Result);
237a7dea167SDimitry Andric 
238a7dea167SDimitry Andric   // Slow path - compute the result using another bit of precision.
239a7dea167SDimitry Andric   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
240a7dea167SDimitry Andric 
241a7dea167SDimitry Andric   // Report undefined behaviour, stopping if required.
242a7dea167SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
243a7dea167SDimitry Andric   QualType Type = E->getType();
244a7dea167SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
245fe6060f1SDimitry Andric     SmallString<32> Trunc;
246fe6060f1SDimitry Andric     Value.trunc(Result.bitWidth()).toString(Trunc, 10);
247a7dea167SDimitry Andric     auto Loc = E->getExprLoc();
248a7dea167SDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
249a7dea167SDimitry Andric     return true;
250a7dea167SDimitry Andric   } else {
251a7dea167SDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
252a7dea167SDimitry Andric     return S.noteUndefinedBehavior();
253a7dea167SDimitry Andric   }
254a7dea167SDimitry Andric }
255a7dea167SDimitry Andric 
256a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
257a7dea167SDimitry Andric bool Add(InterpState &S, CodePtr OpPC) {
258a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
259a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
260a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
261a7dea167SDimitry Andric   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
262a7dea167SDimitry Andric }
263a7dea167SDimitry Andric 
264*06c3fb27SDimitry Andric inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
265*06c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
266*06c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
267*06c3fb27SDimitry Andric 
268*06c3fb27SDimitry Andric   Floating Result;
269*06c3fb27SDimitry Andric   auto Status = Floating::add(LHS, RHS, RM, &Result);
270*06c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
271*06c3fb27SDimitry Andric   return CheckFloatResult(S, OpPC, Status);
272*06c3fb27SDimitry Andric }
273*06c3fb27SDimitry Andric 
274a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
275a7dea167SDimitry Andric bool Sub(InterpState &S, CodePtr OpPC) {
276a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
277a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
278a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
279a7dea167SDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
280a7dea167SDimitry Andric }
281a7dea167SDimitry Andric 
282*06c3fb27SDimitry Andric inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
283*06c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
284*06c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
285*06c3fb27SDimitry Andric 
286*06c3fb27SDimitry Andric   Floating Result;
287*06c3fb27SDimitry Andric   auto Status = Floating::sub(LHS, RHS, RM, &Result);
288*06c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
289*06c3fb27SDimitry Andric   return CheckFloatResult(S, OpPC, Status);
290*06c3fb27SDimitry Andric }
291*06c3fb27SDimitry Andric 
292a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
293a7dea167SDimitry Andric bool Mul(InterpState &S, CodePtr OpPC) {
294a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
295a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
296a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
297a7dea167SDimitry Andric   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
298a7dea167SDimitry Andric }
299a7dea167SDimitry Andric 
300*06c3fb27SDimitry Andric inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
301*06c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
302*06c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
303*06c3fb27SDimitry Andric 
304*06c3fb27SDimitry Andric   Floating Result;
305*06c3fb27SDimitry Andric   auto Status = Floating::mul(LHS, RHS, RM, &Result);
306*06c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
307*06c3fb27SDimitry Andric   return CheckFloatResult(S, OpPC, Status);
308*06c3fb27SDimitry Andric }
309bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
310bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
311bdd1243dSDimitry Andric /// 3) Pushes 'LHS & RHS' on the stack
312bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
313bdd1243dSDimitry Andric bool BitAnd(InterpState &S, CodePtr OpPC) {
314bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
315bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
316bdd1243dSDimitry Andric 
317bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
318bdd1243dSDimitry Andric   T Result;
319bdd1243dSDimitry Andric   if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
320bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
321bdd1243dSDimitry Andric     return true;
322bdd1243dSDimitry Andric   }
323bdd1243dSDimitry Andric   return false;
324bdd1243dSDimitry Andric }
325bdd1243dSDimitry Andric 
326bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
327bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
328bdd1243dSDimitry Andric /// 3) Pushes 'LHS | RHS' on the stack
329bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
330bdd1243dSDimitry Andric bool BitOr(InterpState &S, CodePtr OpPC) {
331bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
332bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
333bdd1243dSDimitry Andric 
334bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
335bdd1243dSDimitry Andric   T Result;
336bdd1243dSDimitry Andric   if (!T::bitOr(LHS, RHS, Bits, &Result)) {
337bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
338bdd1243dSDimitry Andric     return true;
339bdd1243dSDimitry Andric   }
340bdd1243dSDimitry Andric   return false;
341bdd1243dSDimitry Andric }
342bdd1243dSDimitry Andric 
343bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
344bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
345bdd1243dSDimitry Andric /// 3) Pushes 'LHS ^ RHS' on the stack
346bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
347bdd1243dSDimitry Andric bool BitXor(InterpState &S, CodePtr OpPC) {
348bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
349bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
350bdd1243dSDimitry Andric 
351bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
352bdd1243dSDimitry Andric   T Result;
353bdd1243dSDimitry Andric   if (!T::bitXor(LHS, RHS, Bits, &Result)) {
354bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
355bdd1243dSDimitry Andric     return true;
356bdd1243dSDimitry Andric   }
357bdd1243dSDimitry Andric   return false;
358bdd1243dSDimitry Andric }
359bdd1243dSDimitry Andric 
360bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
361bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
362bdd1243dSDimitry Andric /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
363bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
364bdd1243dSDimitry Andric bool Rem(InterpState &S, CodePtr OpPC) {
365bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
366bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
367bdd1243dSDimitry Andric 
368bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
369bdd1243dSDimitry Andric     return false;
370bdd1243dSDimitry Andric 
371bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
372bdd1243dSDimitry Andric   T Result;
373bdd1243dSDimitry Andric   if (!T::rem(LHS, RHS, Bits, &Result)) {
374bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
375bdd1243dSDimitry Andric     return true;
376bdd1243dSDimitry Andric   }
377bdd1243dSDimitry Andric   return false;
378bdd1243dSDimitry Andric }
379bdd1243dSDimitry Andric 
380bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
381bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
382bdd1243dSDimitry Andric /// 3) Pushes 'LHS / RHS' on the stack
383bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
384bdd1243dSDimitry Andric bool Div(InterpState &S, CodePtr OpPC) {
385bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
386bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
387bdd1243dSDimitry Andric 
388bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
389bdd1243dSDimitry Andric     return false;
390bdd1243dSDimitry Andric 
391bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
392bdd1243dSDimitry Andric   T Result;
393bdd1243dSDimitry Andric   if (!T::div(LHS, RHS, Bits, &Result)) {
394bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
395bdd1243dSDimitry Andric     return true;
396bdd1243dSDimitry Andric   }
397bdd1243dSDimitry Andric   return false;
398bdd1243dSDimitry Andric }
399bdd1243dSDimitry Andric 
400*06c3fb27SDimitry Andric inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
401*06c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
402*06c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
403*06c3fb27SDimitry Andric 
404*06c3fb27SDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
405*06c3fb27SDimitry Andric     return false;
406*06c3fb27SDimitry Andric 
407*06c3fb27SDimitry Andric   Floating Result;
408*06c3fb27SDimitry Andric   auto Status = Floating::div(LHS, RHS, RM, &Result);
409*06c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
410*06c3fb27SDimitry Andric   return CheckFloatResult(S, OpPC, Status);
411*06c3fb27SDimitry Andric }
412*06c3fb27SDimitry Andric 
413bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
414bdd1243dSDimitry Andric // Inv
415bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
416bdd1243dSDimitry Andric 
417bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
418bdd1243dSDimitry Andric bool Inv(InterpState &S, CodePtr OpPC) {
419bdd1243dSDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
420bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
421bdd1243dSDimitry Andric   const unsigned Bits = Val.bitWidth();
422bdd1243dSDimitry Andric   Boolean R;
423bdd1243dSDimitry Andric   Boolean::inv(BoolT::from(Val, Bits), &R);
424bdd1243dSDimitry Andric 
425bdd1243dSDimitry Andric   S.Stk.push<BoolT>(R);
426bdd1243dSDimitry Andric   return true;
427bdd1243dSDimitry Andric }
428bdd1243dSDimitry Andric 
429bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
430bdd1243dSDimitry Andric // Neg
431bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
432bdd1243dSDimitry Andric 
433bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
434bdd1243dSDimitry Andric bool Neg(InterpState &S, CodePtr OpPC) {
435*06c3fb27SDimitry Andric   const T &Value = S.Stk.pop<T>();
436bdd1243dSDimitry Andric   T Result;
437bdd1243dSDimitry Andric 
438*06c3fb27SDimitry Andric   if (!T::neg(Value, &Result)) {
439bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
440bdd1243dSDimitry Andric     return true;
441bdd1243dSDimitry Andric   }
442bdd1243dSDimitry Andric 
443*06c3fb27SDimitry Andric   assert(isIntegralType(Name) &&
444*06c3fb27SDimitry Andric          "don't expect other types to fail at constexpr negation");
445*06c3fb27SDimitry Andric   S.Stk.push<T>(Result);
446*06c3fb27SDimitry Andric 
447*06c3fb27SDimitry Andric   APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
448*06c3fb27SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
449*06c3fb27SDimitry Andric   QualType Type = E->getType();
450*06c3fb27SDimitry Andric 
451*06c3fb27SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
452*06c3fb27SDimitry Andric     SmallString<32> Trunc;
453*06c3fb27SDimitry Andric     NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
454*06c3fb27SDimitry Andric     auto Loc = E->getExprLoc();
455*06c3fb27SDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
456*06c3fb27SDimitry Andric     return true;
457*06c3fb27SDimitry Andric   }
458*06c3fb27SDimitry Andric 
459*06c3fb27SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
460*06c3fb27SDimitry Andric   return S.noteUndefinedBehavior();
461*06c3fb27SDimitry Andric }
462*06c3fb27SDimitry Andric 
463bdd1243dSDimitry Andric enum class PushVal : bool {
464bdd1243dSDimitry Andric   No,
465bdd1243dSDimitry Andric   Yes,
466bdd1243dSDimitry Andric };
467bdd1243dSDimitry Andric enum class IncDecOp {
468bdd1243dSDimitry Andric   Inc,
469bdd1243dSDimitry Andric   Dec,
470bdd1243dSDimitry Andric };
471bdd1243dSDimitry Andric 
472bdd1243dSDimitry Andric template <typename T, IncDecOp Op, PushVal DoPush>
473bdd1243dSDimitry Andric bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
474bdd1243dSDimitry Andric   T Value = Ptr.deref<T>();
475bdd1243dSDimitry Andric   T Result;
476bdd1243dSDimitry Andric 
477bdd1243dSDimitry Andric   if constexpr (DoPush == PushVal::Yes)
478*06c3fb27SDimitry Andric     S.Stk.push<T>(Value);
479bdd1243dSDimitry Andric 
480bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc) {
481bdd1243dSDimitry Andric     if (!T::increment(Value, &Result)) {
482bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
483bdd1243dSDimitry Andric       return true;
484bdd1243dSDimitry Andric     }
485bdd1243dSDimitry Andric   } else {
486bdd1243dSDimitry Andric     if (!T::decrement(Value, &Result)) {
487bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
488bdd1243dSDimitry Andric       return true;
489bdd1243dSDimitry Andric     }
490bdd1243dSDimitry Andric   }
491bdd1243dSDimitry Andric 
492bdd1243dSDimitry Andric   // Something went wrong with the previous operation. Compute the
493bdd1243dSDimitry Andric   // result with another bit of precision.
494bdd1243dSDimitry Andric   unsigned Bits = Value.bitWidth() + 1;
495bdd1243dSDimitry Andric   APSInt APResult;
496bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc)
497bdd1243dSDimitry Andric     APResult = ++Value.toAPSInt(Bits);
498bdd1243dSDimitry Andric   else
499bdd1243dSDimitry Andric     APResult = --Value.toAPSInt(Bits);
500bdd1243dSDimitry Andric 
501bdd1243dSDimitry Andric   // Report undefined behaviour, stopping if required.
502bdd1243dSDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
503bdd1243dSDimitry Andric   QualType Type = E->getType();
504bdd1243dSDimitry Andric   if (S.checkingForUndefinedBehavior()) {
505bdd1243dSDimitry Andric     SmallString<32> Trunc;
506bdd1243dSDimitry Andric     APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
507bdd1243dSDimitry Andric     auto Loc = E->getExprLoc();
508bdd1243dSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
509bdd1243dSDimitry Andric     return true;
510bdd1243dSDimitry Andric   }
511bdd1243dSDimitry Andric 
512bdd1243dSDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
513bdd1243dSDimitry Andric   return S.noteUndefinedBehavior();
514bdd1243dSDimitry Andric }
515bdd1243dSDimitry Andric 
516bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
517bdd1243dSDimitry Andric /// 2) Load the value from the pointer
518bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
519bdd1243dSDimitry Andric /// 4) Pushes the original (pre-inc) value on the stack.
520bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
521bdd1243dSDimitry Andric bool Inc(InterpState &S, CodePtr OpPC) {
522bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
523bdd1243dSDimitry Andric 
524*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
525*06c3fb27SDimitry Andric     return false;
526*06c3fb27SDimitry Andric 
527bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
528bdd1243dSDimitry Andric }
529bdd1243dSDimitry Andric 
530bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
531bdd1243dSDimitry Andric /// 2) Load the value from the pointer
532bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
533bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
534bdd1243dSDimitry Andric bool IncPop(InterpState &S, CodePtr OpPC) {
535bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
536bdd1243dSDimitry Andric 
537*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
538*06c3fb27SDimitry Andric     return false;
539*06c3fb27SDimitry Andric 
540bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
541bdd1243dSDimitry Andric }
542bdd1243dSDimitry Andric 
543bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
544bdd1243dSDimitry Andric /// 2) Load the value from the pointer
545bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
546bdd1243dSDimitry Andric /// 4) Pushes the original (pre-dec) value on the stack.
547bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
548bdd1243dSDimitry Andric bool Dec(InterpState &S, CodePtr OpPC) {
549bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
550bdd1243dSDimitry Andric 
551*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
552*06c3fb27SDimitry Andric     return false;
553*06c3fb27SDimitry Andric 
554bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
555bdd1243dSDimitry Andric }
556bdd1243dSDimitry Andric 
557bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
558bdd1243dSDimitry Andric /// 2) Load the value from the pointer
559bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
560bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
561bdd1243dSDimitry Andric bool DecPop(InterpState &S, CodePtr OpPC) {
562bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
563bdd1243dSDimitry Andric 
564*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
565*06c3fb27SDimitry Andric     return false;
566*06c3fb27SDimitry Andric 
567bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
568bdd1243dSDimitry Andric }
569bdd1243dSDimitry Andric 
570*06c3fb27SDimitry Andric template <IncDecOp Op, PushVal DoPush>
571*06c3fb27SDimitry Andric bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
572*06c3fb27SDimitry Andric                        llvm::RoundingMode RM) {
573*06c3fb27SDimitry Andric   Floating Value = Ptr.deref<Floating>();
574*06c3fb27SDimitry Andric   Floating Result;
575*06c3fb27SDimitry Andric 
576*06c3fb27SDimitry Andric   if constexpr (DoPush == PushVal::Yes)
577*06c3fb27SDimitry Andric     S.Stk.push<Floating>(Value);
578*06c3fb27SDimitry Andric 
579*06c3fb27SDimitry Andric   llvm::APFloat::opStatus Status;
580*06c3fb27SDimitry Andric   if constexpr (Op == IncDecOp::Inc)
581*06c3fb27SDimitry Andric     Status = Floating::increment(Value, RM, &Result);
582*06c3fb27SDimitry Andric   else
583*06c3fb27SDimitry Andric     Status = Floating::decrement(Value, RM, &Result);
584*06c3fb27SDimitry Andric 
585*06c3fb27SDimitry Andric   Ptr.deref<Floating>() = Result;
586*06c3fb27SDimitry Andric 
587*06c3fb27SDimitry Andric   return CheckFloatResult(S, OpPC, Status);
588*06c3fb27SDimitry Andric }
589*06c3fb27SDimitry Andric 
590*06c3fb27SDimitry Andric inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
591*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
592*06c3fb27SDimitry Andric 
593*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
594*06c3fb27SDimitry Andric     return false;
595*06c3fb27SDimitry Andric 
596*06c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
597*06c3fb27SDimitry Andric }
598*06c3fb27SDimitry Andric 
599*06c3fb27SDimitry Andric inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
600*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
601*06c3fb27SDimitry Andric 
602*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
603*06c3fb27SDimitry Andric     return false;
604*06c3fb27SDimitry Andric 
605*06c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
606*06c3fb27SDimitry Andric }
607*06c3fb27SDimitry Andric 
608*06c3fb27SDimitry Andric inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
609*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
610*06c3fb27SDimitry Andric 
611*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
612*06c3fb27SDimitry Andric     return false;
613*06c3fb27SDimitry Andric 
614*06c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
615*06c3fb27SDimitry Andric }
616*06c3fb27SDimitry Andric 
617*06c3fb27SDimitry Andric inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
618*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
619*06c3fb27SDimitry Andric 
620*06c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
621*06c3fb27SDimitry Andric     return false;
622*06c3fb27SDimitry Andric 
623*06c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
624*06c3fb27SDimitry Andric }
625*06c3fb27SDimitry Andric 
626bdd1243dSDimitry Andric /// 1) Pops the value from the stack.
627bdd1243dSDimitry Andric /// 2) Pushes the bitwise complemented value on the stack (~V).
628bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
629bdd1243dSDimitry Andric bool Comp(InterpState &S, CodePtr OpPC) {
630bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
631bdd1243dSDimitry Andric   T Result;
632bdd1243dSDimitry Andric   if (!T::comp(Val, &Result)) {
633bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
634bdd1243dSDimitry Andric     return true;
635bdd1243dSDimitry Andric   }
636bdd1243dSDimitry Andric 
637bdd1243dSDimitry Andric   return false;
638bdd1243dSDimitry Andric }
639bdd1243dSDimitry Andric 
640a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
641a7dea167SDimitry Andric // EQ, NE, GT, GE, LT, LE
642a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
643a7dea167SDimitry Andric 
644a7dea167SDimitry Andric using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
645a7dea167SDimitry Andric 
646a7dea167SDimitry Andric template <typename T>
647a7dea167SDimitry Andric bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
648a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
649a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
650a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
651a7dea167SDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
652a7dea167SDimitry Andric   return true;
653a7dea167SDimitry Andric }
654a7dea167SDimitry Andric 
655a7dea167SDimitry Andric template <typename T>
656a7dea167SDimitry Andric bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
657a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, Fn);
658a7dea167SDimitry Andric }
659a7dea167SDimitry Andric 
660*06c3fb27SDimitry Andric /// Function pointers cannot be compared in an ordered way.
661*06c3fb27SDimitry Andric template <>
662*06c3fb27SDimitry Andric inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
663*06c3fb27SDimitry Andric                                        CompareFn Fn) {
664*06c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
665*06c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
666*06c3fb27SDimitry Andric 
667*06c3fb27SDimitry Andric   const SourceInfo &Loc = S.Current->getSource(OpPC);
668*06c3fb27SDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
669*06c3fb27SDimitry Andric       << LHS.toDiagnosticString(S.getCtx())
670*06c3fb27SDimitry Andric       << RHS.toDiagnosticString(S.getCtx());
671*06c3fb27SDimitry Andric   return false;
672*06c3fb27SDimitry Andric }
673*06c3fb27SDimitry Andric 
674*06c3fb27SDimitry Andric template <>
675*06c3fb27SDimitry Andric inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
676*06c3fb27SDimitry Andric                                          CompareFn Fn) {
677*06c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
678*06c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
679*06c3fb27SDimitry Andric   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
680*06c3fb27SDimitry Andric   return true;
681*06c3fb27SDimitry Andric }
682*06c3fb27SDimitry Andric 
683a7dea167SDimitry Andric template <>
684a7dea167SDimitry Andric inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
685a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
686a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
687a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
688a7dea167SDimitry Andric 
689a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
690a7dea167SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
691a7dea167SDimitry Andric     S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
692a7dea167SDimitry Andric     return false;
693a7dea167SDimitry Andric   } else {
694a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
695a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
696a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
697a7dea167SDimitry Andric     return true;
698a7dea167SDimitry Andric   }
699a7dea167SDimitry Andric }
700a7dea167SDimitry Andric 
701a7dea167SDimitry Andric template <>
702a7dea167SDimitry Andric inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
703a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
704a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
705a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
706a7dea167SDimitry Andric 
707480093f4SDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
708a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
709a7dea167SDimitry Andric     return true;
710a7dea167SDimitry Andric   }
711a7dea167SDimitry Andric 
712a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
713a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
714a7dea167SDimitry Andric     return true;
715a7dea167SDimitry Andric   } else {
716a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
717a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
718bdd1243dSDimitry Andric 
719bdd1243dSDimitry Andric     // In our Pointer class, a pointer to an array and a pointer to the first
720bdd1243dSDimitry Andric     // element in the same array are NOT equal. They have the same Base value,
721bdd1243dSDimitry Andric     // but a different Offset. This is a pretty rare case, so we fix this here
722bdd1243dSDimitry Andric     // by comparing pointers to the first elements.
723bdd1243dSDimitry Andric     if (LHS.inArray() && LHS.isRoot())
724bdd1243dSDimitry Andric       VL = LHS.atIndex(0).getByteOffset();
725bdd1243dSDimitry Andric     if (RHS.inArray() && RHS.isRoot())
726bdd1243dSDimitry Andric       VR = RHS.atIndex(0).getByteOffset();
727bdd1243dSDimitry Andric 
728a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
729a7dea167SDimitry Andric     return true;
730a7dea167SDimitry Andric   }
731a7dea167SDimitry Andric }
732a7dea167SDimitry Andric 
733a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
734a7dea167SDimitry Andric bool EQ(InterpState &S, CodePtr OpPC) {
735a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
736a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Equal;
737a7dea167SDimitry Andric   });
738a7dea167SDimitry Andric }
739a7dea167SDimitry Andric 
740a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
741a7dea167SDimitry Andric bool NE(InterpState &S, CodePtr OpPC) {
742a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
743a7dea167SDimitry Andric     return R != ComparisonCategoryResult::Equal;
744a7dea167SDimitry Andric   });
745a7dea167SDimitry Andric }
746a7dea167SDimitry Andric 
747a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
748a7dea167SDimitry Andric bool LT(InterpState &S, CodePtr OpPC) {
749a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
750a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less;
751a7dea167SDimitry Andric   });
752a7dea167SDimitry Andric }
753a7dea167SDimitry Andric 
754a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
755a7dea167SDimitry Andric bool LE(InterpState &S, CodePtr OpPC) {
756a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
757a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less ||
758a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
759a7dea167SDimitry Andric   });
760a7dea167SDimitry Andric }
761a7dea167SDimitry Andric 
762a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
763a7dea167SDimitry Andric bool GT(InterpState &S, CodePtr OpPC) {
764a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
765a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater;
766a7dea167SDimitry Andric   });
767a7dea167SDimitry Andric }
768a7dea167SDimitry Andric 
769a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
770a7dea167SDimitry Andric bool GE(InterpState &S, CodePtr OpPC) {
771a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
772a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater ||
773a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
774a7dea167SDimitry Andric   });
775a7dea167SDimitry Andric }
776a7dea167SDimitry Andric 
777a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
778a7dea167SDimitry Andric // InRange
779a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
780a7dea167SDimitry Andric 
781a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
782a7dea167SDimitry Andric bool InRange(InterpState &S, CodePtr OpPC) {
783a7dea167SDimitry Andric   const T RHS = S.Stk.pop<T>();
784a7dea167SDimitry Andric   const T LHS = S.Stk.pop<T>();
785a7dea167SDimitry Andric   const T Value = S.Stk.pop<T>();
786a7dea167SDimitry Andric 
787a7dea167SDimitry Andric   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
788a7dea167SDimitry Andric   return true;
789a7dea167SDimitry Andric }
790a7dea167SDimitry Andric 
791a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
792a7dea167SDimitry Andric // Dup, Pop, Test
793a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
794a7dea167SDimitry Andric 
795a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
796a7dea167SDimitry Andric bool Dup(InterpState &S, CodePtr OpPC) {
797a7dea167SDimitry Andric   S.Stk.push<T>(S.Stk.peek<T>());
798a7dea167SDimitry Andric   return true;
799a7dea167SDimitry Andric }
800a7dea167SDimitry Andric 
801a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
802a7dea167SDimitry Andric bool Pop(InterpState &S, CodePtr OpPC) {
803a7dea167SDimitry Andric   S.Stk.pop<T>();
804a7dea167SDimitry Andric   return true;
805a7dea167SDimitry Andric }
806a7dea167SDimitry Andric 
807a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
808a7dea167SDimitry Andric // Const
809a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
810a7dea167SDimitry Andric 
811a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
812a7dea167SDimitry Andric bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
813a7dea167SDimitry Andric   S.Stk.push<T>(Arg);
814a7dea167SDimitry Andric   return true;
815a7dea167SDimitry Andric }
816a7dea167SDimitry Andric 
817a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
818a7dea167SDimitry Andric // Get/Set Local/Param/Global/This
819a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
820a7dea167SDimitry Andric 
821a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
822a7dea167SDimitry Andric bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
823bdd1243dSDimitry Andric   const Pointer &Ptr = S.Current->getLocalPointer(I);
824bdd1243dSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
825bdd1243dSDimitry Andric     return false;
826bdd1243dSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
827a7dea167SDimitry Andric   return true;
828a7dea167SDimitry Andric }
829a7dea167SDimitry Andric 
830*06c3fb27SDimitry Andric /// 1) Pops the value from the stack.
831*06c3fb27SDimitry Andric /// 2) Writes the value to the local variable with the
832*06c3fb27SDimitry Andric ///    given offset.
833a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
834a7dea167SDimitry Andric bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
835a7dea167SDimitry Andric   S.Current->setLocal<T>(I, S.Stk.pop<T>());
836a7dea167SDimitry Andric   return true;
837a7dea167SDimitry Andric }
838a7dea167SDimitry Andric 
839a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
840a7dea167SDimitry Andric bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
841a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
842a7dea167SDimitry Andric     return false;
843a7dea167SDimitry Andric   }
844a7dea167SDimitry Andric   S.Stk.push<T>(S.Current->getParam<T>(I));
845a7dea167SDimitry Andric   return true;
846a7dea167SDimitry Andric }
847a7dea167SDimitry Andric 
848a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
849a7dea167SDimitry Andric bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
850a7dea167SDimitry Andric   S.Current->setParam<T>(I, S.Stk.pop<T>());
851a7dea167SDimitry Andric   return true;
852a7dea167SDimitry Andric }
853a7dea167SDimitry Andric 
854bdd1243dSDimitry Andric /// 1) Peeks a pointer on the stack
855bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
856a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
857a7dea167SDimitry Andric bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
858a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
859a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
860a7dea167SDimitry Andric       return false;
861a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
862a7dea167SDimitry Andric     return false;
863a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
864a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
865a7dea167SDimitry Andric     return false;
866a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
867a7dea167SDimitry Andric   return true;
868a7dea167SDimitry Andric }
869a7dea167SDimitry Andric 
870a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
871a7dea167SDimitry Andric bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
872a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
873a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
874a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
875a7dea167SDimitry Andric     return false;
876a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
877a7dea167SDimitry Andric     return false;
878a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
879a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
880a7dea167SDimitry Andric     return false;
881*06c3fb27SDimitry Andric   Field.initialize();
882a7dea167SDimitry Andric   Field.deref<T>() = Value;
883a7dea167SDimitry Andric   return true;
884a7dea167SDimitry Andric }
885a7dea167SDimitry Andric 
886bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
887bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
888a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
889a7dea167SDimitry Andric bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
890a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.pop<Pointer>();
891a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
892a7dea167SDimitry Andric     return false;
893a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
894a7dea167SDimitry Andric     return false;
895a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
896a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
897a7dea167SDimitry Andric     return false;
898a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
899a7dea167SDimitry Andric   return true;
900a7dea167SDimitry Andric }
901a7dea167SDimitry Andric 
902a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
903a7dea167SDimitry Andric bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
904a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
905a7dea167SDimitry Andric     return false;
906a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
907a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
908a7dea167SDimitry Andric     return false;
909a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
910a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
911a7dea167SDimitry Andric     return false;
912a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
913a7dea167SDimitry Andric   return true;
914a7dea167SDimitry Andric }
915a7dea167SDimitry Andric 
916a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
917a7dea167SDimitry Andric bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
918a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
919a7dea167SDimitry Andric     return false;
920a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
921a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
922a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
923a7dea167SDimitry Andric     return false;
924a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
925a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
926a7dea167SDimitry Andric     return false;
927a7dea167SDimitry Andric   Field.deref<T>() = Value;
928a7dea167SDimitry Andric   return true;
929a7dea167SDimitry Andric }
930a7dea167SDimitry Andric 
931a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
932a7dea167SDimitry Andric bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
933a7dea167SDimitry Andric   auto *B = S.P.getGlobal(I);
934a7dea167SDimitry Andric   if (B->isExtern())
935a7dea167SDimitry Andric     return false;
936a7dea167SDimitry Andric   S.Stk.push<T>(B->deref<T>());
937a7dea167SDimitry Andric   return true;
938a7dea167SDimitry Andric }
939a7dea167SDimitry Andric 
940a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
941a7dea167SDimitry Andric bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
942a7dea167SDimitry Andric   // TODO: emit warning.
943a7dea167SDimitry Andric   return false;
944a7dea167SDimitry Andric }
945a7dea167SDimitry Andric 
946a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
947a7dea167SDimitry Andric bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
948a7dea167SDimitry Andric   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
949a7dea167SDimitry Andric   return true;
950a7dea167SDimitry Andric }
951a7dea167SDimitry Andric 
952*06c3fb27SDimitry Andric /// 1) Converts the value on top of the stack to an APValue
953*06c3fb27SDimitry Andric /// 2) Sets that APValue on \Temp
954*06c3fb27SDimitry Andric /// 3) Initialized global with index \I with that
955*06c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
956*06c3fb27SDimitry Andric bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
957*06c3fb27SDimitry Andric                     const LifetimeExtendedTemporaryDecl *Temp) {
958*06c3fb27SDimitry Andric   assert(Temp);
959*06c3fb27SDimitry Andric   const T Value = S.Stk.peek<T>();
960*06c3fb27SDimitry Andric   APValue APV = Value.toAPValue();
961*06c3fb27SDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
962*06c3fb27SDimitry Andric   *Cached = APV;
963*06c3fb27SDimitry Andric 
964*06c3fb27SDimitry Andric   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
965*06c3fb27SDimitry Andric   return true;
966*06c3fb27SDimitry Andric }
967*06c3fb27SDimitry Andric 
968a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
969a7dea167SDimitry Andric bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
970a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
971a7dea167SDimitry Andric     return false;
972a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
973a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
974a7dea167SDimitry Andric     return false;
975a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
976a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
977a7dea167SDimitry Andric   Field.initialize();
978a7dea167SDimitry Andric   return true;
979a7dea167SDimitry Andric }
980a7dea167SDimitry Andric 
981a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
982a7dea167SDimitry Andric bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
983a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
984a7dea167SDimitry Andric     return false;
985a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
986a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
987a7dea167SDimitry Andric     return false;
988a7dea167SDimitry Andric   const Pointer &Field = This.atField(F->Offset);
989a7dea167SDimitry Andric   const auto &Value = S.Stk.pop<T>();
990a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
991a7dea167SDimitry Andric   Field.initialize();
992a7dea167SDimitry Andric   return true;
993a7dea167SDimitry Andric }
994a7dea167SDimitry Andric 
995a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
996a7dea167SDimitry Andric bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
997a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
998a7dea167SDimitry Andric     return false;
999a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1000a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1001a7dea167SDimitry Andric     return false;
1002a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1003a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1004a7dea167SDimitry Andric   Field.activate();
1005a7dea167SDimitry Andric   Field.initialize();
1006a7dea167SDimitry Andric   return true;
1007a7dea167SDimitry Andric }
1008a7dea167SDimitry Andric 
1009bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1010bdd1243dSDimitry Andric /// 2) Peeks a pointer from the stack
1011bdd1243dSDimitry Andric /// 3) Pushes the value to field I of the pointer on the stack
1012a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1013a7dea167SDimitry Andric bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1014a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1015bdd1243dSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1016a7dea167SDimitry Andric   Field.deref<T>() = Value;
1017a7dea167SDimitry Andric   Field.activate();
1018a7dea167SDimitry Andric   Field.initialize();
1019a7dea167SDimitry Andric   return true;
1020a7dea167SDimitry Andric }
1021a7dea167SDimitry Andric 
1022a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1023a7dea167SDimitry Andric bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1024a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1025a7dea167SDimitry Andric   const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
1026a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1027a7dea167SDimitry Andric   Field.activate();
1028a7dea167SDimitry Andric   Field.initialize();
1029a7dea167SDimitry Andric   return true;
1030a7dea167SDimitry Andric }
1031a7dea167SDimitry Andric 
1032a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1033a7dea167SDimitry Andric bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1034a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1035a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1036a7dea167SDimitry Andric   const Pointer &Field = Ptr.atField(I);
1037a7dea167SDimitry Andric   Field.deref<T>() = Value;
1038a7dea167SDimitry Andric   Field.activate();
1039a7dea167SDimitry Andric   Field.initialize();
1040a7dea167SDimitry Andric   return true;
1041a7dea167SDimitry Andric }
1042a7dea167SDimitry Andric 
1043a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1044a7dea167SDimitry Andric // GetPtr Local/Param/Global/Field/This
1045a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1046a7dea167SDimitry Andric 
1047a7dea167SDimitry Andric inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1048a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1049a7dea167SDimitry Andric   return true;
1050a7dea167SDimitry Andric }
1051a7dea167SDimitry Andric 
1052a7dea167SDimitry Andric inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1053a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1054a7dea167SDimitry Andric     return false;
1055a7dea167SDimitry Andric   }
1056a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1057a7dea167SDimitry Andric   return true;
1058a7dea167SDimitry Andric }
1059a7dea167SDimitry Andric 
1060a7dea167SDimitry Andric inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1061a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1062a7dea167SDimitry Andric   return true;
1063a7dea167SDimitry Andric }
1064a7dea167SDimitry Andric 
1065bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack
1066bdd1243dSDimitry Andric /// 2) Pushes Pointer.atField(Off) on the stack
1067a7dea167SDimitry Andric inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1068a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1069a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1070a7dea167SDimitry Andric     return false;
1071a7dea167SDimitry Andric   if (!CheckExtern(S, OpPC, Ptr))
1072a7dea167SDimitry Andric     return false;
1073a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1074a7dea167SDimitry Andric     return false;
1075a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1076a7dea167SDimitry Andric   return true;
1077a7dea167SDimitry Andric }
1078a7dea167SDimitry Andric 
1079a7dea167SDimitry Andric inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1080a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1081a7dea167SDimitry Andric     return false;
1082a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1083a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1084a7dea167SDimitry Andric     return false;
1085a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1086a7dea167SDimitry Andric   return true;
1087a7dea167SDimitry Andric }
1088a7dea167SDimitry Andric 
1089a7dea167SDimitry Andric inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1090a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1091a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1092a7dea167SDimitry Andric     return false;
1093a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1094a7dea167SDimitry Andric     return false;
1095a7dea167SDimitry Andric   Pointer Field = Ptr.atField(Off);
1096a7dea167SDimitry Andric   Ptr.deactivate();
1097a7dea167SDimitry Andric   Field.activate();
1098a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1099a7dea167SDimitry Andric   return true;
1100a7dea167SDimitry Andric }
1101a7dea167SDimitry Andric 
1102a7dea167SDimitry Andric inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1103a7dea167SDimitry Andric  if (S.checkingPotentialConstantExpression())
1104a7dea167SDimitry Andric     return false;
1105a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1106a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1107a7dea167SDimitry Andric     return false;
1108a7dea167SDimitry Andric   Pointer Field = This.atField(Off);
1109a7dea167SDimitry Andric   This.deactivate();
1110a7dea167SDimitry Andric   Field.activate();
1111a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1112a7dea167SDimitry Andric   return true;
1113a7dea167SDimitry Andric }
1114a7dea167SDimitry Andric 
1115a7dea167SDimitry Andric inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1116*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1117*06c3fb27SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1118*06c3fb27SDimitry Andric     return false;
1119*06c3fb27SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1120*06c3fb27SDimitry Andric   return true;
1121*06c3fb27SDimitry Andric }
1122*06c3fb27SDimitry Andric 
1123*06c3fb27SDimitry Andric inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1124a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1125a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1126a7dea167SDimitry Andric     return false;
1127a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1128a7dea167SDimitry Andric   return true;
1129a7dea167SDimitry Andric }
1130a7dea167SDimitry Andric 
1131a7dea167SDimitry Andric inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1132a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1133a7dea167SDimitry Andric     return false;
1134a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1135a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1136a7dea167SDimitry Andric     return false;
1137a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1138a7dea167SDimitry Andric   return true;
1139a7dea167SDimitry Andric }
1140a7dea167SDimitry Andric 
1141a7dea167SDimitry Andric inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1142a7dea167SDimitry Andric                            const Pointer &Ptr) {
1143a7dea167SDimitry Andric   Pointer Base = Ptr;
1144a7dea167SDimitry Andric   while (Base.isBaseClass())
1145a7dea167SDimitry Andric     Base = Base.getBase();
1146a7dea167SDimitry Andric 
1147a7dea167SDimitry Andric   auto *Field = Base.getRecord()->getVirtualBase(Decl);
1148a7dea167SDimitry Andric   S.Stk.push<Pointer>(Base.atField(Field->Offset));
1149a7dea167SDimitry Andric   return true;
1150a7dea167SDimitry Andric }
1151a7dea167SDimitry Andric 
1152a7dea167SDimitry Andric inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1153a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1154a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1155a7dea167SDimitry Andric     return false;
1156a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, Ptr);
1157a7dea167SDimitry Andric }
1158a7dea167SDimitry Andric 
1159a7dea167SDimitry Andric inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1160a7dea167SDimitry Andric                                const RecordDecl *D) {
1161a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1162a7dea167SDimitry Andric     return false;
1163a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1164a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1165a7dea167SDimitry Andric     return false;
1166a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1167a7dea167SDimitry Andric }
1168a7dea167SDimitry Andric 
1169a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1170a7dea167SDimitry Andric // Load, Store, Init
1171a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1172a7dea167SDimitry Andric 
1173a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1174a7dea167SDimitry Andric bool Load(InterpState &S, CodePtr OpPC) {
1175a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1176a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1177a7dea167SDimitry Andric     return false;
1178a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1179a7dea167SDimitry Andric   return true;
1180a7dea167SDimitry Andric }
1181a7dea167SDimitry Andric 
1182a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1183a7dea167SDimitry Andric bool LoadPop(InterpState &S, CodePtr OpPC) {
1184a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1185a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1186a7dea167SDimitry Andric     return false;
1187a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1188a7dea167SDimitry Andric   return true;
1189a7dea167SDimitry Andric }
1190a7dea167SDimitry Andric 
1191a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1192a7dea167SDimitry Andric bool Store(InterpState &S, CodePtr OpPC) {
1193a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1194a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1195a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1196a7dea167SDimitry Andric     return false;
1197bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1198bdd1243dSDimitry Andric     Ptr.initialize();
1199a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1200a7dea167SDimitry Andric   return true;
1201a7dea167SDimitry Andric }
1202a7dea167SDimitry Andric 
1203a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1204a7dea167SDimitry Andric bool StorePop(InterpState &S, CodePtr OpPC) {
1205a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1206a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1207a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1208a7dea167SDimitry Andric     return false;
1209bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1210bdd1243dSDimitry Andric     Ptr.initialize();
1211a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1212a7dea167SDimitry Andric   return true;
1213a7dea167SDimitry Andric }
1214a7dea167SDimitry Andric 
1215a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1216a7dea167SDimitry Andric bool StoreBitField(InterpState &S, CodePtr OpPC) {
1217a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1218a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1219a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1220a7dea167SDimitry Andric     return false;
1221bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1222bdd1243dSDimitry Andric     Ptr.initialize();
1223a7dea167SDimitry Andric   if (auto *FD = Ptr.getField()) {
1224a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1225a7dea167SDimitry Andric   } else {
1226a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1227a7dea167SDimitry Andric   }
1228a7dea167SDimitry Andric   return true;
1229a7dea167SDimitry Andric }
1230a7dea167SDimitry Andric 
1231a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1232a7dea167SDimitry Andric bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1233a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1234a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1235a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1236a7dea167SDimitry Andric     return false;
1237bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1238bdd1243dSDimitry Andric     Ptr.initialize();
1239a7dea167SDimitry Andric   if (auto *FD = Ptr.getField()) {
1240a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1241a7dea167SDimitry Andric   } else {
1242a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1243a7dea167SDimitry Andric   }
1244a7dea167SDimitry Andric   return true;
1245a7dea167SDimitry Andric }
1246a7dea167SDimitry Andric 
1247a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1248a7dea167SDimitry Andric bool InitPop(InterpState &S, CodePtr OpPC) {
1249a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1250a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1251a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1252a7dea167SDimitry Andric     return false;
1253a7dea167SDimitry Andric   Ptr.initialize();
1254a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1255a7dea167SDimitry Andric   return true;
1256a7dea167SDimitry Andric }
1257a7dea167SDimitry Andric 
1258bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1259bdd1243dSDimitry Andric /// 2) Peeks a pointer and gets its index \Idx
1260bdd1243dSDimitry Andric /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1261a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1262a7dea167SDimitry Andric bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1263a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1264a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1265a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1266a7dea167SDimitry Andric     return false;
1267a7dea167SDimitry Andric   Ptr.initialize();
1268a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1269a7dea167SDimitry Andric   return true;
1270a7dea167SDimitry Andric }
1271a7dea167SDimitry Andric 
1272bdd1243dSDimitry Andric /// The same as InitElem, but pops the pointer as well.
1273a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1274a7dea167SDimitry Andric bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1275a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1276a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1277a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1278a7dea167SDimitry Andric     return false;
1279a7dea167SDimitry Andric   Ptr.initialize();
1280a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1281a7dea167SDimitry Andric   return true;
1282a7dea167SDimitry Andric }
1283a7dea167SDimitry Andric 
1284a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1285a7dea167SDimitry Andric // AddOffset, SubOffset
1286a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1287a7dea167SDimitry Andric 
1288*06c3fb27SDimitry Andric template <class T, ArithOp Op>
1289*06c3fb27SDimitry Andric bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
1290*06c3fb27SDimitry Andric                   const Pointer &Ptr) {
1291a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1292a7dea167SDimitry Andric     return false;
1293a7dea167SDimitry Andric 
1294bdd1243dSDimitry Andric   // A zero offset does not change the pointer.
1295a7dea167SDimitry Andric   if (Offset.isZero()) {
1296bdd1243dSDimitry Andric     S.Stk.push<Pointer>(Ptr);
1297a7dea167SDimitry Andric     return true;
1298a7dea167SDimitry Andric   }
1299bdd1243dSDimitry Andric 
1300bdd1243dSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1301bdd1243dSDimitry Andric     return false;
1302bdd1243dSDimitry Andric 
1303a7dea167SDimitry Andric   // Arrays of unknown bounds cannot have pointers into them.
1304a7dea167SDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
1305a7dea167SDimitry Andric     return false;
1306a7dea167SDimitry Andric 
1307bdd1243dSDimitry Andric   // Get a version of the index comparable to the type.
1308bdd1243dSDimitry Andric   T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1309a7dea167SDimitry Andric   // Compute the largest index into the array.
1310a7dea167SDimitry Andric   unsigned MaxIndex = Ptr.getNumElems();
1311a7dea167SDimitry Andric 
1312a7dea167SDimitry Andric   // Helper to report an invalid offset, computed as APSInt.
1313a7dea167SDimitry Andric   auto InvalidOffset = [&]() {
1314a7dea167SDimitry Andric     const unsigned Bits = Offset.bitWidth();
1315a7dea167SDimitry Andric     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1316a7dea167SDimitry Andric     APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1317*06c3fb27SDimitry Andric     APSInt NewIndex =
1318*06c3fb27SDimitry Andric         (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1319a7dea167SDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1320a7dea167SDimitry Andric         << NewIndex
1321a7dea167SDimitry Andric         << /*array*/ static_cast<int>(!Ptr.inArray())
1322a7dea167SDimitry Andric         << static_cast<unsigned>(MaxIndex);
1323a7dea167SDimitry Andric     return false;
1324a7dea167SDimitry Andric   };
1325a7dea167SDimitry Andric 
1326bdd1243dSDimitry Andric   unsigned MaxOffset = MaxIndex - Ptr.getIndex();
1327*06c3fb27SDimitry Andric   if constexpr (Op == ArithOp::Add) {
1328a7dea167SDimitry Andric     // If the new offset would be negative, bail out.
1329bdd1243dSDimitry Andric     if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1330a7dea167SDimitry Andric       return InvalidOffset();
1331a7dea167SDimitry Andric 
1332a7dea167SDimitry Andric     // If the new offset would be out of bounds, bail out.
1333bdd1243dSDimitry Andric     if (Offset.isPositive() && Offset > MaxOffset)
1334a7dea167SDimitry Andric       return InvalidOffset();
1335bdd1243dSDimitry Andric   } else {
1336bdd1243dSDimitry Andric     // If the new offset would be negative, bail out.
1337bdd1243dSDimitry Andric     if (Offset.isPositive() && Index < Offset)
1338a7dea167SDimitry Andric       return InvalidOffset();
1339a7dea167SDimitry Andric 
1340bdd1243dSDimitry Andric     // If the new offset would be out of bounds, bail out.
1341bdd1243dSDimitry Andric     if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1342bdd1243dSDimitry Andric       return InvalidOffset();
1343bdd1243dSDimitry Andric   }
1344bdd1243dSDimitry Andric 
1345a7dea167SDimitry Andric   // Offset is valid - compute it on unsigned.
1346a7dea167SDimitry Andric   int64_t WideIndex = static_cast<int64_t>(Index);
1347a7dea167SDimitry Andric   int64_t WideOffset = static_cast<int64_t>(Offset);
1348bdd1243dSDimitry Andric   int64_t Result;
1349*06c3fb27SDimitry Andric   if constexpr (Op == ArithOp::Add)
1350bdd1243dSDimitry Andric     Result = WideIndex + WideOffset;
1351bdd1243dSDimitry Andric   else
1352bdd1243dSDimitry Andric     Result = WideIndex - WideOffset;
1353bdd1243dSDimitry Andric 
1354a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1355a7dea167SDimitry Andric   return true;
1356a7dea167SDimitry Andric }
1357a7dea167SDimitry Andric 
1358a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1359a7dea167SDimitry Andric bool AddOffset(InterpState &S, CodePtr OpPC) {
1360*06c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
1361*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1362*06c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1363a7dea167SDimitry Andric }
1364a7dea167SDimitry Andric 
1365a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1366a7dea167SDimitry Andric bool SubOffset(InterpState &S, CodePtr OpPC) {
1367*06c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
1368*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1369*06c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
1370*06c3fb27SDimitry Andric }
1371*06c3fb27SDimitry Andric 
1372*06c3fb27SDimitry Andric template <ArithOp Op>
1373*06c3fb27SDimitry Andric static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC) {
1374*06c3fb27SDimitry Andric   using OneT = Integral<8, false>;
1375*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1376*06c3fb27SDimitry Andric 
1377*06c3fb27SDimitry Andric   // Get the current value on the stack.
1378*06c3fb27SDimitry Andric   S.Stk.push<Pointer>(Ptr.deref<Pointer>());
1379*06c3fb27SDimitry Andric 
1380*06c3fb27SDimitry Andric   // Now the current Ptr again and a constant 1.
1381*06c3fb27SDimitry Andric   Pointer P = Ptr.deref<Pointer>();
1382*06c3fb27SDimitry Andric   OneT One = OneT::from(1);
1383*06c3fb27SDimitry Andric   if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
1384*06c3fb27SDimitry Andric     return false;
1385*06c3fb27SDimitry Andric 
1386*06c3fb27SDimitry Andric   // Store the new value.
1387*06c3fb27SDimitry Andric   Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
1388*06c3fb27SDimitry Andric   return true;
1389*06c3fb27SDimitry Andric }
1390*06c3fb27SDimitry Andric 
1391*06c3fb27SDimitry Andric static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1392*06c3fb27SDimitry Andric   return IncDecPtrHelper<ArithOp::Add>(S, OpPC);
1393*06c3fb27SDimitry Andric }
1394*06c3fb27SDimitry Andric 
1395*06c3fb27SDimitry Andric static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1396*06c3fb27SDimitry Andric   return IncDecPtrHelper<ArithOp::Sub>(S, OpPC);
1397a7dea167SDimitry Andric }
1398a7dea167SDimitry Andric 
1399bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack.
1400bdd1243dSDimitry Andric /// 2) Pops another Pointer from the stack.
1401bdd1243dSDimitry Andric /// 3) Pushes the different of the indices of the two pointers on the stack.
1402bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1403bdd1243dSDimitry Andric inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1404bdd1243dSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
1405bdd1243dSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
1406bdd1243dSDimitry Andric 
1407bdd1243dSDimitry Andric   if (!Pointer::hasSameArray(LHS, RHS)) {
1408bdd1243dSDimitry Andric     // TODO: Diagnose.
1409bdd1243dSDimitry Andric     return false;
1410bdd1243dSDimitry Andric   }
1411bdd1243dSDimitry Andric 
1412bdd1243dSDimitry Andric   T A = T::from(LHS.getIndex());
1413bdd1243dSDimitry Andric   T B = T::from(RHS.getIndex());
1414bdd1243dSDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1415bdd1243dSDimitry Andric }
1416a7dea167SDimitry Andric 
1417a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1418a7dea167SDimitry Andric // Destroy
1419a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1420a7dea167SDimitry Andric 
1421a7dea167SDimitry Andric inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1422a7dea167SDimitry Andric   S.Current->destroy(I);
1423a7dea167SDimitry Andric   return true;
1424a7dea167SDimitry Andric }
1425a7dea167SDimitry Andric 
1426a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1427a7dea167SDimitry Andric // Cast, CastFP
1428a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1429a7dea167SDimitry Andric 
1430a7dea167SDimitry Andric template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1431a7dea167SDimitry Andric   using T = typename PrimConv<TIn>::T;
1432a7dea167SDimitry Andric   using U = typename PrimConv<TOut>::T;
1433a7dea167SDimitry Andric   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1434a7dea167SDimitry Andric   return true;
1435a7dea167SDimitry Andric }
1436a7dea167SDimitry Andric 
1437*06c3fb27SDimitry Andric /// 1) Pops a Floating from the stack.
1438*06c3fb27SDimitry Andric /// 2) Pushes a new floating on the stack that uses the given semantics.
1439*06c3fb27SDimitry Andric inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
1440*06c3fb27SDimitry Andric             llvm::RoundingMode RM) {
1441*06c3fb27SDimitry Andric   Floating F = S.Stk.pop<Floating>();
1442*06c3fb27SDimitry Andric   Floating Result = F.toSemantics(Sem, RM);
1443*06c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
1444*06c3fb27SDimitry Andric   return true;
1445*06c3fb27SDimitry Andric }
1446*06c3fb27SDimitry Andric 
1447*06c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1448*06c3fb27SDimitry Andric bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
1449*06c3fb27SDimitry Andric                           const llvm::fltSemantics *Sem,
1450*06c3fb27SDimitry Andric                           llvm::RoundingMode RM) {
1451*06c3fb27SDimitry Andric   const T &From = S.Stk.pop<T>();
1452*06c3fb27SDimitry Andric   APSInt FromAP = From.toAPSInt();
1453*06c3fb27SDimitry Andric   Floating Result;
1454*06c3fb27SDimitry Andric 
1455*06c3fb27SDimitry Andric   auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
1456*06c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
1457*06c3fb27SDimitry Andric 
1458*06c3fb27SDimitry Andric   return CheckFloatResult(S, OpPC, Status);
1459*06c3fb27SDimitry Andric }
1460*06c3fb27SDimitry Andric 
1461*06c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1462*06c3fb27SDimitry Andric bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
1463*06c3fb27SDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
1464*06c3fb27SDimitry Andric 
1465*06c3fb27SDimitry Andric   if constexpr (std::is_same_v<T, Boolean>) {
1466*06c3fb27SDimitry Andric     S.Stk.push<T>(T(F.isNonZero()));
1467*06c3fb27SDimitry Andric     return true;
1468*06c3fb27SDimitry Andric   } else {
1469*06c3fb27SDimitry Andric     APSInt Result(std::max(8u, T::bitWidth() + 1),
1470*06c3fb27SDimitry Andric                   /*IsUnsigned=*/!T::isSigned());
1471*06c3fb27SDimitry Andric     auto Status = F.convertToInteger(Result);
1472*06c3fb27SDimitry Andric 
1473*06c3fb27SDimitry Andric     // Float-to-Integral overflow check.
1474*06c3fb27SDimitry Andric     if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1475*06c3fb27SDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
1476*06c3fb27SDimitry Andric       QualType Type = E->getType();
1477*06c3fb27SDimitry Andric 
1478*06c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1479*06c3fb27SDimitry Andric       return S.noteUndefinedBehavior();
1480*06c3fb27SDimitry Andric     }
1481*06c3fb27SDimitry Andric 
1482*06c3fb27SDimitry Andric     S.Stk.push<T>(T(Result));
1483*06c3fb27SDimitry Andric     return CheckFloatResult(S, OpPC, Status);
1484*06c3fb27SDimitry Andric   }
1485*06c3fb27SDimitry Andric }
1486*06c3fb27SDimitry Andric 
1487a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1488a7dea167SDimitry Andric // Zero, Nullptr
1489a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1490a7dea167SDimitry Andric 
1491a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1492a7dea167SDimitry Andric bool Zero(InterpState &S, CodePtr OpPC) {
1493a7dea167SDimitry Andric   S.Stk.push<T>(T::zero());
1494a7dea167SDimitry Andric   return true;
1495a7dea167SDimitry Andric }
1496a7dea167SDimitry Andric 
1497a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1498a7dea167SDimitry Andric inline bool Null(InterpState &S, CodePtr OpPC) {
1499a7dea167SDimitry Andric   S.Stk.push<T>();
1500a7dea167SDimitry Andric   return true;
1501a7dea167SDimitry Andric }
1502a7dea167SDimitry Andric 
1503a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1504a7dea167SDimitry Andric // This, ImplicitThis
1505a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1506a7dea167SDimitry Andric 
1507a7dea167SDimitry Andric inline bool This(InterpState &S, CodePtr OpPC) {
1508a7dea167SDimitry Andric   // Cannot read 'this' in this mode.
1509a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1510a7dea167SDimitry Andric     return false;
1511a7dea167SDimitry Andric   }
1512a7dea167SDimitry Andric 
1513a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1514a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1515a7dea167SDimitry Andric     return false;
1516a7dea167SDimitry Andric 
1517a7dea167SDimitry Andric   S.Stk.push<Pointer>(This);
1518a7dea167SDimitry Andric   return true;
1519a7dea167SDimitry Andric }
1520a7dea167SDimitry Andric 
1521bdd1243dSDimitry Andric inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1522bdd1243dSDimitry Andric   assert(S.Current->getFunction()->hasRVO());
1523*06c3fb27SDimitry Andric   if (S.checkingPotentialConstantExpression())
1524*06c3fb27SDimitry Andric     return false;
1525bdd1243dSDimitry Andric   S.Stk.push<Pointer>(S.Current->getRVOPtr());
1526bdd1243dSDimitry Andric   return true;
1527bdd1243dSDimitry Andric }
1528bdd1243dSDimitry Andric 
1529a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1530a7dea167SDimitry Andric // Shr, Shl
1531a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1532a7dea167SDimitry Andric 
1533bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
1534a7dea167SDimitry Andric inline bool Shr(InterpState &S, CodePtr OpPC) {
1535bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
1536bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
1537bdd1243dSDimitry Andric   const auto &RHS = S.Stk.pop<RT>();
1538bdd1243dSDimitry Andric   const auto &LHS = S.Stk.pop<LT>();
1539a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
1540a7dea167SDimitry Andric 
1541*06c3fb27SDimitry Andric   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1542bdd1243dSDimitry Andric     return false;
1543bdd1243dSDimitry Andric 
1544*06c3fb27SDimitry Andric   Integral<LT::bitWidth(), false> R;
1545*06c3fb27SDimitry Andric   Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
1546*06c3fb27SDimitry Andric   S.Stk.push<LT>(R);
1547bdd1243dSDimitry Andric   return true;
1548a7dea167SDimitry Andric }
1549a7dea167SDimitry Andric 
1550bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
1551a7dea167SDimitry Andric inline bool Shl(InterpState &S, CodePtr OpPC) {
1552bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
1553bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
1554bdd1243dSDimitry Andric   const auto &RHS = S.Stk.pop<RT>();
1555bdd1243dSDimitry Andric   const auto &LHS = S.Stk.pop<LT>();
1556a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
1557a7dea167SDimitry Andric 
1558*06c3fb27SDimitry Andric   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1559bdd1243dSDimitry Andric     return false;
1560bdd1243dSDimitry Andric 
1561*06c3fb27SDimitry Andric   Integral<LT::bitWidth(), false> R;
1562*06c3fb27SDimitry Andric   Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
1563*06c3fb27SDimitry Andric   S.Stk.push<LT>(R);
1564bdd1243dSDimitry Andric   return true;
1565a7dea167SDimitry Andric }
1566a7dea167SDimitry Andric 
1567a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1568a7dea167SDimitry Andric // NoRet
1569a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1570a7dea167SDimitry Andric 
1571a7dea167SDimitry Andric inline bool NoRet(InterpState &S, CodePtr OpPC) {
1572a7dea167SDimitry Andric   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1573a7dea167SDimitry Andric   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1574a7dea167SDimitry Andric   return false;
1575a7dea167SDimitry Andric }
1576a7dea167SDimitry Andric 
1577a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1578a7dea167SDimitry Andric // NarrowPtr, ExpandPtr
1579a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1580a7dea167SDimitry Andric 
1581a7dea167SDimitry Andric inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1582a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1583a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.narrow());
1584a7dea167SDimitry Andric   return true;
1585a7dea167SDimitry Andric }
1586a7dea167SDimitry Andric 
1587a7dea167SDimitry Andric inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1588a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1589a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.expand());
1590a7dea167SDimitry Andric   return true;
1591a7dea167SDimitry Andric }
1592a7dea167SDimitry Andric 
1593*06c3fb27SDimitry Andric // 1) Pops an integral value from the stack
1594*06c3fb27SDimitry Andric // 2) Peeks a pointer
1595*06c3fb27SDimitry Andric // 3) Pushes a new pointer that's a narrowed array
1596*06c3fb27SDimitry Andric //   element of the peeked pointer with the value
1597*06c3fb27SDimitry Andric //   from 1) added as offset.
1598*06c3fb27SDimitry Andric //
1599*06c3fb27SDimitry Andric // This leaves the original pointer on the stack and pushes a new one
1600*06c3fb27SDimitry Andric // with the offset applied and narrowed.
1601*06c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1602*06c3fb27SDimitry Andric inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
1603*06c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
1604*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1605*06c3fb27SDimitry Andric 
1606*06c3fb27SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1607*06c3fb27SDimitry Andric     return false;
1608*06c3fb27SDimitry Andric 
1609*06c3fb27SDimitry Andric   return NarrowPtr(S, OpPC);
1610*06c3fb27SDimitry Andric }
1611*06c3fb27SDimitry Andric 
1612*06c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1613*06c3fb27SDimitry Andric inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
1614*06c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
1615*06c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1616*06c3fb27SDimitry Andric 
1617*06c3fb27SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
1618*06c3fb27SDimitry Andric     return false;
1619*06c3fb27SDimitry Andric 
1620*06c3fb27SDimitry Andric   return NarrowPtr(S, OpPC);
1621*06c3fb27SDimitry Andric }
1622*06c3fb27SDimitry Andric 
1623*06c3fb27SDimitry Andric inline bool CheckGlobalCtor(InterpState &S, CodePtr OpPC) {
1624*06c3fb27SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
1625*06c3fb27SDimitry Andric   return CheckCtorCall(S, OpPC, Obj);
1626*06c3fb27SDimitry Andric }
1627*06c3fb27SDimitry Andric 
1628*06c3fb27SDimitry Andric inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
1629bdd1243dSDimitry Andric   if (Func->hasThisPointer()) {
1630*06c3fb27SDimitry Andric     size_t ThisOffset =
1631*06c3fb27SDimitry Andric         Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1632bdd1243dSDimitry Andric 
1633*06c3fb27SDimitry Andric     const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1634*06c3fb27SDimitry Andric 
1635*06c3fb27SDimitry Andric     if (!CheckInvoke(S, OpPC, ThisPtr))
1636bdd1243dSDimitry Andric       return false;
1637bdd1243dSDimitry Andric 
1638*06c3fb27SDimitry Andric     if (S.checkingPotentialConstantExpression())
1639*06c3fb27SDimitry Andric       return false;
1640*06c3fb27SDimitry Andric   }
1641*06c3fb27SDimitry Andric 
1642*06c3fb27SDimitry Andric   if (!CheckCallable(S, OpPC, Func))
1643*06c3fb27SDimitry Andric     return false;
1644*06c3fb27SDimitry Andric 
1645*06c3fb27SDimitry Andric   if (!CheckCallDepth(S, OpPC))
1646*06c3fb27SDimitry Andric     return false;
1647*06c3fb27SDimitry Andric 
1648*06c3fb27SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
1649bdd1243dSDimitry Andric   InterpFrame *FrameBefore = S.Current;
1650bdd1243dSDimitry Andric   S.Current = NewFrame.get();
1651bdd1243dSDimitry Andric 
1652bdd1243dSDimitry Andric   APValue CallResult;
1653bdd1243dSDimitry Andric   // Note that we cannot assert(CallResult.hasValue()) here since
1654bdd1243dSDimitry Andric   // Ret() above only sets the APValue if the curent frame doesn't
1655bdd1243dSDimitry Andric   // have a caller set.
1656bdd1243dSDimitry Andric   if (Interpret(S, CallResult)) {
1657bdd1243dSDimitry Andric     NewFrame.release(); // Frame was delete'd already.
1658bdd1243dSDimitry Andric     assert(S.Current == FrameBefore);
1659bdd1243dSDimitry Andric     return true;
1660bdd1243dSDimitry Andric   }
1661bdd1243dSDimitry Andric 
1662bdd1243dSDimitry Andric   // Interpreting the function failed somehow. Reset to
1663bdd1243dSDimitry Andric   // previous state.
1664bdd1243dSDimitry Andric   S.Current = FrameBefore;
1665bdd1243dSDimitry Andric   return false;
1666bdd1243dSDimitry Andric }
1667bdd1243dSDimitry Andric 
1668*06c3fb27SDimitry Andric inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
1669*06c3fb27SDimitry Andric   assert(Func->hasThisPointer());
1670*06c3fb27SDimitry Andric   assert(Func->isVirtual());
1671*06c3fb27SDimitry Andric   size_t ThisOffset =
1672*06c3fb27SDimitry Andric       Func->getArgSize() + (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1673*06c3fb27SDimitry Andric   Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1674*06c3fb27SDimitry Andric 
1675*06c3fb27SDimitry Andric   const CXXRecordDecl *DynamicDecl =
1676*06c3fb27SDimitry Andric       ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
1677*06c3fb27SDimitry Andric   const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
1678*06c3fb27SDimitry Andric   const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
1679*06c3fb27SDimitry Andric   const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
1680*06c3fb27SDimitry Andric       DynamicDecl, StaticDecl, InitialFunction);
1681*06c3fb27SDimitry Andric 
1682*06c3fb27SDimitry Andric   if (Overrider != InitialFunction) {
1683*06c3fb27SDimitry Andric     Func = S.P.getFunction(Overrider);
1684*06c3fb27SDimitry Andric 
1685*06c3fb27SDimitry Andric     const CXXRecordDecl *ThisFieldDecl =
1686*06c3fb27SDimitry Andric         ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
1687*06c3fb27SDimitry Andric     if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
1688*06c3fb27SDimitry Andric       // If the function we call is further DOWN the hierarchy than the
1689*06c3fb27SDimitry Andric       // FieldDesc of our pointer, just get the DeclDesc instead, which
1690*06c3fb27SDimitry Andric       // is the furthest we might go up in the hierarchy.
1691*06c3fb27SDimitry Andric       ThisPtr = ThisPtr.getDeclPtr();
1692*06c3fb27SDimitry Andric     }
1693*06c3fb27SDimitry Andric   }
1694*06c3fb27SDimitry Andric 
1695*06c3fb27SDimitry Andric   return Call(S, OpPC, Func);
1696*06c3fb27SDimitry Andric }
1697*06c3fb27SDimitry Andric 
1698*06c3fb27SDimitry Andric inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func) {
1699*06c3fb27SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1700*06c3fb27SDimitry Andric 
1701*06c3fb27SDimitry Andric   InterpFrame *FrameBefore = S.Current;
1702*06c3fb27SDimitry Andric   S.Current = NewFrame.get();
1703*06c3fb27SDimitry Andric 
1704*06c3fb27SDimitry Andric   if (InterpretBuiltin(S, PC, Func)) {
1705*06c3fb27SDimitry Andric     NewFrame.release();
1706*06c3fb27SDimitry Andric     return true;
1707*06c3fb27SDimitry Andric   }
1708*06c3fb27SDimitry Andric   S.Current = FrameBefore;
1709*06c3fb27SDimitry Andric   return false;
1710*06c3fb27SDimitry Andric }
1711*06c3fb27SDimitry Andric 
1712*06c3fb27SDimitry Andric inline bool CallPtr(InterpState &S, CodePtr OpPC) {
1713*06c3fb27SDimitry Andric   const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
1714*06c3fb27SDimitry Andric 
1715*06c3fb27SDimitry Andric   const Function *F = FuncPtr.getFunction();
1716*06c3fb27SDimitry Andric   if (!F || !F->isConstexpr())
1717*06c3fb27SDimitry Andric     return false;
1718*06c3fb27SDimitry Andric 
1719*06c3fb27SDimitry Andric   return Call(S, OpPC, F);
1720*06c3fb27SDimitry Andric }
1721*06c3fb27SDimitry Andric 
1722*06c3fb27SDimitry Andric inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
1723*06c3fb27SDimitry Andric   assert(Func);
1724*06c3fb27SDimitry Andric   S.Stk.push<FunctionPointer>(Func);
1725*06c3fb27SDimitry Andric   return true;
1726*06c3fb27SDimitry Andric }
1727*06c3fb27SDimitry Andric 
1728349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
1729349cc55cSDimitry Andric // Read opcode arguments
1730349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
1731349cc55cSDimitry Andric 
1732bdd1243dSDimitry Andric template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
1733bdd1243dSDimitry Andric   if constexpr (std::is_pointer<T>::value) {
1734349cc55cSDimitry Andric     uint32_t ID = OpPC.read<uint32_t>();
1735349cc55cSDimitry Andric     return reinterpret_cast<T>(S.P.getNativePointer(ID));
1736bdd1243dSDimitry Andric   } else {
1737bdd1243dSDimitry Andric     return OpPC.read<T>();
1738349cc55cSDimitry Andric   }
1739bdd1243dSDimitry Andric }
1740a7dea167SDimitry Andric 
1741a7dea167SDimitry Andric } // namespace interp
1742a7dea167SDimitry Andric } // namespace clang
1743a7dea167SDimitry Andric 
1744a7dea167SDimitry Andric #endif
1745