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