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 APSInt = llvm::APSInt;
41a7dea167SDimitry Andric 
42349cc55cSDimitry Andric /// Convert a value to an APValue.
ReturnValue(const T & V,APValue & R)43a7dea167SDimitry Andric template <typename T> bool ReturnValue(const T &V, APValue &R) {
44a7dea167SDimitry Andric   R = V.toAPValue();
45a7dea167SDimitry Andric   return true;
46a7dea167SDimitry Andric }
47a7dea167SDimitry Andric 
48a7dea167SDimitry Andric /// Checks if the variable has externally defined storage.
49a7dea167SDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
50a7dea167SDimitry Andric 
51a7dea167SDimitry Andric /// Checks if the array is offsetable.
52a7dea167SDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
53a7dea167SDimitry Andric 
54349cc55cSDimitry Andric /// Checks if a pointer is live and accessible.
55a7dea167SDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
56a7dea167SDimitry Andric                AccessKinds AK);
575f757f3fSDimitry Andric 
585f757f3fSDimitry Andric /// Checks if a pointer is a dummy pointer.
595f757f3fSDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
605f757f3fSDimitry Andric 
61a7dea167SDimitry Andric /// Checks if a pointer is null.
62a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
63a7dea167SDimitry Andric                CheckSubobjectKind CSK);
64a7dea167SDimitry Andric 
65a7dea167SDimitry Andric /// Checks if a pointer is in range.
66a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
67a7dea167SDimitry Andric                 AccessKinds AK);
68a7dea167SDimitry Andric 
69a7dea167SDimitry Andric /// Checks if a field from which a pointer is going to be derived is valid.
70a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
71a7dea167SDimitry Andric                 CheckSubobjectKind CSK);
72a7dea167SDimitry Andric 
735f757f3fSDimitry Andric /// Checks if Ptr is a one-past-the-end pointer.
745f757f3fSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
755f757f3fSDimitry Andric                     CheckSubobjectKind CSK);
765f757f3fSDimitry Andric 
77a7dea167SDimitry Andric /// Checks if a pointer points to const storage.
78a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79a7dea167SDimitry Andric 
80*7a6dacacSDimitry Andric /// Checks if the Descriptor is of a constexpr or const global variable.
81*7a6dacacSDimitry Andric bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
82*7a6dacacSDimitry Andric 
83a7dea167SDimitry Andric /// Checks if a pointer points to a mutable field.
84a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85a7dea167SDimitry Andric 
86a7dea167SDimitry Andric /// Checks if a value can be loaded from a block.
87a7dea167SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
88a7dea167SDimitry Andric 
8906c3fb27SDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
9006c3fb27SDimitry Andric                       AccessKinds AK);
9106c3fb27SDimitry Andric 
92a7dea167SDimitry Andric /// Checks if a value can be stored in a block.
93a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
94a7dea167SDimitry Andric 
95a7dea167SDimitry Andric /// Checks if a method can be invoked on an object.
96a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
97a7dea167SDimitry Andric 
98a7dea167SDimitry Andric /// Checks if a value can be initialized.
99a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
100a7dea167SDimitry Andric 
101a7dea167SDimitry Andric /// Checks if a method can be called.
102bdd1243dSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
103a7dea167SDimitry Andric 
10406c3fb27SDimitry Andric /// Checks if calling the currently active function would exceed
10506c3fb27SDimitry Andric /// the allowed call depth.
10606c3fb27SDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC);
10706c3fb27SDimitry Andric 
108a7dea167SDimitry Andric /// Checks the 'this' pointer.
109a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
110a7dea167SDimitry Andric 
111a7dea167SDimitry Andric /// Checks if a method is pure virtual.
112a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
113a7dea167SDimitry Andric 
1145f757f3fSDimitry Andric /// Checks if reinterpret casts are legal in the current context.
1155f757f3fSDimitry Andric bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
1165f757f3fSDimitry Andric                                    const Pointer &Ptr);
1175f757f3fSDimitry Andric 
1185f757f3fSDimitry Andric /// Sets the given integral value to the pointer, which is of
1195f757f3fSDimitry Andric /// a std::{weak,partial,strong}_ordering type.
1205f757f3fSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
1215f757f3fSDimitry Andric                                 const Pointer &Ptr, const APSInt &IntValue);
1225f757f3fSDimitry Andric 
123bdd1243dSDimitry Andric /// Checks if the shift operation is legal.
12406c3fb27SDimitry Andric template <typename LT, typename RT>
CheckShift(InterpState & S,CodePtr OpPC,const LT & LHS,const RT & RHS,unsigned Bits)12506c3fb27SDimitry Andric bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
12606c3fb27SDimitry Andric                 unsigned Bits) {
127bdd1243dSDimitry Andric   if (RHS.isNegative()) {
128bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
129bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
130bdd1243dSDimitry Andric     return false;
131bdd1243dSDimitry Andric   }
132bdd1243dSDimitry Andric 
133bdd1243dSDimitry Andric   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
134bdd1243dSDimitry Andric   // the shifted type.
135bdd1243dSDimitry Andric   if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
136bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
137bdd1243dSDimitry Andric     const APSInt Val = RHS.toAPSInt();
138bdd1243dSDimitry Andric     QualType Ty = E->getType();
139bdd1243dSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
140bdd1243dSDimitry Andric     return false;
141bdd1243dSDimitry Andric   }
14206c3fb27SDimitry Andric 
14306c3fb27SDimitry Andric   if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
14406c3fb27SDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
14506c3fb27SDimitry Andric     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
14606c3fb27SDimitry Andric     // operand, and must not overflow the corresponding unsigned type.
14706c3fb27SDimitry Andric     if (LHS.isNegative())
14806c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
14906c3fb27SDimitry Andric     else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
15006c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_discards);
15106c3fb27SDimitry Andric   }
15206c3fb27SDimitry Andric 
15306c3fb27SDimitry Andric   // C++2a [expr.shift]p2: [P0907R4]:
15406c3fb27SDimitry Andric   //    E1 << E2 is the unique value congruent to
15506c3fb27SDimitry Andric   //    E1 x 2^E2 module 2^N.
156bdd1243dSDimitry Andric   return true;
157bdd1243dSDimitry Andric }
158bdd1243dSDimitry Andric 
159bdd1243dSDimitry Andric /// Checks if Div/Rem operation on LHS and RHS is valid.
160bdd1243dSDimitry Andric template <typename T>
CheckDivRem(InterpState & S,CodePtr OpPC,const T & LHS,const T & RHS)161bdd1243dSDimitry Andric bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
162bdd1243dSDimitry Andric   if (RHS.isZero()) {
1635f757f3fSDimitry Andric     const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
1645f757f3fSDimitry Andric     S.FFDiag(Op, diag::note_expr_divide_by_zero)
1655f757f3fSDimitry Andric         << Op->getRHS()->getSourceRange();
166bdd1243dSDimitry Andric     return false;
167bdd1243dSDimitry Andric   }
168bdd1243dSDimitry Andric 
169bdd1243dSDimitry Andric   if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
170bdd1243dSDimitry Andric     APSInt LHSInt = LHS.toAPSInt();
171bdd1243dSDimitry Andric     SmallString<32> Trunc;
172bdd1243dSDimitry Andric     (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
173bdd1243dSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
174bdd1243dSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
175bdd1243dSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
176bdd1243dSDimitry Andric     return false;
177bdd1243dSDimitry Andric   }
178bdd1243dSDimitry Andric   return true;
179bdd1243dSDimitry Andric }
180bdd1243dSDimitry Andric 
1815f757f3fSDimitry Andric /// Checks if the result of a floating-point operation is valid
18206c3fb27SDimitry Andric /// in the current context.
1835f757f3fSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
1845f757f3fSDimitry Andric                       APFloat::opStatus Status);
1855f757f3fSDimitry Andric 
1865f757f3fSDimitry Andric /// Checks why the given DeclRefExpr is invalid.
1875f757f3fSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
18806c3fb27SDimitry Andric 
189bdd1243dSDimitry Andric /// Interpreter entry point.
190bdd1243dSDimitry Andric bool Interpret(InterpState &S, APValue &Result);
191a7dea167SDimitry Andric 
19206c3fb27SDimitry Andric /// Interpret a builtin function.
1935f757f3fSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
1945f757f3fSDimitry Andric                       const CallExpr *Call);
1955f757f3fSDimitry Andric 
1965f757f3fSDimitry Andric /// Interpret an offsetof operation.
1975f757f3fSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
1985f757f3fSDimitry Andric                        llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);
19906c3fb27SDimitry Andric 
20006c3fb27SDimitry Andric enum class ArithOp { Add, Sub };
20106c3fb27SDimitry Andric 
20206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
20306c3fb27SDimitry Andric // Returning values
20406c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
20506c3fb27SDimitry Andric 
2065f757f3fSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);
2075f757f3fSDimitry Andric 
2085f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Ret(InterpState & S,CodePtr & PC,APValue & Result)20906c3fb27SDimitry Andric bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
21006c3fb27SDimitry Andric   const T &Ret = S.Stk.pop<T>();
21106c3fb27SDimitry Andric 
2125f757f3fSDimitry Andric   // Make sure returned pointers are live. We might be trying to return a
2135f757f3fSDimitry Andric   // pointer or reference to a local variable.
2145f757f3fSDimitry Andric   // Just return false, since a diagnostic has already been emitted in Sema.
2155f757f3fSDimitry Andric   if constexpr (std::is_same_v<T, Pointer>) {
2165f757f3fSDimitry Andric     // FIXME: We could be calling isLive() here, but the emitted diagnostics
2175f757f3fSDimitry Andric     // seem a little weird, at least if the returned expression is of
2185f757f3fSDimitry Andric     // pointer type.
2195f757f3fSDimitry Andric     // Null pointers are considered live here.
2205f757f3fSDimitry Andric     if (!Ret.isZero() && !Ret.isLive())
2215f757f3fSDimitry Andric       return false;
2225f757f3fSDimitry Andric   }
2235f757f3fSDimitry Andric 
2245f757f3fSDimitry Andric   assert(S.Current);
22506c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
2265f757f3fSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
2275f757f3fSDimitry Andric     cleanupAfterFunctionCall(S, PC);
22806c3fb27SDimitry Andric 
22906c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
23006c3fb27SDimitry Andric     PC = S.Current->getRetPC();
23106c3fb27SDimitry Andric     delete S.Current;
23206c3fb27SDimitry Andric     S.Current = Caller;
23306c3fb27SDimitry Andric     S.Stk.push<T>(Ret);
23406c3fb27SDimitry Andric   } else {
23506c3fb27SDimitry Andric     delete S.Current;
23606c3fb27SDimitry Andric     S.Current = nullptr;
23706c3fb27SDimitry Andric     if (!ReturnValue<T>(Ret, Result))
23806c3fb27SDimitry Andric       return false;
23906c3fb27SDimitry Andric   }
24006c3fb27SDimitry Andric   return true;
24106c3fb27SDimitry Andric }
24206c3fb27SDimitry Andric 
RetVoid(InterpState & S,CodePtr & PC,APValue & Result)24306c3fb27SDimitry Andric inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
24406c3fb27SDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
2455f757f3fSDimitry Andric 
2465f757f3fSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
2475f757f3fSDimitry Andric     cleanupAfterFunctionCall(S, PC);
24806c3fb27SDimitry Andric 
24906c3fb27SDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
25006c3fb27SDimitry Andric     PC = S.Current->getRetPC();
25106c3fb27SDimitry Andric     delete S.Current;
25206c3fb27SDimitry Andric     S.Current = Caller;
25306c3fb27SDimitry Andric   } else {
25406c3fb27SDimitry Andric     delete S.Current;
25506c3fb27SDimitry Andric     S.Current = nullptr;
25606c3fb27SDimitry Andric   }
25706c3fb27SDimitry Andric   return true;
25806c3fb27SDimitry Andric }
25906c3fb27SDimitry Andric 
260a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
261a7dea167SDimitry Andric // Add, Sub, Mul
262a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
263a7dea167SDimitry Andric 
264a7dea167SDimitry Andric template <typename T, bool (*OpFW)(T, T, unsigned, T *),
265a7dea167SDimitry Andric           template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)266a7dea167SDimitry Andric bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
267a7dea167SDimitry Andric                      const T &RHS) {
268a7dea167SDimitry Andric   // Fast path - add the numbers with fixed width.
269a7dea167SDimitry Andric   T Result;
270a7dea167SDimitry Andric   if (!OpFW(LHS, RHS, Bits, &Result)) {
271a7dea167SDimitry Andric     S.Stk.push<T>(Result);
272a7dea167SDimitry Andric     return true;
273a7dea167SDimitry Andric   }
274a7dea167SDimitry Andric 
275a7dea167SDimitry Andric   // If for some reason evaluation continues, use the truncated results.
276a7dea167SDimitry Andric   S.Stk.push<T>(Result);
277a7dea167SDimitry Andric 
278a7dea167SDimitry Andric   // Slow path - compute the result using another bit of precision.
279a7dea167SDimitry Andric   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
280a7dea167SDimitry Andric 
281a7dea167SDimitry Andric   // Report undefined behaviour, stopping if required.
282a7dea167SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
283a7dea167SDimitry Andric   QualType Type = E->getType();
284a7dea167SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
285fe6060f1SDimitry Andric     SmallString<32> Trunc;
286fe6060f1SDimitry Andric     Value.trunc(Result.bitWidth()).toString(Trunc, 10);
287a7dea167SDimitry Andric     auto Loc = E->getExprLoc();
2885f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
2895f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
290a7dea167SDimitry Andric     return true;
291a7dea167SDimitry Andric   } else {
292a7dea167SDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
2935f757f3fSDimitry Andric     if (!S.noteUndefinedBehavior()) {
2945f757f3fSDimitry Andric       S.Stk.pop<T>();
2955f757f3fSDimitry Andric       return false;
2965f757f3fSDimitry Andric     }
2975f757f3fSDimitry Andric     return true;
298a7dea167SDimitry Andric   }
299a7dea167SDimitry Andric }
300a7dea167SDimitry Andric 
301a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)302a7dea167SDimitry Andric bool Add(InterpState &S, CodePtr OpPC) {
303a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
304a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
305a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
306a7dea167SDimitry Andric   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
307a7dea167SDimitry Andric }
308a7dea167SDimitry Andric 
Addf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)30906c3fb27SDimitry Andric inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
31006c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
31106c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
31206c3fb27SDimitry Andric 
31306c3fb27SDimitry Andric   Floating Result;
31406c3fb27SDimitry Andric   auto Status = Floating::add(LHS, RHS, RM, &Result);
31506c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
3165f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
31706c3fb27SDimitry Andric }
31806c3fb27SDimitry Andric 
319a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)320a7dea167SDimitry Andric bool Sub(InterpState &S, CodePtr OpPC) {
321a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
322a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
323a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
324a7dea167SDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
325a7dea167SDimitry Andric }
326a7dea167SDimitry Andric 
Subf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)32706c3fb27SDimitry Andric inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
32806c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
32906c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
33006c3fb27SDimitry Andric 
33106c3fb27SDimitry Andric   Floating Result;
33206c3fb27SDimitry Andric   auto Status = Floating::sub(LHS, RHS, RM, &Result);
33306c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
3345f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
33506c3fb27SDimitry Andric }
33606c3fb27SDimitry Andric 
337a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)338a7dea167SDimitry Andric bool Mul(InterpState &S, CodePtr OpPC) {
339a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
340a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
341a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
342a7dea167SDimitry Andric   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
343a7dea167SDimitry Andric }
344a7dea167SDimitry Andric 
Mulf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)34506c3fb27SDimitry Andric inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
34606c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
34706c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
34806c3fb27SDimitry Andric 
34906c3fb27SDimitry Andric   Floating Result;
35006c3fb27SDimitry Andric   auto Status = Floating::mul(LHS, RHS, RM, &Result);
35106c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
3525f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
35306c3fb27SDimitry Andric }
354bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
355bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
356bdd1243dSDimitry Andric /// 3) Pushes 'LHS & RHS' on the stack
357bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
BitAnd(InterpState & S,CodePtr OpPC)358bdd1243dSDimitry Andric bool BitAnd(InterpState &S, CodePtr OpPC) {
359bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
360bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
361bdd1243dSDimitry Andric 
362bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
363bdd1243dSDimitry Andric   T Result;
364bdd1243dSDimitry Andric   if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
365bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
366bdd1243dSDimitry Andric     return true;
367bdd1243dSDimitry Andric   }
368bdd1243dSDimitry Andric   return false;
369bdd1243dSDimitry Andric }
370bdd1243dSDimitry Andric 
371bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
372bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
373bdd1243dSDimitry Andric /// 3) Pushes 'LHS | RHS' on the stack
374bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
BitOr(InterpState & S,CodePtr OpPC)375bdd1243dSDimitry Andric bool BitOr(InterpState &S, CodePtr OpPC) {
376bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
377bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
378bdd1243dSDimitry Andric 
379bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
380bdd1243dSDimitry Andric   T Result;
381bdd1243dSDimitry Andric   if (!T::bitOr(LHS, RHS, Bits, &Result)) {
382bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
383bdd1243dSDimitry Andric     return true;
384bdd1243dSDimitry Andric   }
385bdd1243dSDimitry Andric   return false;
386bdd1243dSDimitry Andric }
387bdd1243dSDimitry Andric 
388bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
389bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
390bdd1243dSDimitry Andric /// 3) Pushes 'LHS ^ RHS' on the stack
391bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
BitXor(InterpState & S,CodePtr OpPC)392bdd1243dSDimitry Andric bool BitXor(InterpState &S, CodePtr OpPC) {
393bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
394bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
395bdd1243dSDimitry Andric 
396bdd1243dSDimitry Andric   unsigned Bits = RHS.bitWidth();
397bdd1243dSDimitry Andric   T Result;
398bdd1243dSDimitry Andric   if (!T::bitXor(LHS, RHS, Bits, &Result)) {
399bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
400bdd1243dSDimitry Andric     return true;
401bdd1243dSDimitry Andric   }
402bdd1243dSDimitry Andric   return false;
403bdd1243dSDimitry Andric }
404bdd1243dSDimitry Andric 
405bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
406bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
407bdd1243dSDimitry Andric /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
408bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Rem(InterpState & S,CodePtr OpPC)409bdd1243dSDimitry Andric bool Rem(InterpState &S, CodePtr OpPC) {
410bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
411bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
412bdd1243dSDimitry Andric 
413bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
414bdd1243dSDimitry Andric     return false;
415bdd1243dSDimitry Andric 
416bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
417bdd1243dSDimitry Andric   T Result;
418bdd1243dSDimitry Andric   if (!T::rem(LHS, RHS, Bits, &Result)) {
419bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
420bdd1243dSDimitry Andric     return true;
421bdd1243dSDimitry Andric   }
422bdd1243dSDimitry Andric   return false;
423bdd1243dSDimitry Andric }
424bdd1243dSDimitry Andric 
425bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack.
426bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack.
427bdd1243dSDimitry Andric /// 3) Pushes 'LHS / RHS' on the stack
428bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Div(InterpState & S,CodePtr OpPC)429bdd1243dSDimitry Andric bool Div(InterpState &S, CodePtr OpPC) {
430bdd1243dSDimitry Andric   const T &RHS = S.Stk.pop<T>();
431bdd1243dSDimitry Andric   const T &LHS = S.Stk.pop<T>();
432bdd1243dSDimitry Andric 
433bdd1243dSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
434bdd1243dSDimitry Andric     return false;
435bdd1243dSDimitry Andric 
436bdd1243dSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
437bdd1243dSDimitry Andric   T Result;
438bdd1243dSDimitry Andric   if (!T::div(LHS, RHS, Bits, &Result)) {
439bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
440bdd1243dSDimitry Andric     return true;
441bdd1243dSDimitry Andric   }
442bdd1243dSDimitry Andric   return false;
443bdd1243dSDimitry Andric }
444bdd1243dSDimitry Andric 
Divf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)44506c3fb27SDimitry Andric inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
44606c3fb27SDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
44706c3fb27SDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
44806c3fb27SDimitry Andric 
44906c3fb27SDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
45006c3fb27SDimitry Andric     return false;
45106c3fb27SDimitry Andric 
45206c3fb27SDimitry Andric   Floating Result;
45306c3fb27SDimitry Andric   auto Status = Floating::div(LHS, RHS, RM, &Result);
45406c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
4555f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
45606c3fb27SDimitry Andric }
45706c3fb27SDimitry Andric 
458bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
459bdd1243dSDimitry Andric // Inv
460bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
461bdd1243dSDimitry Andric 
462bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Inv(InterpState & S,CodePtr OpPC)463bdd1243dSDimitry Andric bool Inv(InterpState &S, CodePtr OpPC) {
464bdd1243dSDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
465bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
466bdd1243dSDimitry Andric   const unsigned Bits = Val.bitWidth();
467bdd1243dSDimitry Andric   Boolean R;
468bdd1243dSDimitry Andric   Boolean::inv(BoolT::from(Val, Bits), &R);
469bdd1243dSDimitry Andric 
470bdd1243dSDimitry Andric   S.Stk.push<BoolT>(R);
471bdd1243dSDimitry Andric   return true;
472bdd1243dSDimitry Andric }
473bdd1243dSDimitry Andric 
474bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
475bdd1243dSDimitry Andric // Neg
476bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
477bdd1243dSDimitry Andric 
478bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Neg(InterpState & S,CodePtr OpPC)479bdd1243dSDimitry Andric bool Neg(InterpState &S, CodePtr OpPC) {
48006c3fb27SDimitry Andric   const T &Value = S.Stk.pop<T>();
481bdd1243dSDimitry Andric   T Result;
482bdd1243dSDimitry Andric 
48306c3fb27SDimitry Andric   if (!T::neg(Value, &Result)) {
484bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
485bdd1243dSDimitry Andric     return true;
486bdd1243dSDimitry Andric   }
487bdd1243dSDimitry Andric 
48806c3fb27SDimitry Andric   assert(isIntegralType(Name) &&
48906c3fb27SDimitry Andric          "don't expect other types to fail at constexpr negation");
49006c3fb27SDimitry Andric   S.Stk.push<T>(Result);
49106c3fb27SDimitry Andric 
49206c3fb27SDimitry Andric   APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
49306c3fb27SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
49406c3fb27SDimitry Andric   QualType Type = E->getType();
49506c3fb27SDimitry Andric 
49606c3fb27SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
49706c3fb27SDimitry Andric     SmallString<32> Trunc;
49806c3fb27SDimitry Andric     NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10);
49906c3fb27SDimitry Andric     auto Loc = E->getExprLoc();
5005f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
5015f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
50206c3fb27SDimitry Andric     return true;
50306c3fb27SDimitry Andric   }
50406c3fb27SDimitry Andric 
50506c3fb27SDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
50606c3fb27SDimitry Andric   return S.noteUndefinedBehavior();
50706c3fb27SDimitry Andric }
50806c3fb27SDimitry Andric 
509bdd1243dSDimitry Andric enum class PushVal : bool {
510bdd1243dSDimitry Andric   No,
511bdd1243dSDimitry Andric   Yes,
512bdd1243dSDimitry Andric };
513bdd1243dSDimitry Andric enum class IncDecOp {
514bdd1243dSDimitry Andric   Inc,
515bdd1243dSDimitry Andric   Dec,
516bdd1243dSDimitry Andric };
517bdd1243dSDimitry Andric 
518bdd1243dSDimitry Andric template <typename T, IncDecOp Op, PushVal DoPush>
IncDecHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)519bdd1243dSDimitry Andric bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
5205f757f3fSDimitry Andric   const T &Value = Ptr.deref<T>();
521bdd1243dSDimitry Andric   T Result;
522bdd1243dSDimitry Andric 
523bdd1243dSDimitry Andric   if constexpr (DoPush == PushVal::Yes)
52406c3fb27SDimitry Andric     S.Stk.push<T>(Value);
525bdd1243dSDimitry Andric 
526bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc) {
527bdd1243dSDimitry Andric     if (!T::increment(Value, &Result)) {
528bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
529bdd1243dSDimitry Andric       return true;
530bdd1243dSDimitry Andric     }
531bdd1243dSDimitry Andric   } else {
532bdd1243dSDimitry Andric     if (!T::decrement(Value, &Result)) {
533bdd1243dSDimitry Andric       Ptr.deref<T>() = Result;
534bdd1243dSDimitry Andric       return true;
535bdd1243dSDimitry Andric     }
536bdd1243dSDimitry Andric   }
537bdd1243dSDimitry Andric 
538bdd1243dSDimitry Andric   // Something went wrong with the previous operation. Compute the
539bdd1243dSDimitry Andric   // result with another bit of precision.
540bdd1243dSDimitry Andric   unsigned Bits = Value.bitWidth() + 1;
541bdd1243dSDimitry Andric   APSInt APResult;
542bdd1243dSDimitry Andric   if constexpr (Op == IncDecOp::Inc)
543bdd1243dSDimitry Andric     APResult = ++Value.toAPSInt(Bits);
544bdd1243dSDimitry Andric   else
545bdd1243dSDimitry Andric     APResult = --Value.toAPSInt(Bits);
546bdd1243dSDimitry Andric 
547bdd1243dSDimitry Andric   // Report undefined behaviour, stopping if required.
548bdd1243dSDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
549bdd1243dSDimitry Andric   QualType Type = E->getType();
550bdd1243dSDimitry Andric   if (S.checkingForUndefinedBehavior()) {
551bdd1243dSDimitry Andric     SmallString<32> Trunc;
552bdd1243dSDimitry Andric     APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
553bdd1243dSDimitry Andric     auto Loc = E->getExprLoc();
5545f757f3fSDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow)
5555f757f3fSDimitry Andric         << Trunc << Type << E->getSourceRange();
556bdd1243dSDimitry Andric     return true;
557bdd1243dSDimitry Andric   }
558bdd1243dSDimitry Andric 
559bdd1243dSDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
560bdd1243dSDimitry Andric   return S.noteUndefinedBehavior();
561bdd1243dSDimitry Andric }
562bdd1243dSDimitry Andric 
563bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
564bdd1243dSDimitry Andric /// 2) Load the value from the pointer
565bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
566bdd1243dSDimitry Andric /// 4) Pushes the original (pre-inc) value on the stack.
567bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Inc(InterpState & S,CodePtr OpPC)568bdd1243dSDimitry Andric bool Inc(InterpState &S, CodePtr OpPC) {
569bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
570bdd1243dSDimitry Andric 
57106c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
57206c3fb27SDimitry Andric     return false;
57306c3fb27SDimitry Andric 
574bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
575bdd1243dSDimitry Andric }
576bdd1243dSDimitry Andric 
577bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
578bdd1243dSDimitry Andric /// 2) Load the value from the pointer
579bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer
580bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
IncPop(InterpState & S,CodePtr OpPC)581bdd1243dSDimitry Andric bool IncPop(InterpState &S, CodePtr OpPC) {
582bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
583bdd1243dSDimitry Andric 
58406c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
58506c3fb27SDimitry Andric     return false;
58606c3fb27SDimitry Andric 
587bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
588bdd1243dSDimitry Andric }
589bdd1243dSDimitry Andric 
590bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
591bdd1243dSDimitry Andric /// 2) Load the value from the pointer
592bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
593bdd1243dSDimitry Andric /// 4) Pushes the original (pre-dec) value on the stack.
594bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Dec(InterpState & S,CodePtr OpPC)595bdd1243dSDimitry Andric bool Dec(InterpState &S, CodePtr OpPC) {
596bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
597bdd1243dSDimitry Andric 
59806c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
59906c3fb27SDimitry Andric     return false;
60006c3fb27SDimitry Andric 
601bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
602bdd1243dSDimitry Andric }
603bdd1243dSDimitry Andric 
604bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
605bdd1243dSDimitry Andric /// 2) Load the value from the pointer
606bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
607bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
DecPop(InterpState & S,CodePtr OpPC)608bdd1243dSDimitry Andric bool DecPop(InterpState &S, CodePtr OpPC) {
609bdd1243dSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
610bdd1243dSDimitry Andric 
61106c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
61206c3fb27SDimitry Andric     return false;
61306c3fb27SDimitry Andric 
614bdd1243dSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
615bdd1243dSDimitry Andric }
616bdd1243dSDimitry Andric 
61706c3fb27SDimitry Andric template <IncDecOp Op, PushVal DoPush>
IncDecFloatHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr,llvm::RoundingMode RM)61806c3fb27SDimitry Andric bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
61906c3fb27SDimitry Andric                        llvm::RoundingMode RM) {
62006c3fb27SDimitry Andric   Floating Value = Ptr.deref<Floating>();
62106c3fb27SDimitry Andric   Floating Result;
62206c3fb27SDimitry Andric 
62306c3fb27SDimitry Andric   if constexpr (DoPush == PushVal::Yes)
62406c3fb27SDimitry Andric     S.Stk.push<Floating>(Value);
62506c3fb27SDimitry Andric 
62606c3fb27SDimitry Andric   llvm::APFloat::opStatus Status;
62706c3fb27SDimitry Andric   if constexpr (Op == IncDecOp::Inc)
62806c3fb27SDimitry Andric     Status = Floating::increment(Value, RM, &Result);
62906c3fb27SDimitry Andric   else
63006c3fb27SDimitry Andric     Status = Floating::decrement(Value, RM, &Result);
63106c3fb27SDimitry Andric 
63206c3fb27SDimitry Andric   Ptr.deref<Floating>() = Result;
63306c3fb27SDimitry Andric 
6345f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
63506c3fb27SDimitry Andric }
63606c3fb27SDimitry Andric 
Incf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)63706c3fb27SDimitry Andric inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
63806c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
63906c3fb27SDimitry Andric 
64006c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
64106c3fb27SDimitry Andric     return false;
64206c3fb27SDimitry Andric 
64306c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
64406c3fb27SDimitry Andric }
64506c3fb27SDimitry Andric 
IncfPop(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)64606c3fb27SDimitry Andric inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
64706c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
64806c3fb27SDimitry Andric 
64906c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
65006c3fb27SDimitry Andric     return false;
65106c3fb27SDimitry Andric 
65206c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
65306c3fb27SDimitry Andric }
65406c3fb27SDimitry Andric 
Decf(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)65506c3fb27SDimitry Andric inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
65606c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
65706c3fb27SDimitry Andric 
65806c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
65906c3fb27SDimitry Andric     return false;
66006c3fb27SDimitry Andric 
66106c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
66206c3fb27SDimitry Andric }
66306c3fb27SDimitry Andric 
DecfPop(InterpState & S,CodePtr OpPC,llvm::RoundingMode RM)66406c3fb27SDimitry Andric inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
66506c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
66606c3fb27SDimitry Andric 
66706c3fb27SDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
66806c3fb27SDimitry Andric     return false;
66906c3fb27SDimitry Andric 
67006c3fb27SDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
67106c3fb27SDimitry Andric }
67206c3fb27SDimitry Andric 
673bdd1243dSDimitry Andric /// 1) Pops the value from the stack.
674bdd1243dSDimitry Andric /// 2) Pushes the bitwise complemented value on the stack (~V).
675bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Comp(InterpState & S,CodePtr OpPC)676bdd1243dSDimitry Andric bool Comp(InterpState &S, CodePtr OpPC) {
677bdd1243dSDimitry Andric   const T &Val = S.Stk.pop<T>();
678bdd1243dSDimitry Andric   T Result;
679bdd1243dSDimitry Andric   if (!T::comp(Val, &Result)) {
680bdd1243dSDimitry Andric     S.Stk.push<T>(Result);
681bdd1243dSDimitry Andric     return true;
682bdd1243dSDimitry Andric   }
683bdd1243dSDimitry Andric 
684bdd1243dSDimitry Andric   return false;
685bdd1243dSDimitry Andric }
686bdd1243dSDimitry Andric 
687a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
688a7dea167SDimitry Andric // EQ, NE, GT, GE, LT, LE
689a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
690a7dea167SDimitry Andric 
691a7dea167SDimitry Andric using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
692a7dea167SDimitry Andric 
693a7dea167SDimitry Andric template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)694a7dea167SDimitry Andric bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
695a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
696a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
697a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
698a7dea167SDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
699a7dea167SDimitry Andric   return true;
700a7dea167SDimitry Andric }
701a7dea167SDimitry Andric 
702a7dea167SDimitry Andric template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)703a7dea167SDimitry Andric bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
704a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, Fn);
705a7dea167SDimitry Andric }
706a7dea167SDimitry Andric 
70706c3fb27SDimitry Andric /// Function pointers cannot be compared in an ordered way.
70806c3fb27SDimitry Andric template <>
70906c3fb27SDimitry Andric inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
71006c3fb27SDimitry Andric                                        CompareFn Fn) {
71106c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
71206c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
71306c3fb27SDimitry Andric 
71406c3fb27SDimitry Andric   const SourceInfo &Loc = S.Current->getSource(OpPC);
71506c3fb27SDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
71606c3fb27SDimitry Andric       << LHS.toDiagnosticString(S.getCtx())
71706c3fb27SDimitry Andric       << RHS.toDiagnosticString(S.getCtx());
71806c3fb27SDimitry Andric   return false;
71906c3fb27SDimitry Andric }
72006c3fb27SDimitry Andric 
72106c3fb27SDimitry Andric template <>
72206c3fb27SDimitry Andric inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
72306c3fb27SDimitry Andric                                          CompareFn Fn) {
72406c3fb27SDimitry Andric   const auto &RHS = S.Stk.pop<FunctionPointer>();
72506c3fb27SDimitry Andric   const auto &LHS = S.Stk.pop<FunctionPointer>();
72606c3fb27SDimitry Andric   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
72706c3fb27SDimitry Andric   return true;
72806c3fb27SDimitry Andric }
72906c3fb27SDimitry Andric 
730a7dea167SDimitry Andric template <>
731a7dea167SDimitry Andric inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
732a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
733a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
734a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
735a7dea167SDimitry Andric 
736a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
737a7dea167SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
7385f757f3fSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
7395f757f3fSDimitry Andric         << LHS.toDiagnosticString(S.getCtx())
7405f757f3fSDimitry Andric         << RHS.toDiagnosticString(S.getCtx());
741a7dea167SDimitry Andric     return false;
742a7dea167SDimitry Andric   } else {
743a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
744a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
745a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
746a7dea167SDimitry Andric     return true;
747a7dea167SDimitry Andric   }
748a7dea167SDimitry Andric }
749a7dea167SDimitry Andric 
750a7dea167SDimitry Andric template <>
751a7dea167SDimitry Andric inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
752a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
753a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
754a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
755a7dea167SDimitry Andric 
756480093f4SDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
757a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
758a7dea167SDimitry Andric     return true;
759a7dea167SDimitry Andric   }
760a7dea167SDimitry Andric 
761a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
762a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
763a7dea167SDimitry Andric     return true;
764a7dea167SDimitry Andric   } else {
765a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
766a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
767bdd1243dSDimitry Andric 
768bdd1243dSDimitry Andric     // In our Pointer class, a pointer to an array and a pointer to the first
769bdd1243dSDimitry Andric     // element in the same array are NOT equal. They have the same Base value,
770bdd1243dSDimitry Andric     // but a different Offset. This is a pretty rare case, so we fix this here
771bdd1243dSDimitry Andric     // by comparing pointers to the first elements.
7725f757f3fSDimitry Andric     if (LHS.isArrayRoot())
773bdd1243dSDimitry Andric       VL = LHS.atIndex(0).getByteOffset();
7745f757f3fSDimitry Andric     if (RHS.isArrayRoot())
775bdd1243dSDimitry Andric       VR = RHS.atIndex(0).getByteOffset();
776bdd1243dSDimitry Andric 
777a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
778a7dea167SDimitry Andric     return true;
779a7dea167SDimitry Andric   }
780a7dea167SDimitry Andric }
781a7dea167SDimitry Andric 
782a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)783a7dea167SDimitry Andric bool EQ(InterpState &S, CodePtr OpPC) {
784a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
785a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Equal;
786a7dea167SDimitry Andric   });
787a7dea167SDimitry Andric }
788a7dea167SDimitry Andric 
789a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CMP3(InterpState & S,CodePtr OpPC,const ComparisonCategoryInfo * CmpInfo)7905f757f3fSDimitry Andric bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
7915f757f3fSDimitry Andric   const T &RHS = S.Stk.pop<T>();
7925f757f3fSDimitry Andric   const T &LHS = S.Stk.pop<T>();
7935f757f3fSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
7945f757f3fSDimitry Andric 
7955f757f3fSDimitry Andric   ComparisonCategoryResult CmpResult = LHS.compare(RHS);
7965f757f3fSDimitry Andric   if (CmpResult == ComparisonCategoryResult::Unordered) {
7975f757f3fSDimitry Andric     // This should only happen with pointers.
7985f757f3fSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
7995f757f3fSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
8005f757f3fSDimitry Andric         << LHS.toDiagnosticString(S.getCtx())
8015f757f3fSDimitry Andric         << RHS.toDiagnosticString(S.getCtx());
8025f757f3fSDimitry Andric     return false;
8035f757f3fSDimitry Andric   }
8045f757f3fSDimitry Andric 
8055f757f3fSDimitry Andric   assert(CmpInfo);
8065f757f3fSDimitry Andric   const auto *CmpValueInfo = CmpInfo->getValueInfo(CmpResult);
8075f757f3fSDimitry Andric   assert(CmpValueInfo);
8085f757f3fSDimitry Andric   assert(CmpValueInfo->hasValidIntValue());
8095f757f3fSDimitry Andric   APSInt IntValue = CmpValueInfo->getIntValue();
8105f757f3fSDimitry Andric   return SetThreeWayComparisonField(S, OpPC, P, IntValue);
8115f757f3fSDimitry Andric }
8125f757f3fSDimitry Andric 
8135f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)814a7dea167SDimitry Andric bool NE(InterpState &S, CodePtr OpPC) {
815a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
816a7dea167SDimitry Andric     return R != ComparisonCategoryResult::Equal;
817a7dea167SDimitry Andric   });
818a7dea167SDimitry Andric }
819a7dea167SDimitry Andric 
820a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)821a7dea167SDimitry Andric bool LT(InterpState &S, CodePtr OpPC) {
822a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
823a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less;
824a7dea167SDimitry Andric   });
825a7dea167SDimitry Andric }
826a7dea167SDimitry Andric 
827a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)828a7dea167SDimitry Andric bool LE(InterpState &S, CodePtr OpPC) {
829a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
830a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less ||
831a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
832a7dea167SDimitry Andric   });
833a7dea167SDimitry Andric }
834a7dea167SDimitry Andric 
835a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)836a7dea167SDimitry Andric bool GT(InterpState &S, CodePtr OpPC) {
837a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
838a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater;
839a7dea167SDimitry Andric   });
840a7dea167SDimitry Andric }
841a7dea167SDimitry Andric 
842a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)843a7dea167SDimitry Andric bool GE(InterpState &S, CodePtr OpPC) {
844a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
845a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater ||
846a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
847a7dea167SDimitry Andric   });
848a7dea167SDimitry Andric }
849a7dea167SDimitry Andric 
850a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
851a7dea167SDimitry Andric // InRange
852a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
853a7dea167SDimitry Andric 
854a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InRange(InterpState & S,CodePtr OpPC)855a7dea167SDimitry Andric bool InRange(InterpState &S, CodePtr OpPC) {
856a7dea167SDimitry Andric   const T RHS = S.Stk.pop<T>();
857a7dea167SDimitry Andric   const T LHS = S.Stk.pop<T>();
858a7dea167SDimitry Andric   const T Value = S.Stk.pop<T>();
859a7dea167SDimitry Andric 
860a7dea167SDimitry Andric   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
861a7dea167SDimitry Andric   return true;
862a7dea167SDimitry Andric }
863a7dea167SDimitry Andric 
864a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
865a7dea167SDimitry Andric // Dup, Pop, Test
866a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
867a7dea167SDimitry Andric 
868a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)869a7dea167SDimitry Andric bool Dup(InterpState &S, CodePtr OpPC) {
870a7dea167SDimitry Andric   S.Stk.push<T>(S.Stk.peek<T>());
871a7dea167SDimitry Andric   return true;
872a7dea167SDimitry Andric }
873a7dea167SDimitry Andric 
874a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)875a7dea167SDimitry Andric bool Pop(InterpState &S, CodePtr OpPC) {
876a7dea167SDimitry Andric   S.Stk.pop<T>();
877a7dea167SDimitry Andric   return true;
878a7dea167SDimitry Andric }
879a7dea167SDimitry Andric 
880a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
881a7dea167SDimitry Andric // Const
882a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
883a7dea167SDimitry Andric 
884a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)885a7dea167SDimitry Andric bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
886a7dea167SDimitry Andric   S.Stk.push<T>(Arg);
887a7dea167SDimitry Andric   return true;
888a7dea167SDimitry Andric }
889a7dea167SDimitry Andric 
890a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
891a7dea167SDimitry Andric // Get/Set Local/Param/Global/This
892a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
893a7dea167SDimitry Andric 
894a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)895a7dea167SDimitry Andric bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
896bdd1243dSDimitry Andric   const Pointer &Ptr = S.Current->getLocalPointer(I);
897bdd1243dSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
898bdd1243dSDimitry Andric     return false;
899bdd1243dSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
900a7dea167SDimitry Andric   return true;
901a7dea167SDimitry Andric }
902a7dea167SDimitry Andric 
90306c3fb27SDimitry Andric /// 1) Pops the value from the stack.
90406c3fb27SDimitry Andric /// 2) Writes the value to the local variable with the
90506c3fb27SDimitry Andric ///    given offset.
906a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)907a7dea167SDimitry Andric bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
908a7dea167SDimitry Andric   S.Current->setLocal<T>(I, S.Stk.pop<T>());
909a7dea167SDimitry Andric   return true;
910a7dea167SDimitry Andric }
911a7dea167SDimitry Andric 
912a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)913a7dea167SDimitry Andric bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
914a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
915a7dea167SDimitry Andric     return false;
916a7dea167SDimitry Andric   }
917a7dea167SDimitry Andric   S.Stk.push<T>(S.Current->getParam<T>(I));
918a7dea167SDimitry Andric   return true;
919a7dea167SDimitry Andric }
920a7dea167SDimitry Andric 
921a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)922a7dea167SDimitry Andric bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
923a7dea167SDimitry Andric   S.Current->setParam<T>(I, S.Stk.pop<T>());
924a7dea167SDimitry Andric   return true;
925a7dea167SDimitry Andric }
926a7dea167SDimitry Andric 
927bdd1243dSDimitry Andric /// 1) Peeks a pointer on the stack
928bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
929a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)930a7dea167SDimitry Andric bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
931a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
932a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
933a7dea167SDimitry Andric       return false;
934a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
935a7dea167SDimitry Andric     return false;
936a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
937a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
938a7dea167SDimitry Andric     return false;
939a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
940a7dea167SDimitry Andric   return true;
941a7dea167SDimitry Andric }
942a7dea167SDimitry Andric 
943a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)944a7dea167SDimitry Andric bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
945a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
946a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
947a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
948a7dea167SDimitry Andric     return false;
949a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
950a7dea167SDimitry Andric     return false;
951a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
952a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
953a7dea167SDimitry Andric     return false;
95406c3fb27SDimitry Andric   Field.initialize();
955a7dea167SDimitry Andric   Field.deref<T>() = Value;
956a7dea167SDimitry Andric   return true;
957a7dea167SDimitry Andric }
958a7dea167SDimitry Andric 
959bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack
960bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
961a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)962a7dea167SDimitry Andric bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
963a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.pop<Pointer>();
964a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
965a7dea167SDimitry Andric     return false;
966a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
967a7dea167SDimitry Andric     return false;
968a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
969a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
970a7dea167SDimitry Andric     return false;
971a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
972a7dea167SDimitry Andric   return true;
973a7dea167SDimitry Andric }
974a7dea167SDimitry Andric 
975a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)976a7dea167SDimitry Andric bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
977a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
978a7dea167SDimitry Andric     return false;
979a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
980a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
981a7dea167SDimitry Andric     return false;
982a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
983a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
984a7dea167SDimitry Andric     return false;
985a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
986a7dea167SDimitry Andric   return true;
987a7dea167SDimitry Andric }
988a7dea167SDimitry Andric 
989a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)990a7dea167SDimitry Andric bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
991a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
992a7dea167SDimitry Andric     return false;
993a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
994a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
995a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
996a7dea167SDimitry Andric     return false;
997a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
998a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
999a7dea167SDimitry Andric     return false;
1000a7dea167SDimitry Andric   Field.deref<T>() = Value;
1001a7dea167SDimitry Andric   return true;
1002a7dea167SDimitry Andric }
1003a7dea167SDimitry Andric 
1004a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1005a7dea167SDimitry Andric bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
10065f757f3fSDimitry Andric   const Block *B = S.P.getGlobal(I);
1007*7a6dacacSDimitry Andric 
1008*7a6dacacSDimitry Andric   if (!CheckConstant(S, OpPC, B->getDescriptor()))
1009*7a6dacacSDimitry Andric     return false;
1010a7dea167SDimitry Andric   if (B->isExtern())
1011a7dea167SDimitry Andric     return false;
1012a7dea167SDimitry Andric   S.Stk.push<T>(B->deref<T>());
1013a7dea167SDimitry Andric   return true;
1014a7dea167SDimitry Andric }
1015a7dea167SDimitry Andric 
1016*7a6dacacSDimitry Andric /// Same as GetGlobal, but without the checks.
1017*7a6dacacSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobalUnchecked(InterpState & S,CodePtr OpPC,uint32_t I)1018*7a6dacacSDimitry Andric bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1019*7a6dacacSDimitry Andric   auto *B = S.P.getGlobal(I);
1020*7a6dacacSDimitry Andric   S.Stk.push<T>(B->deref<T>());
1021*7a6dacacSDimitry Andric   return true;
1022*7a6dacacSDimitry Andric }
1023*7a6dacacSDimitry Andric 
1024a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1025a7dea167SDimitry Andric bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1026a7dea167SDimitry Andric   // TODO: emit warning.
1027a7dea167SDimitry Andric   return false;
1028a7dea167SDimitry Andric }
1029a7dea167SDimitry Andric 
1030a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1031a7dea167SDimitry Andric bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1032a7dea167SDimitry Andric   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
1033a7dea167SDimitry Andric   return true;
1034a7dea167SDimitry Andric }
1035a7dea167SDimitry Andric 
103606c3fb27SDimitry Andric /// 1) Converts the value on top of the stack to an APValue
103706c3fb27SDimitry Andric /// 2) Sets that APValue on \Temp
103806c3fb27SDimitry Andric /// 3) Initialized global with index \I with that
103906c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobalTemp(InterpState & S,CodePtr OpPC,uint32_t I,const LifetimeExtendedTemporaryDecl * Temp)104006c3fb27SDimitry Andric bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
104106c3fb27SDimitry Andric                     const LifetimeExtendedTemporaryDecl *Temp) {
104206c3fb27SDimitry Andric   assert(Temp);
104306c3fb27SDimitry Andric   const T Value = S.Stk.peek<T>();
104406c3fb27SDimitry Andric   APValue APV = Value.toAPValue();
104506c3fb27SDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
104606c3fb27SDimitry Andric   *Cached = APV;
104706c3fb27SDimitry Andric 
104806c3fb27SDimitry Andric   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
104906c3fb27SDimitry Andric   return true;
105006c3fb27SDimitry Andric }
105106c3fb27SDimitry Andric 
10525f757f3fSDimitry Andric /// 1) Converts the value on top of the stack to an APValue
10535f757f3fSDimitry Andric /// 2) Sets that APValue on \Temp
10545f757f3fSDimitry Andric /// 3) Initialized global with index \I with that
InitGlobalTempComp(InterpState & S,CodePtr OpPC,const LifetimeExtendedTemporaryDecl * Temp)10555f757f3fSDimitry Andric inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
10565f757f3fSDimitry Andric                                const LifetimeExtendedTemporaryDecl *Temp) {
10575f757f3fSDimitry Andric   assert(Temp);
10585f757f3fSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
10595f757f3fSDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
10605f757f3fSDimitry Andric 
1061*7a6dacacSDimitry Andric   if (std::optional<APValue> APV = P.toRValue(S.getCtx())) {
1062*7a6dacacSDimitry Andric     *Cached = *APV;
10635f757f3fSDimitry Andric     return true;
10645f757f3fSDimitry Andric   }
10655f757f3fSDimitry Andric 
1066*7a6dacacSDimitry Andric   return false;
1067*7a6dacacSDimitry Andric }
1068*7a6dacacSDimitry Andric 
1069a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)1070a7dea167SDimitry Andric bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
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(I);
1077a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1078a7dea167SDimitry Andric   Field.initialize();
1079a7dea167SDimitry Andric   return true;
1080a7dea167SDimitry Andric }
1081a7dea167SDimitry Andric 
1082*7a6dacacSDimitry Andric // FIXME: The Field pointer here is too much IMO and we could instead just
1083*7a6dacacSDimitry Andric // pass an Offset + BitWidth pair.
1084a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F,uint32_t FieldOffset)1085*7a6dacacSDimitry Andric bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1086*7a6dacacSDimitry Andric                       uint32_t FieldOffset) {
10875f757f3fSDimitry Andric   assert(F->isBitField());
1088a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1089a7dea167SDimitry Andric     return false;
1090a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1091a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1092a7dea167SDimitry Andric     return false;
1093*7a6dacacSDimitry Andric   const Pointer &Field = This.atField(FieldOffset);
1094a7dea167SDimitry Andric   const auto &Value = S.Stk.pop<T>();
1095a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1096a7dea167SDimitry Andric   Field.initialize();
1097a7dea167SDimitry Andric   return true;
1098a7dea167SDimitry Andric }
1099a7dea167SDimitry Andric 
1100a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)1101a7dea167SDimitry Andric bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1102a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1103a7dea167SDimitry Andric     return false;
1104a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1105a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1106a7dea167SDimitry Andric     return false;
1107a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
1108a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1109a7dea167SDimitry Andric   Field.activate();
1110a7dea167SDimitry Andric   Field.initialize();
1111a7dea167SDimitry Andric   return true;
1112a7dea167SDimitry Andric }
1113a7dea167SDimitry Andric 
1114bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1115bdd1243dSDimitry Andric /// 2) Peeks a pointer from the stack
1116bdd1243dSDimitry Andric /// 3) Pushes the value to field I of the pointer on the stack
1117a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)1118a7dea167SDimitry Andric bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1119a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1120bdd1243dSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
1121a7dea167SDimitry Andric   Field.deref<T>() = Value;
1122a7dea167SDimitry Andric   Field.activate();
1123a7dea167SDimitry Andric   Field.initialize();
1124a7dea167SDimitry Andric   return true;
1125a7dea167SDimitry Andric }
1126a7dea167SDimitry Andric 
1127a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)1128a7dea167SDimitry Andric bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
11295f757f3fSDimitry Andric   assert(F->isBitField());
1130a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
11315f757f3fSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1132a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
1133a7dea167SDimitry Andric   Field.activate();
1134a7dea167SDimitry Andric   Field.initialize();
1135a7dea167SDimitry Andric   return true;
1136a7dea167SDimitry Andric }
1137a7dea167SDimitry Andric 
1138a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)1139a7dea167SDimitry Andric bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
1140a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1141a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1142a7dea167SDimitry Andric   const Pointer &Field = Ptr.atField(I);
1143a7dea167SDimitry Andric   Field.deref<T>() = Value;
1144a7dea167SDimitry Andric   Field.activate();
1145a7dea167SDimitry Andric   Field.initialize();
1146a7dea167SDimitry Andric   return true;
1147a7dea167SDimitry Andric }
1148a7dea167SDimitry Andric 
1149a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1150a7dea167SDimitry Andric // GetPtr Local/Param/Global/Field/This
1151a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1152a7dea167SDimitry Andric 
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)1153a7dea167SDimitry Andric inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1154a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1155a7dea167SDimitry Andric   return true;
1156a7dea167SDimitry Andric }
1157a7dea167SDimitry Andric 
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)1158a7dea167SDimitry Andric inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1159a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1160a7dea167SDimitry Andric     return false;
1161a7dea167SDimitry Andric   }
1162a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1163a7dea167SDimitry Andric   return true;
1164a7dea167SDimitry Andric }
1165a7dea167SDimitry Andric 
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1166a7dea167SDimitry Andric inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1167a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1168a7dea167SDimitry Andric   return true;
1169a7dea167SDimitry Andric }
1170a7dea167SDimitry Andric 
1171bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack
1172bdd1243dSDimitry Andric /// 2) Pushes Pointer.atField(Off) on the stack
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)1173a7dea167SDimitry Andric inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1174a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
11755f757f3fSDimitry Andric   if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field))
1176a7dea167SDimitry Andric     return false;
1177a7dea167SDimitry Andric   if (!CheckExtern(S, OpPC, Ptr))
1178a7dea167SDimitry Andric     return false;
1179a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1180a7dea167SDimitry Andric     return false;
11815f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
11825f757f3fSDimitry Andric     return false;
11835f757f3fSDimitry Andric 
1184a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1185a7dea167SDimitry Andric   return true;
1186a7dea167SDimitry Andric }
1187a7dea167SDimitry Andric 
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)1188a7dea167SDimitry Andric inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1189a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1190a7dea167SDimitry Andric     return false;
1191a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1192a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1193a7dea167SDimitry Andric     return false;
1194a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1195a7dea167SDimitry Andric   return true;
1196a7dea167SDimitry Andric }
1197a7dea167SDimitry Andric 
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)1198a7dea167SDimitry Andric inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1199a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1200a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1201a7dea167SDimitry Andric     return false;
1202a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1203a7dea167SDimitry Andric     return false;
1204a7dea167SDimitry Andric   Pointer Field = Ptr.atField(Off);
1205a7dea167SDimitry Andric   Ptr.deactivate();
1206a7dea167SDimitry Andric   Field.activate();
1207a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1208a7dea167SDimitry Andric   return true;
1209a7dea167SDimitry Andric }
1210a7dea167SDimitry Andric 
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)1211a7dea167SDimitry Andric inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1212a7dea167SDimitry Andric  if (S.checkingPotentialConstantExpression())
1213a7dea167SDimitry Andric     return false;
1214a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1215a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1216a7dea167SDimitry Andric     return false;
1217a7dea167SDimitry Andric   Pointer Field = This.atField(Off);
1218a7dea167SDimitry Andric   This.deactivate();
1219a7dea167SDimitry Andric   Field.activate();
1220a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1221a7dea167SDimitry Andric   return true;
1222a7dea167SDimitry Andric }
1223a7dea167SDimitry Andric 
GetPtrDerivedPop(InterpState & S,CodePtr OpPC,uint32_t Off)12245f757f3fSDimitry Andric inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
12255f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
12265f757f3fSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Derived))
12275f757f3fSDimitry Andric     return false;
12285f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
12295f757f3fSDimitry Andric     return false;
12305f757f3fSDimitry Andric   S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
12315f757f3fSDimitry Andric   return true;
12325f757f3fSDimitry Andric }
12335f757f3fSDimitry Andric 
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)1234a7dea167SDimitry Andric inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
123506c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
123606c3fb27SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
123706c3fb27SDimitry Andric     return false;
12385f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
12395f757f3fSDimitry Andric     return false;
124006c3fb27SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
124106c3fb27SDimitry Andric   return true;
124206c3fb27SDimitry Andric }
124306c3fb27SDimitry Andric 
GetPtrBasePop(InterpState & S,CodePtr OpPC,uint32_t Off)124406c3fb27SDimitry Andric inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1245a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1246a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1247a7dea167SDimitry Andric     return false;
12485f757f3fSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
12495f757f3fSDimitry Andric     return false;
1250a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
1251a7dea167SDimitry Andric   return true;
1252a7dea167SDimitry Andric }
1253a7dea167SDimitry Andric 
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)1254a7dea167SDimitry Andric inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1255a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1256a7dea167SDimitry Andric     return false;
1257a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1258a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1259a7dea167SDimitry Andric     return false;
1260a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1261a7dea167SDimitry Andric   return true;
1262a7dea167SDimitry Andric }
1263a7dea167SDimitry Andric 
InitPtrPop(InterpState & S,CodePtr OpPC)12645f757f3fSDimitry Andric inline bool InitPtrPop(InterpState &S, CodePtr OpPC) {
12655f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
12665f757f3fSDimitry Andric   Ptr.initialize();
12675f757f3fSDimitry Andric   return true;
12685f757f3fSDimitry Andric }
12695f757f3fSDimitry Andric 
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)1270a7dea167SDimitry Andric inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1271a7dea167SDimitry Andric                            const Pointer &Ptr) {
1272a7dea167SDimitry Andric   Pointer Base = Ptr;
1273a7dea167SDimitry Andric   while (Base.isBaseClass())
1274a7dea167SDimitry Andric     Base = Base.getBase();
1275a7dea167SDimitry Andric 
1276a7dea167SDimitry Andric   auto *Field = Base.getRecord()->getVirtualBase(Decl);
1277a7dea167SDimitry Andric   S.Stk.push<Pointer>(Base.atField(Field->Offset));
1278a7dea167SDimitry Andric   return true;
1279a7dea167SDimitry Andric }
1280a7dea167SDimitry Andric 
GetPtrVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)1281a7dea167SDimitry Andric inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
1282a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1283a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1284a7dea167SDimitry Andric     return false;
1285a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, Ptr);
1286a7dea167SDimitry Andric }
1287a7dea167SDimitry Andric 
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)1288a7dea167SDimitry Andric inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1289a7dea167SDimitry Andric                                const RecordDecl *D) {
1290a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
1291a7dea167SDimitry Andric     return false;
1292a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1293a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1294a7dea167SDimitry Andric     return false;
1295a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1296a7dea167SDimitry Andric }
1297a7dea167SDimitry Andric 
1298a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1299a7dea167SDimitry Andric // Load, Store, Init
1300a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1301a7dea167SDimitry Andric 
1302a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)1303a7dea167SDimitry Andric bool Load(InterpState &S, CodePtr OpPC) {
1304a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1305a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1306a7dea167SDimitry Andric     return false;
1307a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1308a7dea167SDimitry Andric   return true;
1309a7dea167SDimitry Andric }
1310a7dea167SDimitry Andric 
1311a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)1312a7dea167SDimitry Andric bool LoadPop(InterpState &S, CodePtr OpPC) {
1313a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1314a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1315a7dea167SDimitry Andric     return false;
1316a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1317a7dea167SDimitry Andric   return true;
1318a7dea167SDimitry Andric }
1319a7dea167SDimitry Andric 
1320a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)1321a7dea167SDimitry Andric bool Store(InterpState &S, CodePtr OpPC) {
1322a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1323a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1324a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1325a7dea167SDimitry Andric     return false;
1326bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1327bdd1243dSDimitry Andric     Ptr.initialize();
1328a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1329a7dea167SDimitry Andric   return true;
1330a7dea167SDimitry Andric }
1331a7dea167SDimitry Andric 
1332a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)1333a7dea167SDimitry Andric bool StorePop(InterpState &S, CodePtr OpPC) {
1334a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1335a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1336a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1337a7dea167SDimitry Andric     return false;
1338bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1339bdd1243dSDimitry Andric     Ptr.initialize();
1340a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
1341a7dea167SDimitry Andric   return true;
1342a7dea167SDimitry Andric }
1343a7dea167SDimitry Andric 
1344a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)1345a7dea167SDimitry Andric bool StoreBitField(InterpState &S, CodePtr OpPC) {
1346a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1347a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1348a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1349a7dea167SDimitry Andric     return false;
1350bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1351bdd1243dSDimitry Andric     Ptr.initialize();
13525f757f3fSDimitry Andric   if (const auto *FD = Ptr.getField())
1353a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
13545f757f3fSDimitry Andric   else
1355a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1356a7dea167SDimitry Andric   return true;
1357a7dea167SDimitry Andric }
1358a7dea167SDimitry Andric 
1359a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)1360a7dea167SDimitry Andric bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1361a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1362a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1363a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1364a7dea167SDimitry Andric     return false;
1365bdd1243dSDimitry Andric   if (!Ptr.isRoot())
1366bdd1243dSDimitry Andric     Ptr.initialize();
13675f757f3fSDimitry Andric   if (const auto *FD = Ptr.getField())
1368a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
13695f757f3fSDimitry Andric   else
1370a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
1371a7dea167SDimitry Andric   return true;
1372a7dea167SDimitry Andric }
1373a7dea167SDimitry Andric 
1374a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)1375a7dea167SDimitry Andric bool InitPop(InterpState &S, CodePtr OpPC) {
1376a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1377a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1378a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1379a7dea167SDimitry Andric     return false;
1380a7dea167SDimitry Andric   Ptr.initialize();
1381a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1382a7dea167SDimitry Andric   return true;
1383a7dea167SDimitry Andric }
1384a7dea167SDimitry Andric 
1385bdd1243dSDimitry Andric /// 1) Pops the value from the stack
1386bdd1243dSDimitry Andric /// 2) Peeks a pointer and gets its index \Idx
1387bdd1243dSDimitry Andric /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1388a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)1389a7dea167SDimitry Andric bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1390a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1391a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1392a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1393a7dea167SDimitry Andric     return false;
1394a7dea167SDimitry Andric   Ptr.initialize();
1395a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1396a7dea167SDimitry Andric   return true;
1397a7dea167SDimitry Andric }
1398a7dea167SDimitry Andric 
1399bdd1243dSDimitry Andric /// The same as InitElem, but pops the pointer as well.
1400a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)1401a7dea167SDimitry Andric bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1402a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
1403a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1404a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1405a7dea167SDimitry Andric     return false;
1406a7dea167SDimitry Andric   Ptr.initialize();
1407a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1408a7dea167SDimitry Andric   return true;
1409a7dea167SDimitry Andric }
1410a7dea167SDimitry Andric 
1411a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1412a7dea167SDimitry Andric // AddOffset, SubOffset
1413a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1414a7dea167SDimitry Andric 
141506c3fb27SDimitry Andric template <class T, ArithOp Op>
OffsetHelper(InterpState & S,CodePtr OpPC,const T & Offset,const Pointer & Ptr)141606c3fb27SDimitry Andric bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
141706c3fb27SDimitry Andric                   const Pointer &Ptr) {
1418a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1419a7dea167SDimitry Andric     return false;
1420a7dea167SDimitry Andric 
1421bdd1243dSDimitry Andric   // A zero offset does not change the pointer.
1422a7dea167SDimitry Andric   if (Offset.isZero()) {
1423bdd1243dSDimitry Andric     S.Stk.push<Pointer>(Ptr);
1424a7dea167SDimitry Andric     return true;
1425a7dea167SDimitry Andric   }
1426bdd1243dSDimitry Andric 
1427bdd1243dSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1428bdd1243dSDimitry Andric     return false;
1429bdd1243dSDimitry Andric 
1430a7dea167SDimitry Andric   // Arrays of unknown bounds cannot have pointers into them.
1431a7dea167SDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
1432a7dea167SDimitry Andric     return false;
1433a7dea167SDimitry Andric 
1434bdd1243dSDimitry Andric   // Get a version of the index comparable to the type.
1435bdd1243dSDimitry Andric   T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1436a7dea167SDimitry Andric   // Compute the largest index into the array.
14375f757f3fSDimitry Andric   T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth());
1438a7dea167SDimitry Andric 
14395f757f3fSDimitry Andric   bool Invalid = false;
1440a7dea167SDimitry Andric   // Helper to report an invalid offset, computed as APSInt.
14415f757f3fSDimitry Andric   auto DiagInvalidOffset = [&]() -> void {
1442a7dea167SDimitry Andric     const unsigned Bits = Offset.bitWidth();
1443a7dea167SDimitry Andric     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1444a7dea167SDimitry Andric     APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
144506c3fb27SDimitry Andric     APSInt NewIndex =
144606c3fb27SDimitry Andric         (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
1447a7dea167SDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1448a7dea167SDimitry Andric         << NewIndex
1449a7dea167SDimitry Andric         << /*array*/ static_cast<int>(!Ptr.inArray())
1450a7dea167SDimitry Andric         << static_cast<unsigned>(MaxIndex);
14515f757f3fSDimitry Andric     Invalid = true;
1452a7dea167SDimitry Andric   };
1453a7dea167SDimitry Andric 
14545f757f3fSDimitry Andric   T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
145506c3fb27SDimitry Andric   if constexpr (Op == ArithOp::Add) {
1456a7dea167SDimitry Andric     // If the new offset would be negative, bail out.
1457bdd1243dSDimitry Andric     if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
14585f757f3fSDimitry Andric       DiagInvalidOffset();
1459a7dea167SDimitry Andric 
1460a7dea167SDimitry Andric     // If the new offset would be out of bounds, bail out.
1461bdd1243dSDimitry Andric     if (Offset.isPositive() && Offset > MaxOffset)
14625f757f3fSDimitry Andric       DiagInvalidOffset();
1463bdd1243dSDimitry Andric   } else {
1464bdd1243dSDimitry Andric     // If the new offset would be negative, bail out.
1465bdd1243dSDimitry Andric     if (Offset.isPositive() && Index < Offset)
14665f757f3fSDimitry Andric       DiagInvalidOffset();
1467a7dea167SDimitry Andric 
1468bdd1243dSDimitry Andric     // If the new offset would be out of bounds, bail out.
1469bdd1243dSDimitry Andric     if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
14705f757f3fSDimitry Andric       DiagInvalidOffset();
1471bdd1243dSDimitry Andric   }
1472bdd1243dSDimitry Andric 
14735f757f3fSDimitry Andric   if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
14745f757f3fSDimitry Andric     return false;
14755f757f3fSDimitry Andric 
1476a7dea167SDimitry Andric   // Offset is valid - compute it on unsigned.
1477a7dea167SDimitry Andric   int64_t WideIndex = static_cast<int64_t>(Index);
1478a7dea167SDimitry Andric   int64_t WideOffset = static_cast<int64_t>(Offset);
1479bdd1243dSDimitry Andric   int64_t Result;
148006c3fb27SDimitry Andric   if constexpr (Op == ArithOp::Add)
1481bdd1243dSDimitry Andric     Result = WideIndex + WideOffset;
1482bdd1243dSDimitry Andric   else
1483bdd1243dSDimitry Andric     Result = WideIndex - WideOffset;
1484bdd1243dSDimitry Andric 
1485a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1486a7dea167SDimitry Andric   return true;
1487a7dea167SDimitry Andric }
1488a7dea167SDimitry Andric 
1489a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)1490a7dea167SDimitry Andric bool AddOffset(InterpState &S, CodePtr OpPC) {
149106c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
149206c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
149306c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);
1494a7dea167SDimitry Andric }
1495a7dea167SDimitry Andric 
1496a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)1497a7dea167SDimitry Andric bool SubOffset(InterpState &S, CodePtr OpPC) {
149806c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
149906c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
150006c3fb27SDimitry Andric   return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);
150106c3fb27SDimitry Andric }
150206c3fb27SDimitry Andric 
150306c3fb27SDimitry Andric template <ArithOp Op>
IncDecPtrHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)15045f757f3fSDimitry Andric static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
15055f757f3fSDimitry Andric                                    const Pointer &Ptr) {
150606c3fb27SDimitry Andric   using OneT = Integral<8, false>;
15075f757f3fSDimitry Andric 
15085f757f3fSDimitry Andric   const Pointer &P = Ptr.deref<Pointer>();
15095f757f3fSDimitry Andric   if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
15105f757f3fSDimitry Andric     return false;
151106c3fb27SDimitry Andric 
151206c3fb27SDimitry Andric   // Get the current value on the stack.
15135f757f3fSDimitry Andric   S.Stk.push<Pointer>(P);
151406c3fb27SDimitry Andric 
151506c3fb27SDimitry Andric   // Now the current Ptr again and a constant 1.
151606c3fb27SDimitry Andric   OneT One = OneT::from(1);
151706c3fb27SDimitry Andric   if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))
151806c3fb27SDimitry Andric     return false;
151906c3fb27SDimitry Andric 
152006c3fb27SDimitry Andric   // Store the new value.
152106c3fb27SDimitry Andric   Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();
152206c3fb27SDimitry Andric   return true;
152306c3fb27SDimitry Andric }
152406c3fb27SDimitry Andric 
IncPtr(InterpState & S,CodePtr OpPC)152506c3fb27SDimitry Andric static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
15265f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
15275f757f3fSDimitry Andric 
15285f757f3fSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
15295f757f3fSDimitry Andric     return false;
15305f757f3fSDimitry Andric 
15315f757f3fSDimitry Andric   return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
153206c3fb27SDimitry Andric }
153306c3fb27SDimitry Andric 
DecPtr(InterpState & S,CodePtr OpPC)153406c3fb27SDimitry Andric static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
15355f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
15365f757f3fSDimitry Andric 
15375f757f3fSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
15385f757f3fSDimitry Andric     return false;
15395f757f3fSDimitry Andric 
15405f757f3fSDimitry Andric   return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
1541a7dea167SDimitry Andric }
1542a7dea167SDimitry Andric 
1543bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack.
1544bdd1243dSDimitry Andric /// 2) Pops another Pointer from the stack.
1545bdd1243dSDimitry Andric /// 3) Pushes the different of the indices of the two pointers on the stack.
1546bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SubPtr(InterpState & S,CodePtr OpPC)1547bdd1243dSDimitry Andric inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1548bdd1243dSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
1549bdd1243dSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
1550bdd1243dSDimitry Andric 
15515f757f3fSDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
1552bdd1243dSDimitry Andric     // TODO: Diagnose.
1553bdd1243dSDimitry Andric     return false;
1554bdd1243dSDimitry Andric   }
1555bdd1243dSDimitry Andric 
1556bdd1243dSDimitry Andric   T A = T::from(LHS.getIndex());
1557bdd1243dSDimitry Andric   T B = T::from(RHS.getIndex());
1558bdd1243dSDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1559bdd1243dSDimitry Andric }
1560a7dea167SDimitry Andric 
1561a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1562a7dea167SDimitry Andric // Destroy
1563a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1564a7dea167SDimitry Andric 
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)1565a7dea167SDimitry Andric inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1566a7dea167SDimitry Andric   S.Current->destroy(I);
1567a7dea167SDimitry Andric   return true;
1568a7dea167SDimitry Andric }
1569a7dea167SDimitry Andric 
1570a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1571a7dea167SDimitry Andric // Cast, CastFP
1572a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1573a7dea167SDimitry Andric 
Cast(InterpState & S,CodePtr OpPC)1574a7dea167SDimitry Andric template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1575a7dea167SDimitry Andric   using T = typename PrimConv<TIn>::T;
1576a7dea167SDimitry Andric   using U = typename PrimConv<TOut>::T;
1577a7dea167SDimitry Andric   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1578a7dea167SDimitry Andric   return true;
1579a7dea167SDimitry Andric }
1580a7dea167SDimitry Andric 
158106c3fb27SDimitry Andric /// 1) Pops a Floating from the stack.
158206c3fb27SDimitry Andric /// 2) Pushes a new floating on the stack that uses the given semantics.
CastFP(InterpState & S,CodePtr OpPC,const llvm::fltSemantics * Sem,llvm::RoundingMode RM)158306c3fb27SDimitry Andric inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
158406c3fb27SDimitry Andric             llvm::RoundingMode RM) {
158506c3fb27SDimitry Andric   Floating F = S.Stk.pop<Floating>();
158606c3fb27SDimitry Andric   Floating Result = F.toSemantics(Sem, RM);
158706c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
158806c3fb27SDimitry Andric   return true;
158906c3fb27SDimitry Andric }
159006c3fb27SDimitry Andric 
15915f757f3fSDimitry Andric /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
15925f757f3fSDimitry Andric /// to know what bitwidth the result should be.
15935f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)15945f757f3fSDimitry Andric bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
15955f757f3fSDimitry Andric   S.Stk.push<IntegralAP<false>>(
15965f757f3fSDimitry Andric       IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));
15975f757f3fSDimitry Andric   return true;
15985f757f3fSDimitry Andric }
15995f757f3fSDimitry Andric 
16005f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)16015f757f3fSDimitry Andric bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
16025f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(
16035f757f3fSDimitry Andric       IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));
16045f757f3fSDimitry Andric   return true;
16055f757f3fSDimitry Andric }
16065f757f3fSDimitry Andric 
160706c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastIntegralFloating(InterpState & S,CodePtr OpPC,const llvm::fltSemantics * Sem,llvm::RoundingMode RM)160806c3fb27SDimitry Andric bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
160906c3fb27SDimitry Andric                           const llvm::fltSemantics *Sem,
161006c3fb27SDimitry Andric                           llvm::RoundingMode RM) {
161106c3fb27SDimitry Andric   const T &From = S.Stk.pop<T>();
161206c3fb27SDimitry Andric   APSInt FromAP = From.toAPSInt();
161306c3fb27SDimitry Andric   Floating Result;
161406c3fb27SDimitry Andric 
161506c3fb27SDimitry Andric   auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
161606c3fb27SDimitry Andric   S.Stk.push<Floating>(Result);
161706c3fb27SDimitry Andric 
16185f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status);
161906c3fb27SDimitry Andric }
162006c3fb27SDimitry Andric 
162106c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastFloatingIntegral(InterpState & S,CodePtr OpPC)162206c3fb27SDimitry Andric bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
162306c3fb27SDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
162406c3fb27SDimitry Andric 
162506c3fb27SDimitry Andric   if constexpr (std::is_same_v<T, Boolean>) {
162606c3fb27SDimitry Andric     S.Stk.push<T>(T(F.isNonZero()));
162706c3fb27SDimitry Andric     return true;
162806c3fb27SDimitry Andric   } else {
16295f757f3fSDimitry Andric     APSInt Result(std::max(8u, T::bitWidth()),
163006c3fb27SDimitry Andric                   /*IsUnsigned=*/!T::isSigned());
163106c3fb27SDimitry Andric     auto Status = F.convertToInteger(Result);
163206c3fb27SDimitry Andric 
163306c3fb27SDimitry Andric     // Float-to-Integral overflow check.
163406c3fb27SDimitry Andric     if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
163506c3fb27SDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
163606c3fb27SDimitry Andric       QualType Type = E->getType();
163706c3fb27SDimitry Andric 
163806c3fb27SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
16395f757f3fSDimitry Andric       if (S.noteUndefinedBehavior()) {
16405f757f3fSDimitry Andric         S.Stk.push<T>(T(Result));
16415f757f3fSDimitry Andric         return true;
16425f757f3fSDimitry Andric       }
16435f757f3fSDimitry Andric       return false;
16445f757f3fSDimitry Andric     }
16455f757f3fSDimitry Andric 
16465f757f3fSDimitry Andric     S.Stk.push<T>(T(Result));
16475f757f3fSDimitry Andric     return CheckFloatResult(S, OpPC, F, Status);
16485f757f3fSDimitry Andric   }
16495f757f3fSDimitry Andric }
16505f757f3fSDimitry Andric 
CastFloatingIntegralAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)16515f757f3fSDimitry Andric static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
16525f757f3fSDimitry Andric                                           uint32_t BitWidth) {
16535f757f3fSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
16545f757f3fSDimitry Andric 
16555f757f3fSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/true);
16565f757f3fSDimitry Andric   auto Status = F.convertToInteger(Result);
16575f757f3fSDimitry Andric 
16585f757f3fSDimitry Andric   // Float-to-Integral overflow check.
16595f757f3fSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
16605f757f3fSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
16615f757f3fSDimitry Andric     QualType Type = E->getType();
16625f757f3fSDimitry Andric 
16635f757f3fSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
166406c3fb27SDimitry Andric     return S.noteUndefinedBehavior();
166506c3fb27SDimitry Andric   }
166606c3fb27SDimitry Andric 
16675f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
16685f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status);
166906c3fb27SDimitry Andric }
16705f757f3fSDimitry Andric 
CastFloatingIntegralAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)16715f757f3fSDimitry Andric static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
16725f757f3fSDimitry Andric                                            uint32_t BitWidth) {
16735f757f3fSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
16745f757f3fSDimitry Andric 
16755f757f3fSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/false);
16765f757f3fSDimitry Andric   auto Status = F.convertToInteger(Result);
16775f757f3fSDimitry Andric 
16785f757f3fSDimitry Andric   // Float-to-Integral overflow check.
16795f757f3fSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
16805f757f3fSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
16815f757f3fSDimitry Andric     QualType Type = E->getType();
16825f757f3fSDimitry Andric 
16835f757f3fSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
16845f757f3fSDimitry Andric     return S.noteUndefinedBehavior();
16855f757f3fSDimitry Andric   }
16865f757f3fSDimitry Andric 
16875f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
16885f757f3fSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status);
16895f757f3fSDimitry Andric }
16905f757f3fSDimitry Andric 
16915f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastPointerIntegral(InterpState & S,CodePtr OpPC)16925f757f3fSDimitry Andric bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
16935f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
16945f757f3fSDimitry Andric 
16955f757f3fSDimitry Andric   if (!CheckPotentialReinterpretCast(S, OpPC, Ptr))
16965f757f3fSDimitry Andric     return false;
16975f757f3fSDimitry Andric 
16985f757f3fSDimitry Andric   S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
16995f757f3fSDimitry Andric   return true;
170006c3fb27SDimitry Andric }
170106c3fb27SDimitry Andric 
1702a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1703a7dea167SDimitry Andric // Zero, Nullptr
1704a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1705a7dea167SDimitry Andric 
1706a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)1707a7dea167SDimitry Andric bool Zero(InterpState &S, CodePtr OpPC) {
1708a7dea167SDimitry Andric   S.Stk.push<T>(T::zero());
1709a7dea167SDimitry Andric   return true;
1710a7dea167SDimitry Andric }
1711a7dea167SDimitry Andric 
ZeroIntAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)17125f757f3fSDimitry Andric static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
17135f757f3fSDimitry Andric   S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));
17145f757f3fSDimitry Andric   return true;
17155f757f3fSDimitry Andric }
17165f757f3fSDimitry Andric 
ZeroIntAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)17175f757f3fSDimitry Andric static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
17185f757f3fSDimitry Andric   S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));
17195f757f3fSDimitry Andric   return true;
17205f757f3fSDimitry Andric }
17215f757f3fSDimitry Andric 
1722a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC)1723a7dea167SDimitry Andric inline bool Null(InterpState &S, CodePtr OpPC) {
1724a7dea167SDimitry Andric   S.Stk.push<T>();
1725a7dea167SDimitry Andric   return true;
1726a7dea167SDimitry Andric }
1727a7dea167SDimitry Andric 
1728a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1729a7dea167SDimitry Andric // This, ImplicitThis
1730a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1731a7dea167SDimitry Andric 
This(InterpState & S,CodePtr OpPC)1732a7dea167SDimitry Andric inline bool This(InterpState &S, CodePtr OpPC) {
1733a7dea167SDimitry Andric   // Cannot read 'this' in this mode.
1734a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1735a7dea167SDimitry Andric     return false;
1736a7dea167SDimitry Andric   }
1737a7dea167SDimitry Andric 
1738a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
1739a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
1740a7dea167SDimitry Andric     return false;
1741a7dea167SDimitry Andric 
1742a7dea167SDimitry Andric   S.Stk.push<Pointer>(This);
1743a7dea167SDimitry Andric   return true;
1744a7dea167SDimitry Andric }
1745a7dea167SDimitry Andric 
RVOPtr(InterpState & S,CodePtr OpPC)1746bdd1243dSDimitry Andric inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1747bdd1243dSDimitry Andric   assert(S.Current->getFunction()->hasRVO());
174806c3fb27SDimitry Andric   if (S.checkingPotentialConstantExpression())
174906c3fb27SDimitry Andric     return false;
1750bdd1243dSDimitry Andric   S.Stk.push<Pointer>(S.Current->getRVOPtr());
1751bdd1243dSDimitry Andric   return true;
1752bdd1243dSDimitry Andric }
1753bdd1243dSDimitry Andric 
1754a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1755a7dea167SDimitry Andric // Shr, Shl
1756a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1757a7dea167SDimitry Andric 
1758bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
Shr(InterpState & S,CodePtr OpPC)1759a7dea167SDimitry Andric inline bool Shr(InterpState &S, CodePtr OpPC) {
1760bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
1761bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
1762bdd1243dSDimitry Andric   const auto &RHS = S.Stk.pop<RT>();
1763bdd1243dSDimitry Andric   const auto &LHS = S.Stk.pop<LT>();
1764a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
1765a7dea167SDimitry Andric 
176606c3fb27SDimitry Andric   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1767bdd1243dSDimitry Andric     return false;
1768bdd1243dSDimitry Andric 
17695f757f3fSDimitry Andric   typename LT::AsUnsigned R;
17705f757f3fSDimitry Andric   LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
17715f757f3fSDimitry Andric                              LT::AsUnsigned::from(RHS), Bits, &R);
17725f757f3fSDimitry Andric   S.Stk.push<LT>(LT::from(R));
17735f757f3fSDimitry Andric 
1774bdd1243dSDimitry Andric   return true;
1775a7dea167SDimitry Andric }
1776a7dea167SDimitry Andric 
1777bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR>
Shl(InterpState & S,CodePtr OpPC)1778a7dea167SDimitry Andric inline bool Shl(InterpState &S, CodePtr OpPC) {
1779bdd1243dSDimitry Andric   using LT = typename PrimConv<NameL>::T;
1780bdd1243dSDimitry Andric   using RT = typename PrimConv<NameR>::T;
1781bdd1243dSDimitry Andric   const auto &RHS = S.Stk.pop<RT>();
1782bdd1243dSDimitry Andric   const auto &LHS = S.Stk.pop<LT>();
1783a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
1784a7dea167SDimitry Andric 
178506c3fb27SDimitry Andric   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
1786bdd1243dSDimitry Andric     return false;
1787bdd1243dSDimitry Andric 
17885f757f3fSDimitry Andric   typename LT::AsUnsigned R;
17895f757f3fSDimitry Andric   LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
17905f757f3fSDimitry Andric                             LT::AsUnsigned::from(RHS, Bits), Bits, &R);
17915f757f3fSDimitry Andric   S.Stk.push<LT>(LT::from(R));
1792bdd1243dSDimitry Andric   return true;
1793a7dea167SDimitry Andric }
1794a7dea167SDimitry Andric 
1795a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1796a7dea167SDimitry Andric // NoRet
1797a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1798a7dea167SDimitry Andric 
NoRet(InterpState & S,CodePtr OpPC)1799a7dea167SDimitry Andric inline bool NoRet(InterpState &S, CodePtr OpPC) {
1800a7dea167SDimitry Andric   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1801a7dea167SDimitry Andric   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1802a7dea167SDimitry Andric   return false;
1803a7dea167SDimitry Andric }
1804a7dea167SDimitry Andric 
1805a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1806a7dea167SDimitry Andric // NarrowPtr, ExpandPtr
1807a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
1808a7dea167SDimitry Andric 
NarrowPtr(InterpState & S,CodePtr OpPC)1809a7dea167SDimitry Andric inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1810a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1811a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.narrow());
1812a7dea167SDimitry Andric   return true;
1813a7dea167SDimitry Andric }
1814a7dea167SDimitry Andric 
ExpandPtr(InterpState & S,CodePtr OpPC)1815a7dea167SDimitry Andric inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1816a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1817a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.expand());
1818a7dea167SDimitry Andric   return true;
1819a7dea167SDimitry Andric }
1820a7dea167SDimitry Andric 
182106c3fb27SDimitry Andric // 1) Pops an integral value from the stack
182206c3fb27SDimitry Andric // 2) Peeks a pointer
182306c3fb27SDimitry Andric // 3) Pushes a new pointer that's a narrowed array
182406c3fb27SDimitry Andric //   element of the peeked pointer with the value
182506c3fb27SDimitry Andric //   from 1) added as offset.
182606c3fb27SDimitry Andric //
182706c3fb27SDimitry Andric // This leaves the original pointer on the stack and pushes a new one
182806c3fb27SDimitry Andric // with the offset applied and narrowed.
182906c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPtr(InterpState & S,CodePtr OpPC)183006c3fb27SDimitry Andric inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
183106c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
183206c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
183306c3fb27SDimitry Andric 
183406c3fb27SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
183506c3fb27SDimitry Andric     return false;
183606c3fb27SDimitry Andric 
183706c3fb27SDimitry Andric   return NarrowPtr(S, OpPC);
183806c3fb27SDimitry Andric }
183906c3fb27SDimitry Andric 
18405f757f3fSDimitry Andric /// Just takes a pointer and checks if its' an incomplete
18415f757f3fSDimitry Andric /// array type.
ArrayDecay(InterpState & S,CodePtr OpPC)18425f757f3fSDimitry Andric inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
18435f757f3fSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
18445f757f3fSDimitry Andric 
18455f757f3fSDimitry Andric   if (!Ptr.isUnknownSizeArray()) {
18465f757f3fSDimitry Andric     S.Stk.push<Pointer>(Ptr.atIndex(0));
18475f757f3fSDimitry Andric     return true;
18485f757f3fSDimitry Andric   }
18495f757f3fSDimitry Andric 
18505f757f3fSDimitry Andric   const SourceInfo &E = S.Current->getSource(OpPC);
18515f757f3fSDimitry Andric   S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
18525f757f3fSDimitry Andric 
18535f757f3fSDimitry Andric   return false;
18545f757f3fSDimitry Andric }
18555f757f3fSDimitry Andric 
185606c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPtrPop(InterpState & S,CodePtr OpPC)185706c3fb27SDimitry Andric inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
185806c3fb27SDimitry Andric   const T &Offset = S.Stk.pop<T>();
185906c3fb27SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
186006c3fb27SDimitry Andric 
186106c3fb27SDimitry Andric   if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
186206c3fb27SDimitry Andric     return false;
186306c3fb27SDimitry Andric 
186406c3fb27SDimitry Andric   return NarrowPtr(S, OpPC);
186506c3fb27SDimitry Andric }
186606c3fb27SDimitry Andric 
Call(InterpState & S,CodePtr OpPC,const Function * Func)186706c3fb27SDimitry Andric inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
1868bdd1243dSDimitry Andric   if (Func->hasThisPointer()) {
186906c3fb27SDimitry Andric     size_t ThisOffset =
18705f757f3fSDimitry Andric         Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1871bdd1243dSDimitry Andric 
187206c3fb27SDimitry Andric     const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
187306c3fb27SDimitry Andric 
18745f757f3fSDimitry Andric     // If the current function is a lambda static invoker and
18755f757f3fSDimitry Andric     // the function we're about to call is a lambda call operator,
18765f757f3fSDimitry Andric     // skip the CheckInvoke, since the ThisPtr is a null pointer
18775f757f3fSDimitry Andric     // anyway.
18785f757f3fSDimitry Andric     if (!(S.Current->getFunction() &&
18795f757f3fSDimitry Andric           S.Current->getFunction()->isLambdaStaticInvoker() &&
18805f757f3fSDimitry Andric           Func->isLambdaCallOperator())) {
188106c3fb27SDimitry Andric       if (!CheckInvoke(S, OpPC, ThisPtr))
1882bdd1243dSDimitry Andric         return false;
18835f757f3fSDimitry Andric     }
1884bdd1243dSDimitry Andric 
188506c3fb27SDimitry Andric     if (S.checkingPotentialConstantExpression())
188606c3fb27SDimitry Andric       return false;
188706c3fb27SDimitry Andric   }
188806c3fb27SDimitry Andric 
188906c3fb27SDimitry Andric   if (!CheckCallable(S, OpPC, Func))
189006c3fb27SDimitry Andric     return false;
189106c3fb27SDimitry Andric 
189206c3fb27SDimitry Andric   if (!CheckCallDepth(S, OpPC))
189306c3fb27SDimitry Andric     return false;
189406c3fb27SDimitry Andric 
189506c3fb27SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
1896bdd1243dSDimitry Andric   InterpFrame *FrameBefore = S.Current;
1897bdd1243dSDimitry Andric   S.Current = NewFrame.get();
1898bdd1243dSDimitry Andric 
1899bdd1243dSDimitry Andric   APValue CallResult;
1900bdd1243dSDimitry Andric   // Note that we cannot assert(CallResult.hasValue()) here since
1901bdd1243dSDimitry Andric   // Ret() above only sets the APValue if the curent frame doesn't
1902bdd1243dSDimitry Andric   // have a caller set.
1903bdd1243dSDimitry Andric   if (Interpret(S, CallResult)) {
1904bdd1243dSDimitry Andric     NewFrame.release(); // Frame was delete'd already.
1905bdd1243dSDimitry Andric     assert(S.Current == FrameBefore);
1906bdd1243dSDimitry Andric     return true;
1907bdd1243dSDimitry Andric   }
1908bdd1243dSDimitry Andric 
1909bdd1243dSDimitry Andric   // Interpreting the function failed somehow. Reset to
1910bdd1243dSDimitry Andric   // previous state.
1911bdd1243dSDimitry Andric   S.Current = FrameBefore;
1912bdd1243dSDimitry Andric   return false;
1913bdd1243dSDimitry Andric }
1914bdd1243dSDimitry Andric 
CallVirt(InterpState & S,CodePtr OpPC,const Function * Func)191506c3fb27SDimitry Andric inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
191606c3fb27SDimitry Andric   assert(Func->hasThisPointer());
191706c3fb27SDimitry Andric   assert(Func->isVirtual());
191806c3fb27SDimitry Andric   size_t ThisOffset =
19195f757f3fSDimitry Andric       Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
192006c3fb27SDimitry Andric   Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
192106c3fb27SDimitry Andric 
192206c3fb27SDimitry Andric   const CXXRecordDecl *DynamicDecl =
192306c3fb27SDimitry Andric       ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();
192406c3fb27SDimitry Andric   const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
192506c3fb27SDimitry Andric   const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());
192606c3fb27SDimitry Andric   const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
192706c3fb27SDimitry Andric       DynamicDecl, StaticDecl, InitialFunction);
192806c3fb27SDimitry Andric 
192906c3fb27SDimitry Andric   if (Overrider != InitialFunction) {
19305f757f3fSDimitry Andric     // DR1872: An instantiated virtual constexpr function can't be called in a
19315f757f3fSDimitry Andric     // constant expression (prior to C++20). We can still constant-fold such a
19325f757f3fSDimitry Andric     // call.
19335f757f3fSDimitry Andric     if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
19345f757f3fSDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
19355f757f3fSDimitry Andric       S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
19365f757f3fSDimitry Andric     }
19375f757f3fSDimitry Andric 
19385f757f3fSDimitry Andric     Func = S.getContext().getOrCreateFunction(Overrider);
193906c3fb27SDimitry Andric 
194006c3fb27SDimitry Andric     const CXXRecordDecl *ThisFieldDecl =
194106c3fb27SDimitry Andric         ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
194206c3fb27SDimitry Andric     if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
194306c3fb27SDimitry Andric       // If the function we call is further DOWN the hierarchy than the
194406c3fb27SDimitry Andric       // FieldDesc of our pointer, just get the DeclDesc instead, which
194506c3fb27SDimitry Andric       // is the furthest we might go up in the hierarchy.
194606c3fb27SDimitry Andric       ThisPtr = ThisPtr.getDeclPtr();
194706c3fb27SDimitry Andric     }
194806c3fb27SDimitry Andric   }
194906c3fb27SDimitry Andric 
195006c3fb27SDimitry Andric   return Call(S, OpPC, Func);
195106c3fb27SDimitry Andric }
195206c3fb27SDimitry Andric 
CallBI(InterpState & S,CodePtr & PC,const Function * Func,const CallExpr * CE)19535f757f3fSDimitry Andric inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
19545f757f3fSDimitry Andric                    const CallExpr *CE) {
195506c3fb27SDimitry Andric   auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
195606c3fb27SDimitry Andric 
195706c3fb27SDimitry Andric   InterpFrame *FrameBefore = S.Current;
195806c3fb27SDimitry Andric   S.Current = NewFrame.get();
195906c3fb27SDimitry Andric 
19605f757f3fSDimitry Andric   if (InterpretBuiltin(S, PC, Func, CE)) {
196106c3fb27SDimitry Andric     NewFrame.release();
196206c3fb27SDimitry Andric     return true;
196306c3fb27SDimitry Andric   }
196406c3fb27SDimitry Andric   S.Current = FrameBefore;
196506c3fb27SDimitry Andric   return false;
196606c3fb27SDimitry Andric }
196706c3fb27SDimitry Andric 
CallPtr(InterpState & S,CodePtr OpPC)196806c3fb27SDimitry Andric inline bool CallPtr(InterpState &S, CodePtr OpPC) {
196906c3fb27SDimitry Andric   const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
197006c3fb27SDimitry Andric 
197106c3fb27SDimitry Andric   const Function *F = FuncPtr.getFunction();
197206c3fb27SDimitry Andric   if (!F || !F->isConstexpr())
197306c3fb27SDimitry Andric     return false;
197406c3fb27SDimitry Andric 
19755f757f3fSDimitry Andric   if (F->isVirtual())
19765f757f3fSDimitry Andric     return CallVirt(S, OpPC, F);
19775f757f3fSDimitry Andric 
197806c3fb27SDimitry Andric   return Call(S, OpPC, F);
197906c3fb27SDimitry Andric }
198006c3fb27SDimitry Andric 
GetFnPtr(InterpState & S,CodePtr OpPC,const Function * Func)198106c3fb27SDimitry Andric inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
198206c3fb27SDimitry Andric   assert(Func);
198306c3fb27SDimitry Andric   S.Stk.push<FunctionPointer>(Func);
198406c3fb27SDimitry Andric   return true;
198506c3fb27SDimitry Andric }
198606c3fb27SDimitry Andric 
19875f757f3fSDimitry Andric /// Just emit a diagnostic. The expression that caused emission of this
19885f757f3fSDimitry Andric /// op is not valid in a constant context.
Invalid(InterpState & S,CodePtr OpPC)19895f757f3fSDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC) {
19905f757f3fSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
19915f757f3fSDimitry Andric   S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
19925f757f3fSDimitry Andric       << S.Current->getRange(OpPC);
19935f757f3fSDimitry Andric   return false;
19945f757f3fSDimitry Andric }
19955f757f3fSDimitry Andric 
19965f757f3fSDimitry Andric /// Same here, but only for casts.
InvalidCast(InterpState & S,CodePtr OpPC,CastKind Kind)19975f757f3fSDimitry Andric inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
19985f757f3fSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
19995f757f3fSDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_invalid_cast)
20005f757f3fSDimitry Andric       << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
20015f757f3fSDimitry Andric   return false;
20025f757f3fSDimitry Andric }
20035f757f3fSDimitry Andric 
InvalidDeclRef(InterpState & S,CodePtr OpPC,const DeclRefExpr * DR)20045f757f3fSDimitry Andric inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
20055f757f3fSDimitry Andric                            const DeclRefExpr *DR) {
20065f757f3fSDimitry Andric   assert(DR);
20075f757f3fSDimitry Andric   return CheckDeclRef(S, OpPC, DR);
20085f757f3fSDimitry Andric }
20095f757f3fSDimitry Andric 
20105f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
OffsetOf(InterpState & S,CodePtr OpPC,const OffsetOfExpr * E)20115f757f3fSDimitry Andric inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
20125f757f3fSDimitry Andric   llvm::SmallVector<int64_t> ArrayIndices;
20135f757f3fSDimitry Andric   for (size_t I = 0; I != E->getNumExpressions(); ++I)
20145f757f3fSDimitry Andric     ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
20155f757f3fSDimitry Andric 
20165f757f3fSDimitry Andric   int64_t Result;
20175f757f3fSDimitry Andric   if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
20185f757f3fSDimitry Andric     return false;
20195f757f3fSDimitry Andric 
20205f757f3fSDimitry Andric   S.Stk.push<T>(T::from(Result));
20215f757f3fSDimitry Andric 
20225f757f3fSDimitry Andric   return true;
20235f757f3fSDimitry Andric }
20245f757f3fSDimitry Andric 
2025349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
2026349cc55cSDimitry Andric // Read opcode arguments
2027349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
2028349cc55cSDimitry Andric 
ReadArg(InterpState & S,CodePtr & OpPC)2029bdd1243dSDimitry Andric template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
2030bdd1243dSDimitry Andric   if constexpr (std::is_pointer<T>::value) {
2031349cc55cSDimitry Andric     uint32_t ID = OpPC.read<uint32_t>();
2032349cc55cSDimitry Andric     return reinterpret_cast<T>(S.P.getNativePointer(ID));
2033bdd1243dSDimitry Andric   } else {
2034bdd1243dSDimitry Andric     return OpPC.read<T>();
2035349cc55cSDimitry Andric   }
2036bdd1243dSDimitry Andric }
2037a7dea167SDimitry Andric 
20385f757f3fSDimitry Andric template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
20395f757f3fSDimitry Andric   Floating F = Floating::deserialize(*OpPC);
20405f757f3fSDimitry Andric   OpPC += align(F.bytesToSerialize());
20415f757f3fSDimitry Andric   return F;
20425f757f3fSDimitry Andric }
20435f757f3fSDimitry Andric 
2044a7dea167SDimitry Andric } // namespace interp
2045a7dea167SDimitry Andric } // namespace clang
2046a7dea167SDimitry Andric 
2047a7dea167SDimitry Andric #endif
2048