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