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"
1706c3fb27SDimitry Andric #include "Floating.h"
18a7dea167SDimitry Andric #include "Function.h"
1906c3fb27SDimitry 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);
58*5f757f3fSDimitry Andric 
59*5f757f3fSDimitry Andric /// Checks if a pointer is a dummy pointer.
60*5f757f3fSDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
61*5f757f3fSDimitry Andric 
62a7dea167SDimitry Andric /// Checks if a pointer is null.
63a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64a7dea167SDimitry Andric                CheckSubobjectKind CSK);
65a7dea167SDimitry Andric 
66a7dea167SDimitry Andric /// Checks if a pointer is in range.
67a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68a7dea167SDimitry Andric                 AccessKinds AK);
69a7dea167SDimitry Andric 
70a7dea167SDimitry Andric /// Checks if a field from which a pointer is going to be derived is valid.
71a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72a7dea167SDimitry Andric                 CheckSubobjectKind CSK);
73a7dea167SDimitry Andric 
74*5f757f3fSDimitry Andric /// Checks if Ptr is a one-past-the-end pointer.
75*5f757f3fSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
76*5f757f3fSDimitry Andric                     CheckSubobjectKind CSK);
77*5f757f3fSDimitry Andric 
78a7dea167SDimitry Andric /// Checks if a pointer points to const storage.
79a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
80a7dea167SDimitry Andric 
81a7dea167SDimitry Andric /// Checks if a pointer points to a mutable field.
82a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
83a7dea167SDimitry Andric 
84a7dea167SDimitry Andric /// Checks if a value can be loaded from a block.
85a7dea167SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
86a7dea167SDimitry Andric 
8706c3fb27SDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
8806c3fb27SDimitry Andric                       AccessKinds AK);
8906c3fb27SDimitry Andric 
90a7dea167SDimitry Andric /// Checks if a value can be stored in a block.
91a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
92a7dea167SDimitry Andric 
93a7dea167SDimitry Andric /// Checks if a method can be invoked on an object.
94a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
95a7dea167SDimitry Andric 
96a7dea167SDimitry Andric /// Checks if a value can be initialized.
97a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
98a7dea167SDimitry Andric 
99a7dea167SDimitry Andric /// Checks if a method can be called.
100bdd1243dSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
101a7dea167SDimitry Andric 
10206c3fb27SDimitry Andric /// Checks if calling the currently active function would exceed
10306c3fb27SDimitry Andric /// the allowed call depth.
10406c3fb27SDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC);
10506c3fb27SDimitry Andric 
106a7dea167SDimitry Andric /// Checks the 'this' pointer.
107a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
108a7dea167SDimitry Andric 
109a7dea167SDimitry Andric /// Checks if a method is pure virtual.
110a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
111a7dea167SDimitry Andric 
112bdd1243dSDimitry Andric /// Checks that all fields are initialized after a constructor call.
113bdd1243dSDimitry Andric bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
114bdd1243dSDimitry Andric 
115*5f757f3fSDimitry Andric /// Checks if reinterpret casts are legal in the current context.
116*5f757f3fSDimitry Andric bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
117*5f757f3fSDimitry Andric                                    const Pointer &Ptr);
118*5f757f3fSDimitry Andric 
119*5f757f3fSDimitry Andric /// Sets the given integral value to the pointer, which is of
120*5f757f3fSDimitry Andric /// a std::{weak,partial,strong}_ordering type.
121*5f757f3fSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
122*5f757f3fSDimitry Andric                                 const Pointer &Ptr, const APSInt &IntValue);
123*5f757f3fSDimitry Andric 
124bdd1243dSDimitry Andric /// Checks if the shift operation is legal.
12506c3fb27SDimitry Andric template <typename LT, typename RT>
12606c3fb27SDimitry Andric bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
12706c3fb27SDimitry Andric                 unsigned Bits) {
128bdd1243dSDimitry Andric   if (RHS.isNegative()) {
129bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
130bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
131bdd1243dSDimitry Andric     return false;
132bdd1243dSDimitry Andric   }
133bdd1243dSDimitry Andric 
134bdd1243dSDimitry Andric   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
135bdd1243dSDimitry Andric   // the shifted type.
136bdd1243dSDimitry Andric   if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
137bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
138bdd1243dSDimitry Andric     const APSInt Val = RHS.toAPSInt();
139bdd1243dSDimitry Andric     QualType Ty = E->getType();
140bdd1243dSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
141bdd1243dSDimitry Andric     return false;
142bdd1243dSDimitry Andric   }
14306c3fb27SDimitry Andric 
14406c3fb27SDimitry Andric   if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
14506c3fb27SDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
14606c3fb27SDimitry Andric     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
14706c3fb27SDimitry Andric     // operand, and must not overflow the corresponding unsigned type.
14806c3fb27SDimitry Andric     if (LHS.isNegative())
14906c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
15006c3fb27SDimitry Andric     else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
15106c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_discards);
15206c3fb27SDimitry Andric   }
15306c3fb27SDimitry Andric 
15406c3fb27SDimitry Andric   // C++2a [expr.shift]p2: [P0907R4]:
15506c3fb27SDimitry Andric   //    E1 << E2 is the unique value congruent to
15606c3fb27SDimitry Andric   //    E1 x 2^E2 module 2^N.
157bdd1243dSDimitry Andric   return true;
158bdd1243dSDimitry Andric }
159bdd1243dSDimitry Andric 
160bdd1243dSDimitry Andric /// Checks if Div/Rem operation on LHS and RHS is valid.
161bdd1243dSDimitry Andric template <typename T>
162bdd1243dSDimitry Andric bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
163bdd1243dSDimitry Andric   if (RHS.isZero()) {
164*5f757f3fSDimitry Andric     const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
165*5f757f3fSDimitry Andric     S.FFDiag(Op, diag::note_expr_divide_by_zero)
166*5f757f3fSDimitry Andric         << Op->getRHS()->getSourceRange();
167bdd1243dSDimitry Andric     return false;
168bdd1243dSDimitry Andric   }
169bdd1243dSDimitry Andric 
170bdd1243dSDimitry Andric   if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
171bdd1243dSDimitry Andric     APSInt LHSInt = LHS.toAPSInt();
172bdd1243dSDimitry Andric     SmallString<32> Trunc;
173bdd1243dSDimitry Andric     (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
174bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
175bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
176bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
177bdd1243dSDimitry Andric     return false;
178bdd1243dSDimitry Andric   }
179bdd1243dSDimitry Andric   return true;
180bdd1243dSDimitry Andric }
181bdd1243dSDimitry Andric 
182*5f757f3fSDimitry Andric /// Checks if the result of a floating-point operation is valid
18306c3fb27SDimitry Andric /// in the current context.
184*5f757f3fSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
185*5f757f3fSDimitry Andric                       APFloat::opStatus Status);
186*5f757f3fSDimitry Andric 
187*5f757f3fSDimitry Andric /// Checks why the given DeclRefExpr is invalid.
188*5f757f3fSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
18906c3fb27SDimitry Andric 
190bdd1243dSDimitry Andric /// Interpreter entry point.
191bdd1243dSDimitry Andric bool Interpret(InterpState &S, APValue &Result);
192a7dea167SDimitry Andric 
19306c3fb27SDimitry Andric /// Interpret a builtin function.
194*5f757f3fSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
195*5f757f3fSDimitry Andric                       const CallExpr *Call);
196*5f757f3fSDimitry Andric 
197*5f757f3fSDimitry Andric /// Interpret an offsetof operation.
198*5f757f3fSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
199*5f757f3fSDimitry Andric                        llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
20006c3fb27SDimitry Andric 
20106c3fb27SDimitry Andric enum class ArithOp { Add, Sub };
20206c3fb27SDimitry Andric 
20306c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
20406c3fb27SDimitry Andric // Returning values
20506c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
20606c3fb27SDimitry Andric 
207*5f757f3fSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
208*5f757f3fSDimitry Andric 
209*5f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
21006c3fb27SDimitry Andric bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
21106c3fb27SDimitry Andric   const T &Ret = S.Stk.pop<T>();
21206c3fb27SDimitry Andric 
213*5f757f3fSDimitry Andric   // Make sure returned pointers are live. We might be trying to return a
214*5f757f3fSDimitry Andric   // pointer or reference to a local variable.
215*5f757f3fSDimitry Andric   // Just return false, since a diagnostic has already been emitted in Sema.
216*5f757f3fSDimitry Andric   if constexpr (std::is_same_v<T, Pointer>) {
217*5f757f3fSDimitry Andric     // FIXME: We could be calling isLive() here, but the emitted diagnostics
218*5f757f3fSDimitry Andric     // seem a little weird, at least if the returned expression is of
219*5f757f3fSDimitry Andric     // pointer type.
220*5f757f3fSDimitry Andric     // Null pointers are considered live here.
221*5f757f3fSDimitry Andric     if (!Ret.isZero() && !Ret.isLive())
222*5f757f3fSDimitry Andric       return false;
223*5f757f3fSDimitry Andric   }
224*5f757f3fSDimitry Andric 
225*5f757f3fSDimitry Andric   assert(S.Current);
22606c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
227*5f757f3fSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
228*5f757f3fSDimitry Andric     cleanupAfterFunctionCall(S, PC);
22906c3fb27SDimitry Andric 
23006c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
23106c3fb27SDimitry Andric     PC = S.Current->getRetPC();
23206c3fb27SDimitry Andric     delete S.Current;
23306c3fb27SDimitry Andric     S.Current = Caller;
23406c3fb27SDimitry Andric     S.Stk.push<T>(Ret);
23506c3fb27SDimitry Andric   } else {
23606c3fb27SDimitry Andric     delete S.Current;
23706c3fb27SDimitry Andric     S.Current = nullptr;
23806c3fb27SDimitry Andric     if (!ReturnValue<T>(Ret, Result))
23906c3fb27SDimitry Andric       return false;
24006c3fb27SDimitry Andric   }
24106c3fb27SDimitry Andric   return true;
24206c3fb27SDimitry Andric }
24306c3fb27SDimitry Andric 
24406c3fb27SDimitry Andric inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
24506c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
246*5f757f3fSDimitry Andric 
247*5f757f3fSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
248*5f757f3fSDimitry Andric     cleanupAfterFunctionCall(S, PC);
24906c3fb27SDimitry Andric 
25006c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
25106c3fb27SDimitry Andric     PC = S.Current->getRetPC();
25206c3fb27SDimitry Andric     delete S.Current;
25306c3fb27SDimitry Andric     S.Current = Caller;
25406c3fb27SDimitry Andric   } else {
25506c3fb27SDimitry Andric     delete S.Current;
25606c3fb27SDimitry Andric     S.Current = nullptr;
25706c3fb27SDimitry Andric   }
25806c3fb27SDimitry Andric   return true;
25906c3fb27SDimitry Andric }
26006c3fb27SDimitry Andric 
261a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
262a7dea167SDimitry Andric // Add, Sub, Mul
263a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
264a7dea167SDimitry Andric 
265a7dea167SDimitry Andric template <typename T, bool (*OpFW)(T, T, unsigned, T *),
266a7dea167SDimitry Andric           template <typename U> class OpAP>
267a7dea167SDimitry Andric bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
268a7dea167SDimitry Andric                      const T &RHS) {
269a7dea167SDimitry Andric   // Fast path - add the numbers with fixed width.
270a7dea167SDimitry Andric   T Result;
271a7dea167SDimitry Andric   if (!OpFW(LHS, RHS, Bits, &Result)) {
272a7dea167SDimitry Andric     S.Stk.push<T>(Result);
273a7dea167SDimitry Andric     return true;
274a7dea167SDimitry Andric   }
275a7dea167SDimitry Andric 
276a7dea167SDimitry Andric   // If for some reason evaluation continues, use the truncated results.
277a7dea167SDimitry Andric   S.Stk.push<T>(Result);
278a7dea167SDimitry Andric 
279a7dea167SDimitry Andric   // Slow path - compute the result using another bit of precision.
280a7dea167SDimitry Andric   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
281a7dea167SDimitry Andric 
282a7dea167SDimitry Andric   // Report undefined behaviour, stopping if required.
283a7dea167SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
284a7dea167SDimitry Andric   QualType Type = E->getType();
285a7dea167SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
286fe6060f1SDimitry Andric     SmallString<32> Trunc;
287fe6060f1SDimitry Andric     Value.trunc(Result.bitWidth()).toString(Trunc, 10);
288a7dea167SDimitry Andric     auto Loc = E->getExprLoc();
289*5f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
290*5f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
291a7dea167SDimitry Andric     return true;
292a7dea167SDimitry Andric   } else {
293a7dea167SDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
294*5f757f3fSDimitry Andric     if (!S.noteUndefinedBehavior()) {
295*5f757f3fSDimitry Andric       S.Stk.pop<T>();
296*5f757f3fSDimitry Andric       return false;
297*5f757f3fSDimitry Andric     }
298*5f757f3fSDimitry Andric     return true;
299a7dea167SDimitry Andric   }
300a7dea167SDimitry Andric }
301a7dea167SDimitry Andric 
302a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
303a7dea167SDimitry Andric bool Add(InterpState &S, CodePtr OpPC) {
304a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
305a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
306a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
307a7dea167SDimitry Andric   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
308a7dea167SDimitry Andric }
309a7dea167SDimitry Andric 
31006c3fb27SDimitry Andric inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
31106c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
31206c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
31306c3fb27SDimitry Andric 
31406c3fb27SDimitry Andric   Floating Result;
31506c3fb27SDimitry Andric   auto Status = Floating::add(LHS, RHS, RM, &Result);
31606c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
317*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
31806c3fb27SDimitry Andric }
31906c3fb27SDimitry Andric 
320a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
321a7dea167SDimitry Andric bool Sub(InterpState &S, CodePtr OpPC) {
322a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
323a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
324a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
325a7dea167SDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
326a7dea167SDimitry Andric }
327a7dea167SDimitry Andric 
32806c3fb27SDimitry Andric inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
32906c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
33006c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
33106c3fb27SDimitry Andric 
33206c3fb27SDimitry Andric   Floating Result;
33306c3fb27SDimitry Andric   auto Status = Floating::sub(LHS, RHS, RM, &Result);
33406c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
335*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
33606c3fb27SDimitry Andric }
33706c3fb27SDimitry Andric 
338a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
339a7dea167SDimitry Andric bool Mul(InterpState &S, CodePtr OpPC) {
340a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
341a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
342a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
343a7dea167SDimitry Andric   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
344a7dea167SDimitry Andric }
345a7dea167SDimitry Andric 
34606c3fb27SDimitry Andric inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
34706c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
34806c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
34906c3fb27SDimitry Andric 
35006c3fb27SDimitry Andric   Floating Result;
35106c3fb27SDimitry Andric   auto Status = Floating::mul(LHS, RHS, RM, &Result);
35206c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
353*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
35406c3fb27SDimitry Andric }
355bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
356bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
357bdd1243dSDimitry Andric /// 3) Pushes 'LHS & RHS' on the stack
358bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
359bdd1243dSDimitry Andric bool BitAnd(InterpState &S, CodePtr OpPC) {
360bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
361bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
362bdd1243dSDimitry Andric 
363bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
364bdd1243dSDimitry Andric   T Result;
365bdd1243dSDimitry Andric   if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
366bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
367bdd1243dSDimitry Andric     return true;
368bdd1243dSDimitry Andric   }
369bdd1243dSDimitry Andric   return false;
370bdd1243dSDimitry Andric }
371bdd1243dSDimitry Andric 
372bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
373bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
374bdd1243dSDimitry Andric /// 3) Pushes 'LHS | RHS' on the stack
375bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
376bdd1243dSDimitry Andric bool BitOr(InterpState &S, CodePtr OpPC) {
377bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
378bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
379bdd1243dSDimitry Andric 
380bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
381bdd1243dSDimitry Andric   T Result;
382bdd1243dSDimitry Andric   if (!T::bitOr(LHS, RHS, Bits, &Result)) {
383bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
384bdd1243dSDimitry Andric     return true;
385bdd1243dSDimitry Andric   }
386bdd1243dSDimitry Andric   return false;
387bdd1243dSDimitry Andric }
388bdd1243dSDimitry Andric 
389bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
390bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
391bdd1243dSDimitry Andric /// 3) Pushes 'LHS ^ RHS' on the stack
392bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
393bdd1243dSDimitry Andric bool BitXor(InterpState &S, CodePtr OpPC) {
394bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
395bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
396bdd1243dSDimitry Andric 
397bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
398bdd1243dSDimitry Andric   T Result;
399bdd1243dSDimitry Andric   if (!T::bitXor(LHS, RHS, Bits, &Result)) {
400bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
401bdd1243dSDimitry Andric     return true;
402bdd1243dSDimitry Andric   }
403bdd1243dSDimitry Andric   return false;
404bdd1243dSDimitry Andric }
405bdd1243dSDimitry Andric 
406bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
407bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
408bdd1243dSDimitry Andric /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
409bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
410bdd1243dSDimitry Andric bool Rem(InterpState &S, CodePtr OpPC) {
411bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
412bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
413bdd1243dSDimitry Andric 
414bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
415bdd1243dSDimitry Andric     return false;
416bdd1243dSDimitry Andric 
417bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
418bdd1243dSDimitry Andric   T Result;
419bdd1243dSDimitry Andric   if (!T::rem(LHS, RHS, Bits, &Result)) {
420bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
421bdd1243dSDimitry Andric     return true;
422bdd1243dSDimitry Andric   }
423bdd1243dSDimitry Andric   return false;
424bdd1243dSDimitry Andric }
425bdd1243dSDimitry Andric 
426bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
427bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
428bdd1243dSDimitry Andric /// 3) Pushes 'LHS / RHS' on the stack
429bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
430bdd1243dSDimitry Andric bool Div(InterpState &S, CodePtr OpPC) {
431bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
432bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
433bdd1243dSDimitry Andric 
434bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
435bdd1243dSDimitry Andric     return false;
436bdd1243dSDimitry Andric 
437bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
438bdd1243dSDimitry Andric   T Result;
439bdd1243dSDimitry Andric   if (!T::div(LHS, RHS, Bits, &Result)) {
440bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
441bdd1243dSDimitry Andric     return true;
442bdd1243dSDimitry Andric   }
443bdd1243dSDimitry Andric   return false;
444bdd1243dSDimitry Andric }
445bdd1243dSDimitry Andric 
44606c3fb27SDimitry Andric inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
44706c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
44806c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
44906c3fb27SDimitry Andric 
45006c3fb27SDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
45106c3fb27SDimitry Andric     return false;
45206c3fb27SDimitry Andric 
45306c3fb27SDimitry Andric   Floating Result;
45406c3fb27SDimitry Andric   auto Status = Floating::div(LHS, RHS, RM, &Result);
45506c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
456*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
45706c3fb27SDimitry Andric }
45806c3fb27SDimitry Andric 
459bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
460bdd1243dSDimitry Andric // Inv
461bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
462bdd1243dSDimitry Andric 
463bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
464bdd1243dSDimitry Andric bool Inv(InterpState &S, CodePtr OpPC) {
465bdd1243dSDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
466bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
467bdd1243dSDimitry Andric   const unsigned Bits = Val.bitWidth();
468bdd1243dSDimitry Andric   Boolean R;
469bdd1243dSDimitry Andric   Boolean::inv(BoolT::from(Val, Bits), &R);
470bdd1243dSDimitry Andric 
471bdd1243dSDimitry Andric   S.Stk.push<BoolT>(R);
472bdd1243dSDimitry Andric   return true;
473bdd1243dSDimitry Andric }
474bdd1243dSDimitry Andric 
475bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
476bdd1243dSDimitry Andric // Neg
477bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
478bdd1243dSDimitry Andric 
479bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
480bdd1243dSDimitry Andric bool Neg(InterpState &S, CodePtr OpPC) {
48106c3fb27SDimitry Andric   const T &Value = S.Stk.pop<T>();
482bdd1243dSDimitry Andric   T Result;
483bdd1243dSDimitry Andric 
48406c3fb27SDimitry Andric   if (!T::neg(Value, &Result)) {
485bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
486bdd1243dSDimitry Andric     return true;
487bdd1243dSDimitry Andric   }
488bdd1243dSDimitry Andric 
48906c3fb27SDimitry Andric   assert(isIntegralType(Name) &&
49006c3fb27SDimitry Andric          "don't expect other types to fail at constexpr negation");
49106c3fb27SDimitry Andric   S.Stk.push<T>(Result);
49206c3fb27SDimitry Andric 
49306c3fb27SDimitry Andric   APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
49406c3fb27SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
49506c3fb27SDimitry Andric   QualType Type = E->getType();
49606c3fb27SDimitry Andric 
49706c3fb27SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
49806c3fb27SDimitry Andric     SmallString<32> Trunc;
49906c3fb27SDimitry Andric     NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
50006c3fb27SDimitry Andric     auto Loc = E->getExprLoc();
501*5f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
502*5f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
50306c3fb27SDimitry Andric     return true;
50406c3fb27SDimitry Andric   }
50506c3fb27SDimitry Andric 
50606c3fb27SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
50706c3fb27SDimitry Andric   return S.noteUndefinedBehavior();
50806c3fb27SDimitry Andric }
50906c3fb27SDimitry Andric 
510bdd1243dSDimitry Andric enum class PushVal : bool {
511bdd1243dSDimitry Andric   No,
512bdd1243dSDimitry Andric   Yes,
513bdd1243dSDimitry Andric };
514bdd1243dSDimitry Andric enum class IncDecOp {
515bdd1243dSDimitry Andric   Inc,
516bdd1243dSDimitry Andric   Dec,
517bdd1243dSDimitry Andric };
518bdd1243dSDimitry Andric 
519bdd1243dSDimitry Andric template <typename T, IncDecOp Op, PushVal DoPush>
520bdd1243dSDimitry Andric bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
521*5f757f3fSDimitry Andric   const T &Value = Ptr.deref<T>();
522bdd1243dSDimitry Andric   T Result;
523bdd1243dSDimitry Andric 
524bdd1243dSDimitry Andric   if constexpr (DoPush == PushVal::Yes)
52506c3fb27SDimitry Andric     S.Stk.push<T>(Value);
526bdd1243dSDimitry Andric 
527bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc) {
528bdd1243dSDimitry Andric     if (!T::increment(Value, &Result)) {
529bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
530bdd1243dSDimitry Andric       return true;
531bdd1243dSDimitry Andric     }
532bdd1243dSDimitry Andric   } else {
533bdd1243dSDimitry Andric     if (!T::decrement(Value, &Result)) {
534bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
535bdd1243dSDimitry Andric       return true;
536bdd1243dSDimitry Andric     }
537bdd1243dSDimitry Andric   }
538bdd1243dSDimitry Andric 
539bdd1243dSDimitry Andric   // Something went wrong with the previous operation. Compute the
540bdd1243dSDimitry Andric   // result with another bit of precision.
541bdd1243dSDimitry Andric   unsigned Bits = Value.bitWidth() + 1;
542bdd1243dSDimitry Andric   APSInt APResult;
543bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc)
544bdd1243dSDimitry Andric     APResult = ++Value.toAPSInt(Bits);
545bdd1243dSDimitry Andric   else
546bdd1243dSDimitry Andric     APResult = --Value.toAPSInt(Bits);
547bdd1243dSDimitry Andric 
548bdd1243dSDimitry Andric   // Report undefined behaviour, stopping if required.
549bdd1243dSDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
550bdd1243dSDimitry Andric   QualType Type = E->getType();
551bdd1243dSDimitry Andric   if (S.checkingForUndefinedBehavior()) {
552bdd1243dSDimitry Andric     SmallString<32> Trunc;
553bdd1243dSDimitry Andric     APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
554bdd1243dSDimitry Andric     auto Loc = E->getExprLoc();
555*5f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
556*5f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
557bdd1243dSDimitry Andric     return true;
558bdd1243dSDimitry Andric   }
559bdd1243dSDimitry Andric 
560bdd1243dSDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
561bdd1243dSDimitry Andric   return S.noteUndefinedBehavior();
562bdd1243dSDimitry Andric }
563bdd1243dSDimitry Andric 
564bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
565bdd1243dSDimitry Andric /// 2) Load the value from the pointer
566bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
567bdd1243dSDimitry Andric /// 4) Pushes the original (pre-inc) value on the stack.
568bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
569bdd1243dSDimitry Andric bool Inc(InterpState &S, CodePtr OpPC) {
570bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
571bdd1243dSDimitry Andric 
57206c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
57306c3fb27SDimitry Andric     return false;
57406c3fb27SDimitry Andric 
575bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
576bdd1243dSDimitry Andric }
577bdd1243dSDimitry Andric 
578bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
579bdd1243dSDimitry Andric /// 2) Load the value from the pointer
580bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
581bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
582bdd1243dSDimitry Andric bool IncPop(InterpState &S, CodePtr OpPC) {
583bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
584bdd1243dSDimitry Andric 
58506c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
58606c3fb27SDimitry Andric     return false;
58706c3fb27SDimitry Andric 
588bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
589bdd1243dSDimitry Andric }
590bdd1243dSDimitry Andric 
591bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
592bdd1243dSDimitry Andric /// 2) Load the value from the pointer
593bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
594bdd1243dSDimitry Andric /// 4) Pushes the original (pre-dec) value on the stack.
595bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
596bdd1243dSDimitry Andric bool Dec(InterpState &S, CodePtr OpPC) {
597bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
598bdd1243dSDimitry Andric 
59906c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
60006c3fb27SDimitry Andric     return false;
60106c3fb27SDimitry Andric 
602bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
603bdd1243dSDimitry Andric }
604bdd1243dSDimitry Andric 
605bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
606bdd1243dSDimitry Andric /// 2) Load the value from the pointer
607bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
608bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
609bdd1243dSDimitry Andric bool DecPop(InterpState &S, CodePtr OpPC) {
610bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
611bdd1243dSDimitry Andric 
61206c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
61306c3fb27SDimitry Andric     return false;
61406c3fb27SDimitry Andric 
615bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
616bdd1243dSDimitry Andric }
617bdd1243dSDimitry Andric 
61806c3fb27SDimitry Andric template <IncDecOp Op, PushVal DoPush>
61906c3fb27SDimitry Andric bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
62006c3fb27SDimitry Andric                        llvm::RoundingMode RM) {
62106c3fb27SDimitry Andric   Floating Value = Ptr.deref<Floating>();
62206c3fb27SDimitry Andric   Floating Result;
62306c3fb27SDimitry Andric 
62406c3fb27SDimitry Andric   if constexpr (DoPush == PushVal::Yes)
62506c3fb27SDimitry Andric     S.Stk.push<Floating>(Value);
62606c3fb27SDimitry Andric 
62706c3fb27SDimitry Andric   llvm::APFloat::opStatus Status;
62806c3fb27SDimitry Andric   if constexpr (Op == IncDecOp::Inc)
62906c3fb27SDimitry Andric     Status = Floating::increment(Value, RM, &Result);
63006c3fb27SDimitry Andric   else
63106c3fb27SDimitry Andric     Status = Floating::decrement(Value, RM, &Result);
63206c3fb27SDimitry Andric 
63306c3fb27SDimitry Andric   Ptr.deref<Floating>() = Result;
63406c3fb27SDimitry Andric 
635*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
63606c3fb27SDimitry Andric }
63706c3fb27SDimitry Andric 
63806c3fb27SDimitry Andric inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
63906c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
64006c3fb27SDimitry Andric 
64106c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
64206c3fb27SDimitry Andric     return false;
64306c3fb27SDimitry Andric 
64406c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
64506c3fb27SDimitry Andric }
64606c3fb27SDimitry Andric 
64706c3fb27SDimitry Andric inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
64806c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
64906c3fb27SDimitry Andric 
65006c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
65106c3fb27SDimitry Andric     return false;
65206c3fb27SDimitry Andric 
65306c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
65406c3fb27SDimitry Andric }
65506c3fb27SDimitry Andric 
65606c3fb27SDimitry Andric inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
65706c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
65806c3fb27SDimitry Andric 
65906c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
66006c3fb27SDimitry Andric     return false;
66106c3fb27SDimitry Andric 
66206c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
66306c3fb27SDimitry Andric }
66406c3fb27SDimitry Andric 
66506c3fb27SDimitry Andric inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
66606c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
66706c3fb27SDimitry Andric 
66806c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
66906c3fb27SDimitry Andric     return false;
67006c3fb27SDimitry Andric 
67106c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
67206c3fb27SDimitry Andric }
67306c3fb27SDimitry Andric 
674bdd1243dSDimitry Andric /// 1) Pops the value from the stack.
675bdd1243dSDimitry Andric /// 2) Pushes the bitwise complemented value on the stack (~V).
676bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
677bdd1243dSDimitry Andric bool Comp(InterpState &S, CodePtr OpPC) {
678bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
679bdd1243dSDimitry Andric   T Result;
680bdd1243dSDimitry Andric   if (!T::comp(Val, &Result)) {
681bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
682bdd1243dSDimitry Andric     return true;
683bdd1243dSDimitry Andric   }
684bdd1243dSDimitry Andric 
685bdd1243dSDimitry Andric   return false;
686bdd1243dSDimitry Andric }
687bdd1243dSDimitry Andric 
688a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
689a7dea167SDimitry Andric // EQ, NE, GT, GE, LT, LE
690a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
691a7dea167SDimitry Andric 
692a7dea167SDimitry Andric using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
693a7dea167SDimitry Andric 
694a7dea167SDimitry Andric template <typename T>
695a7dea167SDimitry Andric bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
696a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
697a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
698a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
699a7dea167SDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
700a7dea167SDimitry Andric   return true;
701a7dea167SDimitry Andric }
702a7dea167SDimitry Andric 
703a7dea167SDimitry Andric template <typename T>
704a7dea167SDimitry Andric bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
705a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, Fn);
706a7dea167SDimitry Andric }
707a7dea167SDimitry Andric 
70806c3fb27SDimitry Andric /// Function pointers cannot be compared in an ordered way.
70906c3fb27SDimitry Andric template <>
71006c3fb27SDimitry Andric inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
71106c3fb27SDimitry Andric                                        CompareFn Fn) {
71206c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
71306c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
71406c3fb27SDimitry Andric 
71506c3fb27SDimitry Andric   const SourceInfo &Loc = S.Current->getSource(OpPC);
71606c3fb27SDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
71706c3fb27SDimitry Andric       << LHS.toDiagnosticString(S.getCtx())
71806c3fb27SDimitry Andric       << RHS.toDiagnosticString(S.getCtx());
71906c3fb27SDimitry Andric   return false;
72006c3fb27SDimitry Andric }
72106c3fb27SDimitry Andric 
72206c3fb27SDimitry Andric template <>
72306c3fb27SDimitry Andric inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
72406c3fb27SDimitry Andric                                          CompareFn Fn) {
72506c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
72606c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
72706c3fb27SDimitry Andric   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
72806c3fb27SDimitry Andric   return true;
72906c3fb27SDimitry Andric }
73006c3fb27SDimitry Andric 
731a7dea167SDimitry Andric template <>
732a7dea167SDimitry Andric inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
733a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
734a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
735a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
736a7dea167SDimitry Andric 
737a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
738a7dea167SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
739*5f757f3fSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
740*5f757f3fSDimitry Andric         << LHS.toDiagnosticString(S.getCtx())
741*5f757f3fSDimitry Andric         << RHS.toDiagnosticString(S.getCtx());
742a7dea167SDimitry Andric     return false;
743a7dea167SDimitry Andric   } else {
744a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
745a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
746a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
747a7dea167SDimitry Andric     return true;
748a7dea167SDimitry Andric   }
749a7dea167SDimitry Andric }
750a7dea167SDimitry Andric 
751a7dea167SDimitry Andric template <>
752a7dea167SDimitry Andric inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
753a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
754a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
755a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
756a7dea167SDimitry Andric 
757480093f4SDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
758a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
759a7dea167SDimitry Andric     return true;
760a7dea167SDimitry Andric   }
761a7dea167SDimitry Andric 
762a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
763a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
764a7dea167SDimitry Andric     return true;
765a7dea167SDimitry Andric   } else {
766a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
767a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
768bdd1243dSDimitry Andric 
769bdd1243dSDimitry Andric     // In our Pointer class, a pointer to an array and a pointer to the first
770bdd1243dSDimitry Andric     // element in the same array are NOT equal. They have the same Base value,
771bdd1243dSDimitry Andric     // but a different Offset. This is a pretty rare case, so we fix this here
772bdd1243dSDimitry Andric     // by comparing pointers to the first elements.
773*5f757f3fSDimitry Andric     if (LHS.isArrayRoot())
774bdd1243dSDimitry Andric       VL = LHS.atIndex(0).getByteOffset();
775*5f757f3fSDimitry Andric     if (RHS.isArrayRoot())
776bdd1243dSDimitry Andric       VR = RHS.atIndex(0).getByteOffset();
777bdd1243dSDimitry Andric 
778a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
779a7dea167SDimitry Andric     return true;
780a7dea167SDimitry Andric   }
781a7dea167SDimitry Andric }
782a7dea167SDimitry Andric 
783a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
784a7dea167SDimitry Andric bool EQ(InterpState &S, CodePtr OpPC) {
785a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
786a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Equal;
787a7dea167SDimitry Andric   });
788a7dea167SDimitry Andric }
789a7dea167SDimitry Andric 
790a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
791*5f757f3fSDimitry Andric bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
792*5f757f3fSDimitry Andric   const T &RHS = S.Stk.pop<T>();
793*5f757f3fSDimitry Andric   const T &LHS = S.Stk.pop<T>();
794*5f757f3fSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
795*5f757f3fSDimitry Andric 
796*5f757f3fSDimitry Andric   ComparisonCategoryResult CmpResult = LHS.compare(RHS);
797*5f757f3fSDimitry Andric   if (CmpResult == ComparisonCategoryResult::Unordered) {
798*5f757f3fSDimitry Andric     // This should only happen with pointers.
799*5f757f3fSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
800*5f757f3fSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
801*5f757f3fSDimitry Andric         << LHS.toDiagnosticString(S.getCtx())
802*5f757f3fSDimitry Andric         << RHS.toDiagnosticString(S.getCtx());
803*5f757f3fSDimitry Andric     return false;
804*5f757f3fSDimitry Andric   }
805*5f757f3fSDimitry Andric 
806*5f757f3fSDimitry Andric   assert(CmpInfo);
807*5f757f3fSDimitry Andric   const auto *CmpValueInfo = CmpInfo->getValueInfo(CmpResult);
808*5f757f3fSDimitry Andric   assert(CmpValueInfo);
809*5f757f3fSDimitry Andric   assert(CmpValueInfo->hasValidIntValue());
810*5f757f3fSDimitry Andric   APSInt IntValue = CmpValueInfo->getIntValue();
811*5f757f3fSDimitry Andric   return SetThreeWayComparisonField(S, OpPC, P, IntValue);
812*5f757f3fSDimitry Andric }
813*5f757f3fSDimitry Andric 
814*5f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
815a7dea167SDimitry Andric bool NE(InterpState &S, CodePtr OpPC) {
816a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
817a7dea167SDimitry Andric     return R != ComparisonCategoryResult::Equal;
818a7dea167SDimitry Andric   });
819a7dea167SDimitry Andric }
820a7dea167SDimitry Andric 
821a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
822a7dea167SDimitry Andric bool LT(InterpState &S, CodePtr OpPC) {
823a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
824a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less;
825a7dea167SDimitry Andric   });
826a7dea167SDimitry Andric }
827a7dea167SDimitry Andric 
828a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
829a7dea167SDimitry Andric bool LE(InterpState &S, CodePtr OpPC) {
830a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
831a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less ||
832a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
833a7dea167SDimitry Andric   });
834a7dea167SDimitry Andric }
835a7dea167SDimitry Andric 
836a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
837a7dea167SDimitry Andric bool GT(InterpState &S, CodePtr OpPC) {
838a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
839a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater;
840a7dea167SDimitry Andric   });
841a7dea167SDimitry Andric }
842a7dea167SDimitry Andric 
843a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
844a7dea167SDimitry Andric bool GE(InterpState &S, CodePtr OpPC) {
845a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
846a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater ||
847a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
848a7dea167SDimitry Andric   });
849a7dea167SDimitry Andric }
850a7dea167SDimitry Andric 
851a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
852a7dea167SDimitry Andric // InRange
853a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
854a7dea167SDimitry Andric 
855a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
856a7dea167SDimitry Andric bool InRange(InterpState &S, CodePtr OpPC) {
857a7dea167SDimitry Andric   const T RHS = S.Stk.pop<T>();
858a7dea167SDimitry Andric   const T LHS = S.Stk.pop<T>();
859a7dea167SDimitry Andric   const T Value = S.Stk.pop<T>();
860a7dea167SDimitry Andric 
861a7dea167SDimitry Andric   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
862a7dea167SDimitry Andric   return true;
863a7dea167SDimitry Andric }
864a7dea167SDimitry Andric 
865a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
866a7dea167SDimitry Andric // Dup, Pop, Test
867a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
868a7dea167SDimitry Andric 
869a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
870a7dea167SDimitry Andric bool Dup(InterpState &S, CodePtr OpPC) {
871a7dea167SDimitry Andric   S.Stk.push<T>(S.Stk.peek<T>());
872a7dea167SDimitry Andric   return true;
873a7dea167SDimitry Andric }
874a7dea167SDimitry Andric 
875a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
876a7dea167SDimitry Andric bool Pop(InterpState &S, CodePtr OpPC) {
877a7dea167SDimitry Andric   S.Stk.pop<T>();
878a7dea167SDimitry Andric   return true;
879a7dea167SDimitry Andric }
880a7dea167SDimitry Andric 
881a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
882a7dea167SDimitry Andric // Const
883a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
884a7dea167SDimitry Andric 
885a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
886a7dea167SDimitry Andric bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
887a7dea167SDimitry Andric   S.Stk.push<T>(Arg);
888a7dea167SDimitry Andric   return true;
889a7dea167SDimitry Andric }
890a7dea167SDimitry Andric 
891a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
892a7dea167SDimitry Andric // Get/Set Local/Param/Global/This
893a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
894a7dea167SDimitry Andric 
895a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
896a7dea167SDimitry Andric bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
897bdd1243dSDimitry Andric   const Pointer &Ptr = S.Current->getLocalPointer(I);
898bdd1243dSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
899bdd1243dSDimitry Andric     return false;
900bdd1243dSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
901a7dea167SDimitry Andric   return true;
902a7dea167SDimitry Andric }
903a7dea167SDimitry Andric 
90406c3fb27SDimitry Andric /// 1) Pops the value from the stack.
90506c3fb27SDimitry Andric /// 2) Writes the value to the local variable with the
90606c3fb27SDimitry Andric ///    given offset.
907a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
908a7dea167SDimitry Andric bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
909a7dea167SDimitry Andric   S.Current->setLocal<T>(I, S.Stk.pop<T>());
910a7dea167SDimitry Andric   return true;
911a7dea167SDimitry Andric }
912a7dea167SDimitry Andric 
913a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
914a7dea167SDimitry Andric bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
915a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
916a7dea167SDimitry Andric     return false;
917a7dea167SDimitry Andric   }
918a7dea167SDimitry Andric   S.Stk.push<T>(S.Current->getParam<T>(I));
919a7dea167SDimitry Andric   return true;
920a7dea167SDimitry Andric }
921a7dea167SDimitry Andric 
922a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
923a7dea167SDimitry Andric bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
924a7dea167SDimitry Andric   S.Current->setParam<T>(I, S.Stk.pop<T>());
925a7dea167SDimitry Andric   return true;
926a7dea167SDimitry Andric }
927a7dea167SDimitry Andric 
928bdd1243dSDimitry Andric /// 1) Peeks a pointer on the stack
929bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
930a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
931a7dea167SDimitry Andric bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
932a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
933a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
934a7dea167SDimitry Andric       return false;
935a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
936a7dea167SDimitry Andric     return false;
937a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
938a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
939a7dea167SDimitry Andric     return false;
940a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
941a7dea167SDimitry Andric   return true;
942a7dea167SDimitry Andric }
943a7dea167SDimitry Andric 
944a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
945a7dea167SDimitry Andric bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
946a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
947a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
948a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
949a7dea167SDimitry Andric     return false;
950a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
951a7dea167SDimitry Andric     return false;
952a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
953a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
954a7dea167SDimitry Andric     return false;
95506c3fb27SDimitry Andric   Field.initialize();
956a7dea167SDimitry Andric   Field.deref<T>() = Value;
957a7dea167SDimitry Andric   return true;
958a7dea167SDimitry Andric }
959a7dea167SDimitry Andric 
960bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
961bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
962a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
963a7dea167SDimitry Andric bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
964a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.pop<Pointer>();
965a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
966a7dea167SDimitry Andric     return false;
967a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
968a7dea167SDimitry Andric     return false;
969a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
970a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
971a7dea167SDimitry Andric     return false;
972a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
973a7dea167SDimitry Andric   return true;
974a7dea167SDimitry Andric }
975a7dea167SDimitry Andric 
976a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
977a7dea167SDimitry Andric bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
978a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
979a7dea167SDimitry Andric     return false;
980a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
981a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
982a7dea167SDimitry Andric     return false;
983a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
984a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
985a7dea167SDimitry Andric     return false;
986a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
987a7dea167SDimitry Andric   return true;
988a7dea167SDimitry Andric }
989a7dea167SDimitry Andric 
990a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
991a7dea167SDimitry Andric bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
992a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
993a7dea167SDimitry Andric     return false;
994a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
995a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
996a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
997a7dea167SDimitry Andric     return false;
998a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
999a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
1000a7dea167SDimitry Andric     return false;
1001a7dea167SDimitry Andric   Field.deref<T>() = Value;
1002a7dea167SDimitry Andric   return true;
1003a7dea167SDimitry Andric }
1004a7dea167SDimitry Andric 
1005a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1006a7dea167SDimitry Andric bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1007*5f757f3fSDimitry Andric   const Block *B = S.P.getGlobal(I);
1008a7dea167SDimitry Andric   if (B->isExtern())
1009a7dea167SDimitry Andric     return false;
1010a7dea167SDimitry Andric   S.Stk.push<T>(B->deref<T>());
1011a7dea167SDimitry Andric   return true;
1012a7dea167SDimitry Andric }
1013a7dea167SDimitry Andric 
1014a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1015a7dea167SDimitry Andric bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1016a7dea167SDimitry Andric   // TODO: emit warning.
1017a7dea167SDimitry Andric   return false;
1018a7dea167SDimitry Andric }
1019a7dea167SDimitry Andric 
1020a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1021a7dea167SDimitry Andric bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1022a7dea167SDimitry Andric   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1023a7dea167SDimitry Andric   return true;
1024a7dea167SDimitry Andric }
1025a7dea167SDimitry Andric 
102606c3fb27SDimitry Andric /// 1) Converts the value on top of the stack to an APValue
102706c3fb27SDimitry Andric /// 2) Sets that APValue on \Temp
102806c3fb27SDimitry Andric /// 3) Initialized global with index \I with that
102906c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
103006c3fb27SDimitry Andric bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
103106c3fb27SDimitry Andric                     const LifetimeExtendedTemporaryDecl *Temp) {
103206c3fb27SDimitry Andric   assert(Temp);
103306c3fb27SDimitry Andric   const T Value = S.Stk.peek<T>();
103406c3fb27SDimitry Andric   APValue APV = Value.toAPValue();
103506c3fb27SDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
103606c3fb27SDimitry Andric   *Cached = APV;
103706c3fb27SDimitry Andric 
103806c3fb27SDimitry Andric   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
103906c3fb27SDimitry Andric   return true;
104006c3fb27SDimitry Andric }
104106c3fb27SDimitry Andric 
1042*5f757f3fSDimitry Andric /// 1) Converts the value on top of the stack to an APValue
1043*5f757f3fSDimitry Andric /// 2) Sets that APValue on \Temp
1044*5f757f3fSDimitry Andric /// 3) Initialized global with index \I with that
1045*5f757f3fSDimitry Andric inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1046*5f757f3fSDimitry Andric                                const LifetimeExtendedTemporaryDecl *Temp) {
1047*5f757f3fSDimitry Andric   assert(Temp);
1048*5f757f3fSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
1049*5f757f3fSDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
1050*5f757f3fSDimitry Andric 
1051*5f757f3fSDimitry Andric   *Cached = P.toRValue(S.getCtx());
1052*5f757f3fSDimitry Andric   return true;
1053*5f757f3fSDimitry Andric }
1054*5f757f3fSDimitry Andric 
1055a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1056a7dea167SDimitry Andric bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1057a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1058a7dea167SDimitry Andric     return false;
1059a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1060a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1061a7dea167SDimitry Andric     return false;
1062a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1063a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1064a7dea167SDimitry Andric   Field.initialize();
1065a7dea167SDimitry Andric   return true;
1066a7dea167SDimitry Andric }
1067a7dea167SDimitry Andric 
1068a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1069a7dea167SDimitry Andric bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1070*5f757f3fSDimitry Andric   assert(F->isBitField());
1071a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1072a7dea167SDimitry Andric     return false;
1073a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1074a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1075a7dea167SDimitry Andric     return false;
1076a7dea167SDimitry Andric   const Pointer &Field = This.atField(F->Offset);
1077a7dea167SDimitry Andric   const auto &Value = S.Stk.pop<T>();
1078a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1079a7dea167SDimitry Andric   Field.initialize();
1080a7dea167SDimitry Andric   return true;
1081a7dea167SDimitry Andric }
1082a7dea167SDimitry Andric 
1083a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1084a7dea167SDimitry Andric bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1085a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1086a7dea167SDimitry Andric     return false;
1087a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1088a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1089a7dea167SDimitry Andric     return false;
1090a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1091a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1092a7dea167SDimitry Andric   Field.activate();
1093a7dea167SDimitry Andric   Field.initialize();
1094a7dea167SDimitry Andric   return true;
1095a7dea167SDimitry Andric }
1096a7dea167SDimitry Andric 
1097bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1098bdd1243dSDimitry Andric /// 2) Peeks a pointer from the stack
1099bdd1243dSDimitry Andric /// 3) Pushes the value to field I of the pointer on the stack
1100a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1101a7dea167SDimitry Andric bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1102a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1103bdd1243dSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1104a7dea167SDimitry Andric   Field.deref<T>() = Value;
1105a7dea167SDimitry Andric   Field.activate();
1106a7dea167SDimitry Andric   Field.initialize();
1107a7dea167SDimitry Andric   return true;
1108a7dea167SDimitry Andric }
1109a7dea167SDimitry Andric 
1110a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1111a7dea167SDimitry Andric bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1112*5f757f3fSDimitry Andric   assert(F->isBitField());
1113a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1114*5f757f3fSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1115a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1116a7dea167SDimitry Andric   Field.activate();
1117a7dea167SDimitry Andric   Field.initialize();
1118a7dea167SDimitry Andric   return true;
1119a7dea167SDimitry Andric }
1120a7dea167SDimitry Andric 
1121a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1122a7dea167SDimitry Andric bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1123a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1124a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1125a7dea167SDimitry Andric   const Pointer &Field = Ptr.atField(I);
1126a7dea167SDimitry Andric   Field.deref<T>() = Value;
1127a7dea167SDimitry Andric   Field.activate();
1128a7dea167SDimitry Andric   Field.initialize();
1129a7dea167SDimitry Andric   return true;
1130a7dea167SDimitry Andric }
1131a7dea167SDimitry Andric 
1132a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1133a7dea167SDimitry Andric // GetPtr Local/Param/Global/Field/This
1134a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1135a7dea167SDimitry Andric 
1136a7dea167SDimitry Andric inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1137a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1138a7dea167SDimitry Andric   return true;
1139a7dea167SDimitry Andric }
1140a7dea167SDimitry Andric 
1141a7dea167SDimitry Andric inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1142a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1143a7dea167SDimitry Andric     return false;
1144a7dea167SDimitry Andric   }
1145a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1146a7dea167SDimitry Andric   return true;
1147a7dea167SDimitry Andric }
1148a7dea167SDimitry Andric 
1149a7dea167SDimitry Andric inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1150a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1151a7dea167SDimitry Andric   return true;
1152a7dea167SDimitry Andric }
1153a7dea167SDimitry Andric 
1154bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack
1155bdd1243dSDimitry Andric /// 2) Pushes Pointer.atField(Off) on the stack
1156a7dea167SDimitry Andric inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1157a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1158*5f757f3fSDimitry Andric   if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field))
1159a7dea167SDimitry Andric     return false;
1160a7dea167SDimitry Andric   if (!CheckExtern(S, OpPC, Ptr))
1161a7dea167SDimitry Andric     return false;
1162a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1163a7dea167SDimitry Andric     return false;
1164*5f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1165*5f757f3fSDimitry Andric     return false;
1166*5f757f3fSDimitry Andric 
1167a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1168a7dea167SDimitry Andric   return true;
1169a7dea167SDimitry Andric }
1170a7dea167SDimitry Andric 
1171a7dea167SDimitry Andric inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1172a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1173a7dea167SDimitry Andric     return false;
1174a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1175a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1176a7dea167SDimitry Andric     return false;
1177a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1178a7dea167SDimitry Andric   return true;
1179a7dea167SDimitry Andric }
1180a7dea167SDimitry Andric 
1181a7dea167SDimitry Andric inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1182a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1183a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1184a7dea167SDimitry Andric     return false;
1185a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1186a7dea167SDimitry Andric     return false;
1187a7dea167SDimitry Andric   Pointer Field = Ptr.atField(Off);
1188a7dea167SDimitry Andric   Ptr.deactivate();
1189a7dea167SDimitry Andric   Field.activate();
1190a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1191a7dea167SDimitry Andric   return true;
1192a7dea167SDimitry Andric }
1193a7dea167SDimitry Andric 
1194a7dea167SDimitry Andric inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1195a7dea167SDimitry Andric  if (S.checkingPotentialConstantExpression())
1196a7dea167SDimitry Andric     return false;
1197a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1198a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1199a7dea167SDimitry Andric     return false;
1200a7dea167SDimitry Andric   Pointer Field = This.atField(Off);
1201a7dea167SDimitry Andric   This.deactivate();
1202a7dea167SDimitry Andric   Field.activate();
1203a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1204a7dea167SDimitry Andric   return true;
1205a7dea167SDimitry Andric }
1206a7dea167SDimitry Andric 
1207*5f757f3fSDimitry Andric inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1208*5f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1209*5f757f3fSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
1210*5f757f3fSDimitry Andric     return false;
1211*5f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1212*5f757f3fSDimitry Andric     return false;
1213*5f757f3fSDimitry Andric   S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1214*5f757f3fSDimitry Andric   return true;
1215*5f757f3fSDimitry Andric }
1216*5f757f3fSDimitry Andric 
1217a7dea167SDimitry Andric inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
121806c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
121906c3fb27SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
122006c3fb27SDimitry Andric     return false;
1221*5f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1222*5f757f3fSDimitry Andric     return false;
122306c3fb27SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
122406c3fb27SDimitry Andric   return true;
122506c3fb27SDimitry Andric }
122606c3fb27SDimitry Andric 
122706c3fb27SDimitry Andric inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1228a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1229a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1230a7dea167SDimitry Andric     return false;
1231*5f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1232*5f757f3fSDimitry Andric     return false;
1233a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1234a7dea167SDimitry Andric   return true;
1235a7dea167SDimitry Andric }
1236a7dea167SDimitry Andric 
1237a7dea167SDimitry Andric inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1238a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1239a7dea167SDimitry Andric     return false;
1240a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1241a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1242a7dea167SDimitry Andric     return false;
1243a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1244a7dea167SDimitry Andric   return true;
1245a7dea167SDimitry Andric }
1246a7dea167SDimitry Andric 
1247*5f757f3fSDimitry Andric inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
1248*5f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1249*5f757f3fSDimitry Andric   Ptr.initialize();
1250*5f757f3fSDimitry Andric   return true;
1251*5f757f3fSDimitry Andric }
1252*5f757f3fSDimitry Andric 
1253a7dea167SDimitry Andric inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1254a7dea167SDimitry Andric                            const Pointer &Ptr) {
1255a7dea167SDimitry Andric   Pointer Base = Ptr;
1256a7dea167SDimitry Andric   while (Base.isBaseClass())
1257a7dea167SDimitry Andric     Base = Base.getBase();
1258a7dea167SDimitry Andric 
1259a7dea167SDimitry Andric   auto *Field = Base.getRecord()->getVirtualBase(Decl);
1260a7dea167SDimitry Andric   S.Stk.push<Pointer>(Base.atField(Field->Offset));
1261a7dea167SDimitry Andric   return true;
1262a7dea167SDimitry Andric }
1263a7dea167SDimitry Andric 
1264a7dea167SDimitry Andric inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1265a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1266a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1267a7dea167SDimitry Andric     return false;
1268a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, Ptr);
1269a7dea167SDimitry Andric }
1270a7dea167SDimitry Andric 
1271a7dea167SDimitry Andric inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1272a7dea167SDimitry Andric                                const RecordDecl *D) {
1273a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1274a7dea167SDimitry Andric     return false;
1275a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1276a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1277a7dea167SDimitry Andric     return false;
1278a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1279a7dea167SDimitry Andric }
1280a7dea167SDimitry Andric 
1281a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1282a7dea167SDimitry Andric // Load, Store, Init
1283a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1284a7dea167SDimitry Andric 
1285a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1286a7dea167SDimitry Andric bool Load(InterpState &S, CodePtr OpPC) {
1287a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1288a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1289a7dea167SDimitry Andric     return false;
1290a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1291a7dea167SDimitry Andric   return true;
1292a7dea167SDimitry Andric }
1293a7dea167SDimitry Andric 
1294a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1295a7dea167SDimitry Andric bool LoadPop(InterpState &S, CodePtr OpPC) {
1296a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1297a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1298a7dea167SDimitry Andric     return false;
1299a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1300a7dea167SDimitry Andric   return true;
1301a7dea167SDimitry Andric }
1302a7dea167SDimitry Andric 
1303a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1304a7dea167SDimitry Andric bool Store(InterpState &S, CodePtr OpPC) {
1305a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1306a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1307a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1308a7dea167SDimitry Andric     return false;
1309bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1310bdd1243dSDimitry Andric     Ptr.initialize();
1311a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1312a7dea167SDimitry Andric   return true;
1313a7dea167SDimitry Andric }
1314a7dea167SDimitry Andric 
1315a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1316a7dea167SDimitry Andric bool StorePop(InterpState &S, CodePtr OpPC) {
1317a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1318a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1319a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1320a7dea167SDimitry Andric     return false;
1321bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1322bdd1243dSDimitry Andric     Ptr.initialize();
1323a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1324a7dea167SDimitry Andric   return true;
1325a7dea167SDimitry Andric }
1326a7dea167SDimitry Andric 
1327a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1328a7dea167SDimitry Andric bool StoreBitField(InterpState &S, CodePtr OpPC) {
1329a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1330a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1331a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1332a7dea167SDimitry Andric     return false;
1333bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1334bdd1243dSDimitry Andric     Ptr.initialize();
1335*5f757f3fSDimitry Andric   if (const auto *FD = Ptr.getField())
1336a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1337*5f757f3fSDimitry Andric   else
1338a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1339a7dea167SDimitry Andric   return true;
1340a7dea167SDimitry Andric }
1341a7dea167SDimitry Andric 
1342a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1343a7dea167SDimitry Andric bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1344a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1345a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1346a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1347a7dea167SDimitry Andric     return false;
1348bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1349bdd1243dSDimitry Andric     Ptr.initialize();
1350*5f757f3fSDimitry Andric   if (const auto *FD = Ptr.getField())
1351a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
1352*5f757f3fSDimitry Andric   else
1353a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1354a7dea167SDimitry Andric   return true;
1355a7dea167SDimitry Andric }
1356a7dea167SDimitry Andric 
1357a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1358a7dea167SDimitry Andric bool InitPop(InterpState &S, CodePtr OpPC) {
1359a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1360a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1361a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1362a7dea167SDimitry Andric     return false;
1363a7dea167SDimitry Andric   Ptr.initialize();
1364a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1365a7dea167SDimitry Andric   return true;
1366a7dea167SDimitry Andric }
1367a7dea167SDimitry Andric 
1368bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1369bdd1243dSDimitry Andric /// 2) Peeks a pointer and gets its index \Idx
1370bdd1243dSDimitry Andric /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1371a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1372a7dea167SDimitry Andric bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1373a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1374a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1375a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1376a7dea167SDimitry Andric     return false;
1377a7dea167SDimitry Andric   Ptr.initialize();
1378a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1379a7dea167SDimitry Andric   return true;
1380a7dea167SDimitry Andric }
1381a7dea167SDimitry Andric 
1382bdd1243dSDimitry Andric /// The same as InitElem, but pops the pointer as well.
1383a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1384a7dea167SDimitry Andric bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1385a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1386a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1387a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1388a7dea167SDimitry Andric     return false;
1389a7dea167SDimitry Andric   Ptr.initialize();
1390a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1391a7dea167SDimitry Andric   return true;
1392a7dea167SDimitry Andric }
1393a7dea167SDimitry Andric 
1394a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1395a7dea167SDimitry Andric // AddOffset, SubOffset
1396a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1397a7dea167SDimitry Andric 
139806c3fb27SDimitry Andric template <class T, ArithOp Op>
139906c3fb27SDimitry Andric bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
140006c3fb27SDimitry Andric                   const Pointer &Ptr) {
1401a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1402a7dea167SDimitry Andric     return false;
1403a7dea167SDimitry Andric 
1404bdd1243dSDimitry Andric   // A zero offset does not change the pointer.
1405a7dea167SDimitry Andric   if (Offset.isZero()) {
1406bdd1243dSDimitry Andric     S.Stk.push<Pointer>(Ptr);
1407a7dea167SDimitry Andric     return true;
1408a7dea167SDimitry Andric   }
1409bdd1243dSDimitry Andric 
1410bdd1243dSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1411bdd1243dSDimitry Andric     return false;
1412bdd1243dSDimitry Andric 
1413a7dea167SDimitry Andric   // Arrays of unknown bounds cannot have pointers into them.
1414a7dea167SDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
1415a7dea167SDimitry Andric     return false;
1416a7dea167SDimitry Andric 
1417bdd1243dSDimitry Andric   // Get a version of the index comparable to the type.
1418bdd1243dSDimitry Andric   T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1419a7dea167SDimitry Andric   // Compute the largest index into the array.
1420*5f757f3fSDimitry Andric   T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
1421a7dea167SDimitry Andric 
1422*5f757f3fSDimitry Andric   bool Invalid = false;
1423a7dea167SDimitry Andric   // Helper to report an invalid offset, computed as APSInt.
1424*5f757f3fSDimitry Andric   auto DiagInvalidOffset = [&]() -> void {
1425a7dea167SDimitry Andric     const unsigned Bits = Offset.bitWidth();
1426a7dea167SDimitry Andric     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1427a7dea167SDimitry Andric     APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
142806c3fb27SDimitry Andric     APSInt NewIndex =
142906c3fb27SDimitry Andric         (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1430a7dea167SDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1431a7dea167SDimitry Andric         << NewIndex
1432a7dea167SDimitry Andric         << /*array*/ static_cast<int>(!Ptr.inArray())
1433a7dea167SDimitry Andric         << static_cast<unsigned>(MaxIndex);
1434*5f757f3fSDimitry Andric     Invalid = true;
1435a7dea167SDimitry Andric   };
1436a7dea167SDimitry Andric 
1437*5f757f3fSDimitry Andric   T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
143806c3fb27SDimitry Andric   if constexpr (Op == ArithOp::Add) {
1439a7dea167SDimitry Andric     // If the new offset would be negative, bail out.
1440bdd1243dSDimitry Andric     if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1441*5f757f3fSDimitry Andric       DiagInvalidOffset();
1442a7dea167SDimitry Andric 
1443a7dea167SDimitry Andric     // If the new offset would be out of bounds, bail out.
1444bdd1243dSDimitry Andric     if (Offset.isPositive() && Offset > MaxOffset)
1445*5f757f3fSDimitry Andric       DiagInvalidOffset();
1446bdd1243dSDimitry Andric   } else {
1447bdd1243dSDimitry Andric     // If the new offset would be negative, bail out.
1448bdd1243dSDimitry Andric     if (Offset.isPositive() && Index < Offset)
1449*5f757f3fSDimitry Andric       DiagInvalidOffset();
1450a7dea167SDimitry Andric 
1451bdd1243dSDimitry Andric     // If the new offset would be out of bounds, bail out.
1452bdd1243dSDimitry Andric     if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1453*5f757f3fSDimitry Andric       DiagInvalidOffset();
1454bdd1243dSDimitry Andric   }
1455bdd1243dSDimitry Andric 
1456*5f757f3fSDimitry Andric   if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
1457*5f757f3fSDimitry Andric     return false;
1458*5f757f3fSDimitry Andric 
1459a7dea167SDimitry Andric   // Offset is valid - compute it on unsigned.
1460a7dea167SDimitry Andric   int64_t WideIndex = static_cast<int64_t>(Index);
1461a7dea167SDimitry Andric   int64_t WideOffset = static_cast<int64_t>(Offset);
1462bdd1243dSDimitry Andric   int64_t Result;
146306c3fb27SDimitry Andric   if constexpr (Op == ArithOp::Add)
1464bdd1243dSDimitry Andric     Result = WideIndex + WideOffset;
1465bdd1243dSDimitry Andric   else
1466bdd1243dSDimitry Andric     Result = WideIndex - WideOffset;
1467bdd1243dSDimitry Andric 
1468a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1469a7dea167SDimitry Andric   return true;
1470a7dea167SDimitry Andric }
1471a7dea167SDimitry Andric 
1472a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1473a7dea167SDimitry Andric bool AddOffset(InterpState &S, CodePtr OpPC) {
147406c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
147506c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
147606c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1477a7dea167SDimitry Andric }
1478a7dea167SDimitry Andric 
1479a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1480a7dea167SDimitry Andric bool SubOffset(InterpState &S, CodePtr OpPC) {
148106c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
148206c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
148306c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
148406c3fb27SDimitry Andric }
148506c3fb27SDimitry Andric 
148606c3fb27SDimitry Andric template <ArithOp Op>
1487*5f757f3fSDimitry Andric static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
1488*5f757f3fSDimitry Andric                                    const Pointer &Ptr) {
148906c3fb27SDimitry Andric   using OneT = Integral<8, false>;
1490*5f757f3fSDimitry Andric 
1491*5f757f3fSDimitry Andric   const Pointer &P = Ptr.deref<Pointer>();
1492*5f757f3fSDimitry Andric   if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
1493*5f757f3fSDimitry Andric     return false;
149406c3fb27SDimitry Andric 
149506c3fb27SDimitry Andric   // Get the current value on the stack.
1496*5f757f3fSDimitry Andric   S.Stk.push<Pointer>(P);
149706c3fb27SDimitry Andric 
149806c3fb27SDimitry Andric   // Now the current Ptr again and a constant 1.
149906c3fb27SDimitry Andric   OneT One = OneT::from(1);
150006c3fb27SDimitry Andric   if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
150106c3fb27SDimitry Andric     return false;
150206c3fb27SDimitry Andric 
150306c3fb27SDimitry Andric   // Store the new value.
150406c3fb27SDimitry Andric   Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
150506c3fb27SDimitry Andric   return true;
150606c3fb27SDimitry Andric }
150706c3fb27SDimitry Andric 
150806c3fb27SDimitry Andric static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
1509*5f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1510*5f757f3fSDimitry Andric 
1511*5f757f3fSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
1512*5f757f3fSDimitry Andric     return false;
1513*5f757f3fSDimitry Andric 
1514*5f757f3fSDimitry Andric   return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
151506c3fb27SDimitry Andric }
151606c3fb27SDimitry Andric 
151706c3fb27SDimitry Andric static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
1518*5f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1519*5f757f3fSDimitry Andric 
1520*5f757f3fSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
1521*5f757f3fSDimitry Andric     return false;
1522*5f757f3fSDimitry Andric 
1523*5f757f3fSDimitry Andric   return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1524a7dea167SDimitry Andric }
1525a7dea167SDimitry Andric 
1526bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack.
1527bdd1243dSDimitry Andric /// 2) Pops another Pointer from the stack.
1528bdd1243dSDimitry Andric /// 3) Pushes the different of the indices of the two pointers on the stack.
1529bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1530bdd1243dSDimitry Andric inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1531bdd1243dSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
1532bdd1243dSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
1533bdd1243dSDimitry Andric 
1534*5f757f3fSDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
1535bdd1243dSDimitry Andric     // TODO: Diagnose.
1536bdd1243dSDimitry Andric     return false;
1537bdd1243dSDimitry Andric   }
1538bdd1243dSDimitry Andric 
1539bdd1243dSDimitry Andric   T A = T::from(LHS.getIndex());
1540bdd1243dSDimitry Andric   T B = T::from(RHS.getIndex());
1541bdd1243dSDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1542bdd1243dSDimitry Andric }
1543a7dea167SDimitry Andric 
1544a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1545a7dea167SDimitry Andric // Destroy
1546a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1547a7dea167SDimitry Andric 
1548a7dea167SDimitry Andric inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1549a7dea167SDimitry Andric   S.Current->destroy(I);
1550a7dea167SDimitry Andric   return true;
1551a7dea167SDimitry Andric }
1552a7dea167SDimitry Andric 
1553a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1554a7dea167SDimitry Andric // Cast, CastFP
1555a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1556a7dea167SDimitry Andric 
1557a7dea167SDimitry Andric template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1558a7dea167SDimitry Andric   using T = typename PrimConv<TIn>::T;
1559a7dea167SDimitry Andric   using U = typename PrimConv<TOut>::T;
1560a7dea167SDimitry Andric   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1561a7dea167SDimitry Andric   return true;
1562a7dea167SDimitry Andric }
1563a7dea167SDimitry Andric 
156406c3fb27SDimitry Andric /// 1) Pops a Floating from the stack.
156506c3fb27SDimitry Andric /// 2) Pushes a new floating on the stack that uses the given semantics.
156606c3fb27SDimitry Andric inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
156706c3fb27SDimitry Andric             llvm::RoundingMode RM) {
156806c3fb27SDimitry Andric   Floating F = S.Stk.pop<Floating>();
156906c3fb27SDimitry Andric   Floating Result = F.toSemantics(Sem, RM);
157006c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
157106c3fb27SDimitry Andric   return true;
157206c3fb27SDimitry Andric }
157306c3fb27SDimitry Andric 
1574*5f757f3fSDimitry Andric /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
1575*5f757f3fSDimitry Andric /// to know what bitwidth the result should be.
1576*5f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1577*5f757f3fSDimitry Andric bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1578*5f757f3fSDimitry Andric   S.Stk.push<IntegralAP<false>>(
1579*5f757f3fSDimitry Andric       IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
1580*5f757f3fSDimitry Andric   return true;
1581*5f757f3fSDimitry Andric }
1582*5f757f3fSDimitry Andric 
1583*5f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1584*5f757f3fSDimitry Andric bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1585*5f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(
1586*5f757f3fSDimitry Andric       IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
1587*5f757f3fSDimitry Andric   return true;
1588*5f757f3fSDimitry Andric }
1589*5f757f3fSDimitry Andric 
159006c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
159106c3fb27SDimitry Andric bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
159206c3fb27SDimitry Andric                           const llvm::fltSemantics *Sem,
159306c3fb27SDimitry Andric                           llvm::RoundingMode RM) {
159406c3fb27SDimitry Andric   const T &From = S.Stk.pop<T>();
159506c3fb27SDimitry Andric   APSInt FromAP = From.toAPSInt();
159606c3fb27SDimitry Andric   Floating Result;
159706c3fb27SDimitry Andric 
159806c3fb27SDimitry Andric   auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
159906c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
160006c3fb27SDimitry Andric 
1601*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
160206c3fb27SDimitry Andric }
160306c3fb27SDimitry Andric 
160406c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
160506c3fb27SDimitry Andric bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
160606c3fb27SDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
160706c3fb27SDimitry Andric 
160806c3fb27SDimitry Andric   if constexpr (std::is_same_v<T, Boolean>) {
160906c3fb27SDimitry Andric     S.Stk.push<T>(T(F.isNonZero()));
161006c3fb27SDimitry Andric     return true;
161106c3fb27SDimitry Andric   } else {
1612*5f757f3fSDimitry Andric     APSInt Result(std::max(8u, T::bitWidth()),
161306c3fb27SDimitry Andric                   /*IsUnsigned=*/!T::isSigned());
161406c3fb27SDimitry Andric     auto Status = F.convertToInteger(Result);
161506c3fb27SDimitry Andric 
161606c3fb27SDimitry Andric     // Float-to-Integral overflow check.
161706c3fb27SDimitry Andric     if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
161806c3fb27SDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
161906c3fb27SDimitry Andric       QualType Type = E->getType();
162006c3fb27SDimitry Andric 
162106c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1622*5f757f3fSDimitry Andric       if (S.noteUndefinedBehavior()) {
1623*5f757f3fSDimitry Andric         S.Stk.push<T>(T(Result));
1624*5f757f3fSDimitry Andric         return true;
1625*5f757f3fSDimitry Andric       }
1626*5f757f3fSDimitry Andric       return false;
1627*5f757f3fSDimitry Andric     }
1628*5f757f3fSDimitry Andric 
1629*5f757f3fSDimitry Andric     S.Stk.push<T>(T(Result));
1630*5f757f3fSDimitry Andric     return CheckFloatResult(S, OpPC, F, Status);
1631*5f757f3fSDimitry Andric   }
1632*5f757f3fSDimitry Andric }
1633*5f757f3fSDimitry Andric 
1634*5f757f3fSDimitry Andric static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
1635*5f757f3fSDimitry Andric                                           uint32_t BitWidth) {
1636*5f757f3fSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
1637*5f757f3fSDimitry Andric 
1638*5f757f3fSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/true);
1639*5f757f3fSDimitry Andric   auto Status = F.convertToInteger(Result);
1640*5f757f3fSDimitry Andric 
1641*5f757f3fSDimitry Andric   // Float-to-Integral overflow check.
1642*5f757f3fSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1643*5f757f3fSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
1644*5f757f3fSDimitry Andric     QualType Type = E->getType();
1645*5f757f3fSDimitry Andric 
1646*5f757f3fSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
164706c3fb27SDimitry Andric     return S.noteUndefinedBehavior();
164806c3fb27SDimitry Andric   }
164906c3fb27SDimitry Andric 
1650*5f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
1651*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status);
165206c3fb27SDimitry Andric }
1653*5f757f3fSDimitry Andric 
1654*5f757f3fSDimitry Andric static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
1655*5f757f3fSDimitry Andric                                            uint32_t BitWidth) {
1656*5f757f3fSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
1657*5f757f3fSDimitry Andric 
1658*5f757f3fSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/false);
1659*5f757f3fSDimitry Andric   auto Status = F.convertToInteger(Result);
1660*5f757f3fSDimitry Andric 
1661*5f757f3fSDimitry Andric   // Float-to-Integral overflow check.
1662*5f757f3fSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
1663*5f757f3fSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
1664*5f757f3fSDimitry Andric     QualType Type = E->getType();
1665*5f757f3fSDimitry Andric 
1666*5f757f3fSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
1667*5f757f3fSDimitry Andric     return S.noteUndefinedBehavior();
1668*5f757f3fSDimitry Andric   }
1669*5f757f3fSDimitry Andric 
1670*5f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
1671*5f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status);
1672*5f757f3fSDimitry Andric }
1673*5f757f3fSDimitry Andric 
1674*5f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1675*5f757f3fSDimitry Andric bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
1676*5f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1677*5f757f3fSDimitry Andric 
1678*5f757f3fSDimitry Andric   if (!CheckPotentialReinterpretCast(S, OpPC, Ptr))
1679*5f757f3fSDimitry Andric     return false;
1680*5f757f3fSDimitry Andric 
1681*5f757f3fSDimitry Andric   S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
1682*5f757f3fSDimitry Andric   return true;
168306c3fb27SDimitry Andric }
168406c3fb27SDimitry Andric 
1685a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1686a7dea167SDimitry Andric // Zero, Nullptr
1687a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1688a7dea167SDimitry Andric 
1689a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1690a7dea167SDimitry Andric bool Zero(InterpState &S, CodePtr OpPC) {
1691a7dea167SDimitry Andric   S.Stk.push<T>(T::zero());
1692a7dea167SDimitry Andric   return true;
1693a7dea167SDimitry Andric }
1694a7dea167SDimitry Andric 
1695*5f757f3fSDimitry Andric static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1696*5f757f3fSDimitry Andric   S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
1697*5f757f3fSDimitry Andric   return true;
1698*5f757f3fSDimitry Andric }
1699*5f757f3fSDimitry Andric 
1700*5f757f3fSDimitry Andric static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1701*5f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
1702*5f757f3fSDimitry Andric   return true;
1703*5f757f3fSDimitry Andric }
1704*5f757f3fSDimitry Andric 
1705a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
1706a7dea167SDimitry Andric inline bool Null(InterpState &S, CodePtr OpPC) {
1707a7dea167SDimitry Andric   S.Stk.push<T>();
1708a7dea167SDimitry Andric   return true;
1709a7dea167SDimitry Andric }
1710a7dea167SDimitry Andric 
1711a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1712a7dea167SDimitry Andric // This, ImplicitThis
1713a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1714a7dea167SDimitry Andric 
1715a7dea167SDimitry Andric inline bool This(InterpState &S, CodePtr OpPC) {
1716a7dea167SDimitry Andric   // Cannot read 'this' in this mode.
1717a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1718a7dea167SDimitry Andric     return false;
1719a7dea167SDimitry Andric   }
1720a7dea167SDimitry Andric 
1721a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1722a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1723a7dea167SDimitry Andric     return false;
1724a7dea167SDimitry Andric 
1725a7dea167SDimitry Andric   S.Stk.push<Pointer>(This);
1726a7dea167SDimitry Andric   return true;
1727a7dea167SDimitry Andric }
1728a7dea167SDimitry Andric 
1729bdd1243dSDimitry Andric inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1730bdd1243dSDimitry Andric   assert(S.Current->getFunction()->hasRVO());
173106c3fb27SDimitry Andric   if (S.checkingPotentialConstantExpression())
173206c3fb27SDimitry Andric     return false;
1733bdd1243dSDimitry Andric   S.Stk.push<Pointer>(S.Current->getRVOPtr());
1734bdd1243dSDimitry Andric   return true;
1735bdd1243dSDimitry Andric }
1736bdd1243dSDimitry Andric 
1737a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1738a7dea167SDimitry Andric // Shr, Shl
1739a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1740a7dea167SDimitry Andric 
1741bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
1742a7dea167SDimitry Andric inline bool Shr(InterpState &S, CodePtr OpPC) {
1743bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
1744bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
1745bdd1243dSDimitry Andric   const auto &RHS = S.Stk.pop<RT>();
1746bdd1243dSDimitry Andric   const auto &LHS = S.Stk.pop<LT>();
1747a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
1748a7dea167SDimitry Andric 
174906c3fb27SDimitry Andric   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1750bdd1243dSDimitry Andric     return false;
1751bdd1243dSDimitry Andric 
1752*5f757f3fSDimitry Andric   typename LT::AsUnsigned R;
1753*5f757f3fSDimitry Andric   LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
1754*5f757f3fSDimitry Andric                              LT::AsUnsigned::from(RHS), Bits, &R);
1755*5f757f3fSDimitry Andric   S.Stk.push<LT>(LT::from(R));
1756*5f757f3fSDimitry Andric 
1757bdd1243dSDimitry Andric   return true;
1758a7dea167SDimitry Andric }
1759a7dea167SDimitry Andric 
1760bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
1761a7dea167SDimitry Andric inline bool Shl(InterpState &S, CodePtr OpPC) {
1762bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
1763bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
1764bdd1243dSDimitry Andric   const auto &RHS = S.Stk.pop<RT>();
1765bdd1243dSDimitry Andric   const auto &LHS = S.Stk.pop<LT>();
1766a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
1767a7dea167SDimitry Andric 
176806c3fb27SDimitry Andric   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1769bdd1243dSDimitry Andric     return false;
1770bdd1243dSDimitry Andric 
1771*5f757f3fSDimitry Andric   typename LT::AsUnsigned R;
1772*5f757f3fSDimitry Andric   LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
1773*5f757f3fSDimitry Andric                             LT::AsUnsigned::from(RHS, Bits), Bits, &R);
1774*5f757f3fSDimitry Andric   S.Stk.push<LT>(LT::from(R));
1775bdd1243dSDimitry Andric   return true;
1776a7dea167SDimitry Andric }
1777a7dea167SDimitry Andric 
1778a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1779a7dea167SDimitry Andric // NoRet
1780a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1781a7dea167SDimitry Andric 
1782a7dea167SDimitry Andric inline bool NoRet(InterpState &S, CodePtr OpPC) {
1783a7dea167SDimitry Andric   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1784a7dea167SDimitry Andric   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1785a7dea167SDimitry Andric   return false;
1786a7dea167SDimitry Andric }
1787a7dea167SDimitry Andric 
1788a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1789a7dea167SDimitry Andric // NarrowPtr, ExpandPtr
1790a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1791a7dea167SDimitry Andric 
1792a7dea167SDimitry Andric inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1793a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1794a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.narrow());
1795a7dea167SDimitry Andric   return true;
1796a7dea167SDimitry Andric }
1797a7dea167SDimitry Andric 
1798a7dea167SDimitry Andric inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1799a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1800a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.expand());
1801a7dea167SDimitry Andric   return true;
1802a7dea167SDimitry Andric }
1803a7dea167SDimitry Andric 
180406c3fb27SDimitry Andric // 1) Pops an integral value from the stack
180506c3fb27SDimitry Andric // 2) Peeks a pointer
180606c3fb27SDimitry Andric // 3) Pushes a new pointer that's a narrowed array
180706c3fb27SDimitry Andric //   element of the peeked pointer with the value
180806c3fb27SDimitry Andric //   from 1) added as offset.
180906c3fb27SDimitry Andric //
181006c3fb27SDimitry Andric // This leaves the original pointer on the stack and pushes a new one
181106c3fb27SDimitry Andric // with the offset applied and narrowed.
181206c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
181306c3fb27SDimitry Andric inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
181406c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
181506c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
181606c3fb27SDimitry Andric 
1817*5f757f3fSDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
1818*5f757f3fSDimitry Andric     return false;
1819*5f757f3fSDimitry Andric 
182006c3fb27SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
182106c3fb27SDimitry Andric     return false;
182206c3fb27SDimitry Andric 
182306c3fb27SDimitry Andric   return NarrowPtr(S, OpPC);
182406c3fb27SDimitry Andric }
182506c3fb27SDimitry Andric 
1826*5f757f3fSDimitry Andric /// Just takes a pointer and checks if its' an incomplete
1827*5f757f3fSDimitry Andric /// array type.
1828*5f757f3fSDimitry Andric inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
1829*5f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1830*5f757f3fSDimitry Andric 
1831*5f757f3fSDimitry Andric   if (!Ptr.isUnknownSizeArray()) {
1832*5f757f3fSDimitry Andric     S.Stk.push<Pointer>(Ptr.atIndex(0));
1833*5f757f3fSDimitry Andric     return true;
1834*5f757f3fSDimitry Andric   }
1835*5f757f3fSDimitry Andric 
1836*5f757f3fSDimitry Andric   const SourceInfo &E = S.Current->getSource(OpPC);
1837*5f757f3fSDimitry Andric   S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
1838*5f757f3fSDimitry Andric 
1839*5f757f3fSDimitry Andric   return false;
1840*5f757f3fSDimitry Andric }
1841*5f757f3fSDimitry Andric 
184206c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
184306c3fb27SDimitry Andric inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
184406c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
184506c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
184606c3fb27SDimitry Andric 
1847*5f757f3fSDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
1848*5f757f3fSDimitry Andric     return false;
1849*5f757f3fSDimitry Andric 
185006c3fb27SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
185106c3fb27SDimitry Andric     return false;
185206c3fb27SDimitry Andric 
185306c3fb27SDimitry Andric   return NarrowPtr(S, OpPC);
185406c3fb27SDimitry Andric }
185506c3fb27SDimitry Andric 
185606c3fb27SDimitry Andric inline bool CheckGlobalCtor(InterpState &S, CodePtr OpPC) {
185706c3fb27SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
185806c3fb27SDimitry Andric   return CheckCtorCall(S, OpPC, Obj);
185906c3fb27SDimitry Andric }
186006c3fb27SDimitry Andric 
186106c3fb27SDimitry Andric inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
1862bdd1243dSDimitry Andric   if (Func->hasThisPointer()) {
186306c3fb27SDimitry Andric     size_t ThisOffset =
1864*5f757f3fSDimitry Andric         Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1865bdd1243dSDimitry Andric 
186606c3fb27SDimitry Andric     const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
186706c3fb27SDimitry Andric 
1868*5f757f3fSDimitry Andric     // If the current function is a lambda static invoker and
1869*5f757f3fSDimitry Andric     // the function we're about to call is a lambda call operator,
1870*5f757f3fSDimitry Andric     // skip the CheckInvoke, since the ThisPtr is a null pointer
1871*5f757f3fSDimitry Andric     // anyway.
1872*5f757f3fSDimitry Andric     if (!(S.Current->getFunction() &&
1873*5f757f3fSDimitry Andric           S.Current->getFunction()->isLambdaStaticInvoker() &&
1874*5f757f3fSDimitry Andric           Func->isLambdaCallOperator())) {
187506c3fb27SDimitry Andric       if (!CheckInvoke(S, OpPC, ThisPtr))
1876bdd1243dSDimitry Andric         return false;
1877*5f757f3fSDimitry Andric     }
1878bdd1243dSDimitry Andric 
187906c3fb27SDimitry Andric     if (S.checkingPotentialConstantExpression())
188006c3fb27SDimitry Andric       return false;
188106c3fb27SDimitry Andric   }
188206c3fb27SDimitry Andric 
188306c3fb27SDimitry Andric   if (!CheckCallable(S, OpPC, Func))
188406c3fb27SDimitry Andric     return false;
188506c3fb27SDimitry Andric 
188606c3fb27SDimitry Andric   if (!CheckCallDepth(S, OpPC))
188706c3fb27SDimitry Andric     return false;
188806c3fb27SDimitry Andric 
188906c3fb27SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
1890bdd1243dSDimitry Andric   InterpFrame *FrameBefore = S.Current;
1891bdd1243dSDimitry Andric   S.Current = NewFrame.get();
1892bdd1243dSDimitry Andric 
1893bdd1243dSDimitry Andric   APValue CallResult;
1894bdd1243dSDimitry Andric   // Note that we cannot assert(CallResult.hasValue()) here since
1895bdd1243dSDimitry Andric   // Ret() above only sets the APValue if the curent frame doesn't
1896bdd1243dSDimitry Andric   // have a caller set.
1897bdd1243dSDimitry Andric   if (Interpret(S, CallResult)) {
1898bdd1243dSDimitry Andric     NewFrame.release(); // Frame was delete'd already.
1899bdd1243dSDimitry Andric     assert(S.Current == FrameBefore);
1900bdd1243dSDimitry Andric     return true;
1901bdd1243dSDimitry Andric   }
1902bdd1243dSDimitry Andric 
1903bdd1243dSDimitry Andric   // Interpreting the function failed somehow. Reset to
1904bdd1243dSDimitry Andric   // previous state.
1905bdd1243dSDimitry Andric   S.Current = FrameBefore;
1906bdd1243dSDimitry Andric   return false;
1907bdd1243dSDimitry Andric }
1908bdd1243dSDimitry Andric 
190906c3fb27SDimitry Andric inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
191006c3fb27SDimitry Andric   assert(Func->hasThisPointer());
191106c3fb27SDimitry Andric   assert(Func->isVirtual());
191206c3fb27SDimitry Andric   size_t ThisOffset =
1913*5f757f3fSDimitry Andric       Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
191406c3fb27SDimitry Andric   Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
191506c3fb27SDimitry Andric 
191606c3fb27SDimitry Andric   const CXXRecordDecl *DynamicDecl =
191706c3fb27SDimitry Andric       ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
191806c3fb27SDimitry Andric   const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
191906c3fb27SDimitry Andric   const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
192006c3fb27SDimitry Andric   const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
192106c3fb27SDimitry Andric       DynamicDecl, StaticDecl, InitialFunction);
192206c3fb27SDimitry Andric 
192306c3fb27SDimitry Andric   if (Overrider != InitialFunction) {
1924*5f757f3fSDimitry Andric     // DR1872: An instantiated virtual constexpr function can't be called in a
1925*5f757f3fSDimitry Andric     // constant expression (prior to C++20). We can still constant-fold such a
1926*5f757f3fSDimitry Andric     // call.
1927*5f757f3fSDimitry Andric     if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
1928*5f757f3fSDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
1929*5f757f3fSDimitry Andric       S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
1930*5f757f3fSDimitry Andric     }
1931*5f757f3fSDimitry Andric 
1932*5f757f3fSDimitry Andric     Func = S.getContext().getOrCreateFunction(Overrider);
193306c3fb27SDimitry Andric 
193406c3fb27SDimitry Andric     const CXXRecordDecl *ThisFieldDecl =
193506c3fb27SDimitry Andric         ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
193606c3fb27SDimitry Andric     if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
193706c3fb27SDimitry Andric       // If the function we call is further DOWN the hierarchy than the
193806c3fb27SDimitry Andric       // FieldDesc of our pointer, just get the DeclDesc instead, which
193906c3fb27SDimitry Andric       // is the furthest we might go up in the hierarchy.
194006c3fb27SDimitry Andric       ThisPtr = ThisPtr.getDeclPtr();
194106c3fb27SDimitry Andric     }
194206c3fb27SDimitry Andric   }
194306c3fb27SDimitry Andric 
194406c3fb27SDimitry Andric   return Call(S, OpPC, Func);
194506c3fb27SDimitry Andric }
194606c3fb27SDimitry Andric 
1947*5f757f3fSDimitry Andric inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
1948*5f757f3fSDimitry Andric                    const CallExpr *CE) {
194906c3fb27SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
195006c3fb27SDimitry Andric 
195106c3fb27SDimitry Andric   InterpFrame *FrameBefore = S.Current;
195206c3fb27SDimitry Andric   S.Current = NewFrame.get();
195306c3fb27SDimitry Andric 
1954*5f757f3fSDimitry Andric   if (InterpretBuiltin(S, PC, Func, CE)) {
195506c3fb27SDimitry Andric     NewFrame.release();
195606c3fb27SDimitry Andric     return true;
195706c3fb27SDimitry Andric   }
195806c3fb27SDimitry Andric   S.Current = FrameBefore;
195906c3fb27SDimitry Andric   return false;
196006c3fb27SDimitry Andric }
196106c3fb27SDimitry Andric 
196206c3fb27SDimitry Andric inline bool CallPtr(InterpState &S, CodePtr OpPC) {
196306c3fb27SDimitry Andric   const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
196406c3fb27SDimitry Andric 
196506c3fb27SDimitry Andric   const Function *F = FuncPtr.getFunction();
196606c3fb27SDimitry Andric   if (!F || !F->isConstexpr())
196706c3fb27SDimitry Andric     return false;
196806c3fb27SDimitry Andric 
1969*5f757f3fSDimitry Andric   if (F->isVirtual())
1970*5f757f3fSDimitry Andric     return CallVirt(S, OpPC, F);
1971*5f757f3fSDimitry Andric 
197206c3fb27SDimitry Andric   return Call(S, OpPC, F);
197306c3fb27SDimitry Andric }
197406c3fb27SDimitry Andric 
197506c3fb27SDimitry Andric inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
197606c3fb27SDimitry Andric   assert(Func);
197706c3fb27SDimitry Andric   S.Stk.push<FunctionPointer>(Func);
197806c3fb27SDimitry Andric   return true;
197906c3fb27SDimitry Andric }
198006c3fb27SDimitry Andric 
1981*5f757f3fSDimitry Andric /// Just emit a diagnostic. The expression that caused emission of this
1982*5f757f3fSDimitry Andric /// op is not valid in a constant context.
1983*5f757f3fSDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC) {
1984*5f757f3fSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
1985*5f757f3fSDimitry Andric   S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
1986*5f757f3fSDimitry Andric       << S.Current->getRange(OpPC);
1987*5f757f3fSDimitry Andric   return false;
1988*5f757f3fSDimitry Andric }
1989*5f757f3fSDimitry Andric 
1990*5f757f3fSDimitry Andric /// Same here, but only for casts.
1991*5f757f3fSDimitry Andric inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
1992*5f757f3fSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
1993*5f757f3fSDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
1994*5f757f3fSDimitry Andric       << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
1995*5f757f3fSDimitry Andric   return false;
1996*5f757f3fSDimitry Andric }
1997*5f757f3fSDimitry Andric 
1998*5f757f3fSDimitry Andric inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
1999*5f757f3fSDimitry Andric                            const DeclRefExpr *DR) {
2000*5f757f3fSDimitry Andric   assert(DR);
2001*5f757f3fSDimitry Andric   return CheckDeclRef(S, OpPC, DR);
2002*5f757f3fSDimitry Andric }
2003*5f757f3fSDimitry Andric 
2004*5f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
2005*5f757f3fSDimitry Andric inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
2006*5f757f3fSDimitry Andric   llvm::SmallVector<int64_t> ArrayIndices;
2007*5f757f3fSDimitry Andric   for (size_t I = 0; I != E->getNumExpressions(); ++I)
2008*5f757f3fSDimitry Andric     ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
2009*5f757f3fSDimitry Andric 
2010*5f757f3fSDimitry Andric   int64_t Result;
2011*5f757f3fSDimitry Andric   if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
2012*5f757f3fSDimitry Andric     return false;
2013*5f757f3fSDimitry Andric 
2014*5f757f3fSDimitry Andric   S.Stk.push<T>(T::from(Result));
2015*5f757f3fSDimitry Andric 
2016*5f757f3fSDimitry Andric   return true;
2017*5f757f3fSDimitry Andric }
2018*5f757f3fSDimitry Andric 
2019349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
2020349cc55cSDimitry Andric // Read opcode arguments
2021349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
2022349cc55cSDimitry Andric 
2023bdd1243dSDimitry Andric template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2024bdd1243dSDimitry Andric   if constexpr (std::is_pointer<T>::value) {
2025349cc55cSDimitry Andric     uint32_t ID = OpPC.read<uint32_t>();
2026349cc55cSDimitry Andric     return reinterpret_cast<T>(S.P.getNativePointer(ID));
2027bdd1243dSDimitry Andric   } else {
2028bdd1243dSDimitry Andric     return OpPC.read<T>();
2029349cc55cSDimitry Andric   }
2030bdd1243dSDimitry Andric }
2031a7dea167SDimitry Andric 
2032*5f757f3fSDimitry Andric template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
2033*5f757f3fSDimitry Andric   Floating F = Floating::deserialize(*OpPC);
2034*5f757f3fSDimitry Andric   OpPC += align(F.bytesToSerialize());
2035*5f757f3fSDimitry Andric   return F;
2036*5f757f3fSDimitry Andric }
2037*5f757f3fSDimitry Andric 
2038a7dea167SDimitry Andric } // namespace interp
2039a7dea167SDimitry Andric } // namespace clang
2040a7dea167SDimitry Andric 
2041a7dea167SDimitry Andric #endif
2042