xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // Definition of the interpreter state and entry point.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14*700637cbSDimitry Andric #define LLVM_CLANG_AST_INTERP_INTERP_H
15*700637cbSDimitry Andric 
16*700637cbSDimitry Andric #include "../ExprConstShared.h"
17*700637cbSDimitry Andric #include "BitcastBuffer.h"
18*700637cbSDimitry Andric #include "Boolean.h"
19*700637cbSDimitry Andric #include "DynamicAllocator.h"
20*700637cbSDimitry Andric #include "FixedPoint.h"
21*700637cbSDimitry Andric #include "Floating.h"
22*700637cbSDimitry Andric #include "Function.h"
23*700637cbSDimitry Andric #include "InterpBuiltinBitCast.h"
24*700637cbSDimitry Andric #include "InterpFrame.h"
25*700637cbSDimitry Andric #include "InterpStack.h"
26*700637cbSDimitry Andric #include "InterpState.h"
27*700637cbSDimitry Andric #include "MemberPointer.h"
28*700637cbSDimitry Andric #include "Opcode.h"
29*700637cbSDimitry Andric #include "PrimType.h"
30*700637cbSDimitry Andric #include "Program.h"
31*700637cbSDimitry Andric #include "State.h"
32*700637cbSDimitry Andric #include "clang/AST/ASTContext.h"
33*700637cbSDimitry Andric #include "clang/AST/Expr.h"
34*700637cbSDimitry Andric #include "llvm/ADT/APFloat.h"
35*700637cbSDimitry Andric #include "llvm/ADT/APSInt.h"
36*700637cbSDimitry Andric #include <type_traits>
37*700637cbSDimitry Andric 
38*700637cbSDimitry Andric namespace clang {
39*700637cbSDimitry Andric namespace interp {
40*700637cbSDimitry Andric 
41*700637cbSDimitry Andric using APSInt = llvm::APSInt;
42*700637cbSDimitry Andric using FixedPointSemantics = llvm::FixedPointSemantics;
43*700637cbSDimitry Andric 
44*700637cbSDimitry Andric /// Checks if the variable has externally defined storage.
45*700637cbSDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
46*700637cbSDimitry Andric 
47*700637cbSDimitry Andric /// Checks if the array is offsetable.
48*700637cbSDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
49*700637cbSDimitry Andric 
50*700637cbSDimitry Andric /// Checks if a pointer is live and accessible.
51*700637cbSDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
52*700637cbSDimitry Andric                AccessKinds AK);
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric /// Checks if a pointer is a dummy pointer.
55*700637cbSDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
56*700637cbSDimitry Andric                 AccessKinds AK);
57*700637cbSDimitry Andric 
58*700637cbSDimitry Andric /// Checks if a pointer is null.
59*700637cbSDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
60*700637cbSDimitry Andric                CheckSubobjectKind CSK);
61*700637cbSDimitry Andric 
62*700637cbSDimitry Andric /// Checks if a pointer is in range.
63*700637cbSDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
64*700637cbSDimitry Andric                 AccessKinds AK);
65*700637cbSDimitry Andric 
66*700637cbSDimitry Andric /// Checks if a field from which a pointer is going to be derived is valid.
67*700637cbSDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
68*700637cbSDimitry Andric                 CheckSubobjectKind CSK);
69*700637cbSDimitry Andric 
70*700637cbSDimitry Andric /// Checks if Ptr is a one-past-the-end pointer.
71*700637cbSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
72*700637cbSDimitry Andric                     CheckSubobjectKind CSK);
73*700637cbSDimitry Andric 
74*700637cbSDimitry Andric /// Checks if the dowcast using the given offset is possible with the given
75*700637cbSDimitry Andric /// pointer.
76*700637cbSDimitry Andric bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
77*700637cbSDimitry Andric                    uint32_t Offset);
78*700637cbSDimitry Andric 
79*700637cbSDimitry Andric /// Checks if a pointer points to const storage.
80*700637cbSDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
81*700637cbSDimitry Andric 
82*700637cbSDimitry Andric /// Checks if the Descriptor is of a constexpr or const global variable.
83*700637cbSDimitry Andric bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);
84*700637cbSDimitry Andric 
85*700637cbSDimitry Andric /// Checks if a pointer points to a mutable field.
86*700637cbSDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
87*700637cbSDimitry Andric 
88*700637cbSDimitry Andric /// Checks if a value can be loaded from a block.
89*700637cbSDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
90*700637cbSDimitry Andric                AccessKinds AK = AK_Read);
91*700637cbSDimitry Andric bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
92*700637cbSDimitry Andric 
93*700637cbSDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
94*700637cbSDimitry Andric                       AccessKinds AK);
95*700637cbSDimitry Andric /// Check if a global variable is initialized.
96*700637cbSDimitry Andric bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
97*700637cbSDimitry Andric 
98*700637cbSDimitry Andric /// Checks if a value can be stored in a block.
99*700637cbSDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
100*700637cbSDimitry Andric 
101*700637cbSDimitry Andric /// Checks if a method can be invoked on an object.
102*700637cbSDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
103*700637cbSDimitry Andric 
104*700637cbSDimitry Andric /// Checks if a value can be initialized.
105*700637cbSDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
106*700637cbSDimitry Andric 
107*700637cbSDimitry Andric /// Checks if a method can be called.
108*700637cbSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
109*700637cbSDimitry Andric 
110*700637cbSDimitry Andric /// Checks if calling the currently active function would exceed
111*700637cbSDimitry Andric /// the allowed call depth.
112*700637cbSDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC);
113*700637cbSDimitry Andric 
114*700637cbSDimitry Andric /// Checks the 'this' pointer.
115*700637cbSDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
116*700637cbSDimitry Andric 
117*700637cbSDimitry Andric /// Checks if all the arguments annotated as 'nonnull' are in fact not null.
118*700637cbSDimitry Andric bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
119*700637cbSDimitry Andric                       const CallExpr *CE, unsigned ArgSize);
120*700637cbSDimitry Andric 
121*700637cbSDimitry Andric /// Checks if dynamic memory allocation is available in the current
122*700637cbSDimitry Andric /// language mode.
123*700637cbSDimitry Andric bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);
124*700637cbSDimitry Andric 
125*700637cbSDimitry Andric /// Diagnose mismatched new[]/delete or new/delete[] pairs.
126*700637cbSDimitry Andric bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
127*700637cbSDimitry Andric                          DynamicAllocator::Form AllocForm,
128*700637cbSDimitry Andric                          DynamicAllocator::Form DeleteForm, const Descriptor *D,
129*700637cbSDimitry Andric                          const Expr *NewExpr);
130*700637cbSDimitry Andric 
131*700637cbSDimitry Andric /// Check the source of the pointer passed to delete/delete[] has actually
132*700637cbSDimitry Andric /// been heap allocated by us.
133*700637cbSDimitry Andric bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
134*700637cbSDimitry Andric                        const Pointer &Ptr);
135*700637cbSDimitry Andric 
136*700637cbSDimitry Andric bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
137*700637cbSDimitry Andric                  AccessKinds AK);
138*700637cbSDimitry Andric 
139*700637cbSDimitry Andric /// Sets the given integral value to the pointer, which is of
140*700637cbSDimitry Andric /// a std::{weak,partial,strong}_ordering type.
141*700637cbSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
142*700637cbSDimitry Andric                                 const Pointer &Ptr, const APSInt &IntValue);
143*700637cbSDimitry Andric 
144*700637cbSDimitry Andric /// Copy the contents of Src into Dest.
145*700637cbSDimitry Andric bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);
146*700637cbSDimitry Andric 
147*700637cbSDimitry Andric bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
148*700637cbSDimitry Andric              uint32_t VarArgSize);
149*700637cbSDimitry Andric bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
150*700637cbSDimitry Andric           uint32_t VarArgSize);
151*700637cbSDimitry Andric bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
152*700637cbSDimitry Andric               uint32_t VarArgSize);
153*700637cbSDimitry Andric bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,
154*700637cbSDimitry Andric             uint32_t BuiltinID);
155*700637cbSDimitry Andric bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
156*700637cbSDimitry Andric              const CallExpr *CE);
157*700637cbSDimitry Andric bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
158*700637cbSDimitry Andric bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
159*700637cbSDimitry Andric bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
160*700637cbSDimitry Andric                   bool TargetIsUCharOrByte);
161*700637cbSDimitry Andric bool CheckBCPResult(InterpState &S, const Pointer &Ptr);
162*700637cbSDimitry Andric bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
163*700637cbSDimitry Andric 
164*700637cbSDimitry Andric template <typename T>
handleOverflow(InterpState & S,CodePtr OpPC,const T & SrcValue)165*700637cbSDimitry Andric static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
166*700637cbSDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
167*700637cbSDimitry Andric   S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();
168*700637cbSDimitry Andric   return S.noteUndefinedBehavior();
169*700637cbSDimitry Andric }
170*700637cbSDimitry Andric bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
171*700637cbSDimitry Andric                               const FixedPoint &FP);
172*700637cbSDimitry Andric 
173*700637cbSDimitry Andric bool isConstexprUnknown(const Pointer &P);
174*700637cbSDimitry Andric 
175*700637cbSDimitry Andric inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems);
176*700637cbSDimitry Andric 
177*700637cbSDimitry Andric enum class ShiftDir { Left, Right };
178*700637cbSDimitry Andric 
179*700637cbSDimitry Andric /// Checks if the shift operation is legal.
180*700637cbSDimitry Andric template <ShiftDir Dir, typename LT, typename RT>
CheckShift(InterpState & S,CodePtr OpPC,const LT & LHS,const RT & RHS,unsigned Bits)181*700637cbSDimitry Andric bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
182*700637cbSDimitry Andric                 unsigned Bits) {
183*700637cbSDimitry Andric   if (RHS.isNegative()) {
184*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
185*700637cbSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
186*700637cbSDimitry Andric     if (!S.noteUndefinedBehavior())
187*700637cbSDimitry Andric       return false;
188*700637cbSDimitry Andric   }
189*700637cbSDimitry Andric 
190*700637cbSDimitry Andric   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
191*700637cbSDimitry Andric   // the shifted type.
192*700637cbSDimitry Andric   if (Bits > 1 && RHS >= Bits) {
193*700637cbSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
194*700637cbSDimitry Andric     const APSInt Val = RHS.toAPSInt();
195*700637cbSDimitry Andric     QualType Ty = E->getType();
196*700637cbSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
197*700637cbSDimitry Andric     if (!S.noteUndefinedBehavior())
198*700637cbSDimitry Andric       return false;
199*700637cbSDimitry Andric   }
200*700637cbSDimitry Andric 
201*700637cbSDimitry Andric   if constexpr (Dir == ShiftDir::Left) {
202*700637cbSDimitry Andric     if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
203*700637cbSDimitry Andric       // C++11 [expr.shift]p2: A signed left shift must have a non-negative
204*700637cbSDimitry Andric       // operand, and must not overflow the corresponding unsigned type.
205*700637cbSDimitry Andric       if (LHS.isNegative()) {
206*700637cbSDimitry Andric         const Expr *E = S.Current->getExpr(OpPC);
207*700637cbSDimitry Andric         S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
208*700637cbSDimitry Andric         if (!S.noteUndefinedBehavior())
209*700637cbSDimitry Andric           return false;
210*700637cbSDimitry Andric       } else if (LHS.toUnsigned().countLeadingZeros() <
211*700637cbSDimitry Andric                  static_cast<unsigned>(RHS)) {
212*700637cbSDimitry Andric         const Expr *E = S.Current->getExpr(OpPC);
213*700637cbSDimitry Andric         S.CCEDiag(E, diag::note_constexpr_lshift_discards);
214*700637cbSDimitry Andric         if (!S.noteUndefinedBehavior())
215*700637cbSDimitry Andric           return false;
216*700637cbSDimitry Andric       }
217*700637cbSDimitry Andric     }
218*700637cbSDimitry Andric   }
219*700637cbSDimitry Andric 
220*700637cbSDimitry Andric   // C++2a [expr.shift]p2: [P0907R4]:
221*700637cbSDimitry Andric   //    E1 << E2 is the unique value congruent to
222*700637cbSDimitry Andric   //    E1 x 2^E2 module 2^N.
223*700637cbSDimitry Andric   return true;
224*700637cbSDimitry Andric }
225*700637cbSDimitry Andric 
226*700637cbSDimitry Andric /// Checks if Div/Rem operation on LHS and RHS is valid.
227*700637cbSDimitry Andric template <typename T>
CheckDivRem(InterpState & S,CodePtr OpPC,const T & LHS,const T & RHS)228*700637cbSDimitry Andric bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
229*700637cbSDimitry Andric   if (RHS.isZero()) {
230*700637cbSDimitry Andric     const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));
231*700637cbSDimitry Andric     if constexpr (std::is_same_v<T, Floating>) {
232*700637cbSDimitry Andric       S.CCEDiag(Op, diag::note_expr_divide_by_zero)
233*700637cbSDimitry Andric           << Op->getRHS()->getSourceRange();
234*700637cbSDimitry Andric       return true;
235*700637cbSDimitry Andric     }
236*700637cbSDimitry Andric 
237*700637cbSDimitry Andric     S.FFDiag(Op, diag::note_expr_divide_by_zero)
238*700637cbSDimitry Andric         << Op->getRHS()->getSourceRange();
239*700637cbSDimitry Andric     return false;
240*700637cbSDimitry Andric   }
241*700637cbSDimitry Andric 
242*700637cbSDimitry Andric   if constexpr (!std::is_same_v<T, FixedPoint>) {
243*700637cbSDimitry Andric     if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
244*700637cbSDimitry Andric       APSInt LHSInt = LHS.toAPSInt();
245*700637cbSDimitry Andric       SmallString<32> Trunc;
246*700637cbSDimitry Andric       (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
247*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
248*700637cbSDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
249*700637cbSDimitry Andric       S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
250*700637cbSDimitry Andric       return false;
251*700637cbSDimitry Andric     }
252*700637cbSDimitry Andric   }
253*700637cbSDimitry Andric   return true;
254*700637cbSDimitry Andric }
255*700637cbSDimitry Andric 
256*700637cbSDimitry Andric template <typename SizeT>
CheckArraySize(InterpState & S,CodePtr OpPC,SizeT * NumElements,unsigned ElemSize,bool IsNoThrow)257*700637cbSDimitry Andric bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
258*700637cbSDimitry Andric                     unsigned ElemSize, bool IsNoThrow) {
259*700637cbSDimitry Andric   // FIXME: Both the SizeT::from() as well as the
260*700637cbSDimitry Andric   // NumElements.toAPSInt() in this function are rather expensive.
261*700637cbSDimitry Andric 
262*700637cbSDimitry Andric   // Can't be too many elements if the bitwidth of NumElements is lower than
263*700637cbSDimitry Andric   // that of Descriptor::MaxArrayElemBytes.
264*700637cbSDimitry Andric   if ((NumElements->bitWidth() - NumElements->isSigned()) <
265*700637cbSDimitry Andric       (sizeof(Descriptor::MaxArrayElemBytes) * 8))
266*700637cbSDimitry Andric     return true;
267*700637cbSDimitry Andric 
268*700637cbSDimitry Andric   // FIXME: GH63562
269*700637cbSDimitry Andric   // APValue stores array extents as unsigned,
270*700637cbSDimitry Andric   // so anything that is greater that unsigned would overflow when
271*700637cbSDimitry Andric   // constructing the array, we catch this here.
272*700637cbSDimitry Andric   SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);
273*700637cbSDimitry Andric   assert(MaxElements.isPositive());
274*700637cbSDimitry Andric   if (NumElements->toAPSInt().getActiveBits() >
275*700637cbSDimitry Andric           ConstantArrayType::getMaxSizeBits(S.getASTContext()) ||
276*700637cbSDimitry Andric       *NumElements > MaxElements) {
277*700637cbSDimitry Andric     if (!IsNoThrow) {
278*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
279*700637cbSDimitry Andric 
280*700637cbSDimitry Andric       if (NumElements->isSigned() && NumElements->isNegative()) {
281*700637cbSDimitry Andric         S.FFDiag(Loc, diag::note_constexpr_new_negative)
282*700637cbSDimitry Andric             << NumElements->toDiagnosticString(S.getASTContext());
283*700637cbSDimitry Andric       } else {
284*700637cbSDimitry Andric         S.FFDiag(Loc, diag::note_constexpr_new_too_large)
285*700637cbSDimitry Andric             << NumElements->toDiagnosticString(S.getASTContext());
286*700637cbSDimitry Andric       }
287*700637cbSDimitry Andric     }
288*700637cbSDimitry Andric     return false;
289*700637cbSDimitry Andric   }
290*700637cbSDimitry Andric   return true;
291*700637cbSDimitry Andric }
292*700637cbSDimitry Andric 
293*700637cbSDimitry Andric /// Checks if the result of a floating-point operation is valid
294*700637cbSDimitry Andric /// in the current context.
295*700637cbSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
296*700637cbSDimitry Andric                       APFloat::opStatus Status, FPOptions FPO);
297*700637cbSDimitry Andric 
298*700637cbSDimitry Andric /// Checks why the given DeclRefExpr is invalid.
299*700637cbSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
300*700637cbSDimitry Andric 
301*700637cbSDimitry Andric /// Interpreter entry point.
302*700637cbSDimitry Andric bool Interpret(InterpState &S);
303*700637cbSDimitry Andric 
304*700637cbSDimitry Andric /// Interpret a builtin function.
305*700637cbSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
306*700637cbSDimitry Andric                       uint32_t BuiltinID);
307*700637cbSDimitry Andric 
308*700637cbSDimitry Andric /// Interpret an offsetof operation.
309*700637cbSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
310*700637cbSDimitry Andric                        ArrayRef<int64_t> ArrayIndices, int64_t &Result);
311*700637cbSDimitry Andric 
312*700637cbSDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC);
313*700637cbSDimitry Andric 
314*700637cbSDimitry Andric enum class ArithOp { Add, Sub };
315*700637cbSDimitry Andric 
316*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
317*700637cbSDimitry Andric // Returning values
318*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
319*700637cbSDimitry Andric 
320*700637cbSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
321*700637cbSDimitry Andric                               const Function *Func);
322*700637cbSDimitry Andric 
323*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Ret(InterpState & S,CodePtr & PC)324*700637cbSDimitry Andric bool Ret(InterpState &S, CodePtr &PC) {
325*700637cbSDimitry Andric   const T &Ret = S.Stk.pop<T>();
326*700637cbSDimitry Andric 
327*700637cbSDimitry Andric   assert(S.Current);
328*700637cbSDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
329*700637cbSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
330*700637cbSDimitry Andric     cleanupAfterFunctionCall(S, PC, S.Current->getFunction());
331*700637cbSDimitry Andric 
332*700637cbSDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
333*700637cbSDimitry Andric     PC = S.Current->getRetPC();
334*700637cbSDimitry Andric     InterpFrame::free(S.Current);
335*700637cbSDimitry Andric     S.Current = Caller;
336*700637cbSDimitry Andric     S.Stk.push<T>(Ret);
337*700637cbSDimitry Andric   } else {
338*700637cbSDimitry Andric     InterpFrame::free(S.Current);
339*700637cbSDimitry Andric     S.Current = nullptr;
340*700637cbSDimitry Andric     // The topmost frame should come from an EvalEmitter,
341*700637cbSDimitry Andric     // which has its own implementation of the Ret<> instruction.
342*700637cbSDimitry Andric   }
343*700637cbSDimitry Andric   return true;
344*700637cbSDimitry Andric }
345*700637cbSDimitry Andric 
RetVoid(InterpState & S,CodePtr & PC)346*700637cbSDimitry Andric inline bool RetVoid(InterpState &S, CodePtr &PC) {
347*700637cbSDimitry Andric   assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
348*700637cbSDimitry Andric 
349*700637cbSDimitry Andric   if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
350*700637cbSDimitry Andric     cleanupAfterFunctionCall(S, PC, S.Current->getFunction());
351*700637cbSDimitry Andric 
352*700637cbSDimitry Andric   if (InterpFrame *Caller = S.Current->Caller) {
353*700637cbSDimitry Andric     PC = S.Current->getRetPC();
354*700637cbSDimitry Andric     InterpFrame::free(S.Current);
355*700637cbSDimitry Andric     S.Current = Caller;
356*700637cbSDimitry Andric   } else {
357*700637cbSDimitry Andric     InterpFrame::free(S.Current);
358*700637cbSDimitry Andric     S.Current = nullptr;
359*700637cbSDimitry Andric   }
360*700637cbSDimitry Andric   return true;
361*700637cbSDimitry Andric }
362*700637cbSDimitry Andric 
363*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
364*700637cbSDimitry Andric // Add, Sub, Mul
365*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
366*700637cbSDimitry Andric 
367*700637cbSDimitry Andric template <typename T, bool (*OpFW)(T, T, unsigned, T *),
368*700637cbSDimitry Andric           template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)369*700637cbSDimitry Andric bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
370*700637cbSDimitry Andric                      const T &RHS) {
371*700637cbSDimitry Andric   // Fast path - add the numbers with fixed width.
372*700637cbSDimitry Andric   T Result;
373*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
374*700637cbSDimitry Andric     Result = S.allocAP<T>(LHS.bitWidth());
375*700637cbSDimitry Andric 
376*700637cbSDimitry Andric   if (!OpFW(LHS, RHS, Bits, &Result)) {
377*700637cbSDimitry Andric     S.Stk.push<T>(Result);
378*700637cbSDimitry Andric     return true;
379*700637cbSDimitry Andric   }
380*700637cbSDimitry Andric   // If for some reason evaluation continues, use the truncated results.
381*700637cbSDimitry Andric   S.Stk.push<T>(Result);
382*700637cbSDimitry Andric 
383*700637cbSDimitry Andric   // Short-circuit fixed-points here since the error handling is easier.
384*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, FixedPoint>)
385*700637cbSDimitry Andric     return handleFixedPointOverflow(S, OpPC, Result);
386*700637cbSDimitry Andric 
387*700637cbSDimitry Andric   // Slow path - compute the result using another bit of precision.
388*700637cbSDimitry Andric   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
389*700637cbSDimitry Andric 
390*700637cbSDimitry Andric   // Report undefined behaviour, stopping if required.
391*700637cbSDimitry Andric   if (S.checkingForUndefinedBehavior()) {
392*700637cbSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
393*700637cbSDimitry Andric     QualType Type = E->getType();
394*700637cbSDimitry Andric     SmallString<32> Trunc;
395*700637cbSDimitry Andric     Value.trunc(Result.bitWidth())
396*700637cbSDimitry Andric         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
397*700637cbSDimitry Andric                   /*UpperCase=*/true, /*InsertSeparators=*/true);
398*700637cbSDimitry Andric     S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
399*700637cbSDimitry Andric         << Trunc << Type << E->getSourceRange();
400*700637cbSDimitry Andric   }
401*700637cbSDimitry Andric 
402*700637cbSDimitry Andric   if (!handleOverflow(S, OpPC, Value)) {
403*700637cbSDimitry Andric     S.Stk.pop<T>();
404*700637cbSDimitry Andric     return false;
405*700637cbSDimitry Andric   }
406*700637cbSDimitry Andric   return true;
407*700637cbSDimitry Andric }
408*700637cbSDimitry Andric 
409*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)410*700637cbSDimitry Andric bool Add(InterpState &S, CodePtr OpPC) {
411*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
412*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
413*700637cbSDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
414*700637cbSDimitry Andric 
415*700637cbSDimitry Andric   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
416*700637cbSDimitry Andric }
417*700637cbSDimitry Andric 
getRoundingMode(FPOptions FPO)418*700637cbSDimitry Andric static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {
419*700637cbSDimitry Andric   auto RM = FPO.getRoundingMode();
420*700637cbSDimitry Andric   if (RM == llvm::RoundingMode::Dynamic)
421*700637cbSDimitry Andric     return llvm::RoundingMode::NearestTiesToEven;
422*700637cbSDimitry Andric   return RM;
423*700637cbSDimitry Andric }
424*700637cbSDimitry Andric 
Addf(InterpState & S,CodePtr OpPC,uint32_t FPOI)425*700637cbSDimitry Andric inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
426*700637cbSDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
427*700637cbSDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
428*700637cbSDimitry Andric 
429*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
430*700637cbSDimitry Andric   Floating Result = S.allocFloat(LHS.getSemantics());
431*700637cbSDimitry Andric   auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);
432*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
433*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status, FPO);
434*700637cbSDimitry Andric }
435*700637cbSDimitry Andric 
436*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)437*700637cbSDimitry Andric bool Sub(InterpState &S, CodePtr OpPC) {
438*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
439*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
440*700637cbSDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
441*700637cbSDimitry Andric 
442*700637cbSDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
443*700637cbSDimitry Andric }
444*700637cbSDimitry Andric 
Subf(InterpState & S,CodePtr OpPC,uint32_t FPOI)445*700637cbSDimitry Andric inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
446*700637cbSDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
447*700637cbSDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
448*700637cbSDimitry Andric 
449*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
450*700637cbSDimitry Andric   Floating Result = S.allocFloat(LHS.getSemantics());
451*700637cbSDimitry Andric   auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);
452*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
453*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status, FPO);
454*700637cbSDimitry Andric }
455*700637cbSDimitry Andric 
456*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)457*700637cbSDimitry Andric bool Mul(InterpState &S, CodePtr OpPC) {
458*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
459*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
460*700637cbSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
461*700637cbSDimitry Andric 
462*700637cbSDimitry Andric   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
463*700637cbSDimitry Andric }
464*700637cbSDimitry Andric 
Mulf(InterpState & S,CodePtr OpPC,uint32_t FPOI)465*700637cbSDimitry Andric inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
466*700637cbSDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
467*700637cbSDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
468*700637cbSDimitry Andric 
469*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
470*700637cbSDimitry Andric   Floating Result = S.allocFloat(LHS.getSemantics());
471*700637cbSDimitry Andric 
472*700637cbSDimitry Andric   auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);
473*700637cbSDimitry Andric 
474*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
475*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status, FPO);
476*700637cbSDimitry Andric }
477*700637cbSDimitry Andric 
478*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Mulc(InterpState & S,CodePtr OpPC)479*700637cbSDimitry Andric inline bool Mulc(InterpState &S, CodePtr OpPC) {
480*700637cbSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
481*700637cbSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
482*700637cbSDimitry Andric   const Pointer &Result = S.Stk.peek<Pointer>();
483*700637cbSDimitry Andric 
484*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Floating>) {
485*700637cbSDimitry Andric     APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
486*700637cbSDimitry Andric     APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
487*700637cbSDimitry Andric     APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
488*700637cbSDimitry Andric     APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
489*700637cbSDimitry Andric 
490*700637cbSDimitry Andric     APFloat ResR(A.getSemantics());
491*700637cbSDimitry Andric     APFloat ResI(A.getSemantics());
492*700637cbSDimitry Andric     HandleComplexComplexMul(A, B, C, D, ResR, ResI);
493*700637cbSDimitry Andric 
494*700637cbSDimitry Andric     // Copy into the result.
495*700637cbSDimitry Andric     Floating RA = S.allocFloat(A.getSemantics());
496*700637cbSDimitry Andric     RA.copy(ResR);
497*700637cbSDimitry Andric     Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);
498*700637cbSDimitry Andric     Result.atIndex(0).initialize();
499*700637cbSDimitry Andric 
500*700637cbSDimitry Andric     Floating RI = S.allocFloat(A.getSemantics());
501*700637cbSDimitry Andric     RI.copy(ResI);
502*700637cbSDimitry Andric     Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);
503*700637cbSDimitry Andric     Result.atIndex(1).initialize();
504*700637cbSDimitry Andric     Result.initialize();
505*700637cbSDimitry Andric   } else {
506*700637cbSDimitry Andric     // Integer element type.
507*700637cbSDimitry Andric     const T &LHSR = LHS.atIndex(0).deref<T>();
508*700637cbSDimitry Andric     const T &LHSI = LHS.atIndex(1).deref<T>();
509*700637cbSDimitry Andric     const T &RHSR = RHS.atIndex(0).deref<T>();
510*700637cbSDimitry Andric     const T &RHSI = RHS.atIndex(1).deref<T>();
511*700637cbSDimitry Andric     unsigned Bits = LHSR.bitWidth();
512*700637cbSDimitry Andric 
513*700637cbSDimitry Andric     // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))
514*700637cbSDimitry Andric     T A;
515*700637cbSDimitry Andric     if (T::mul(LHSR, RHSR, Bits, &A))
516*700637cbSDimitry Andric       return false;
517*700637cbSDimitry Andric     T B;
518*700637cbSDimitry Andric     if (T::mul(LHSI, RHSI, Bits, &B))
519*700637cbSDimitry Andric       return false;
520*700637cbSDimitry Andric     if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))
521*700637cbSDimitry Andric       return false;
522*700637cbSDimitry Andric     Result.atIndex(0).initialize();
523*700637cbSDimitry Andric 
524*700637cbSDimitry Andric     // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))
525*700637cbSDimitry Andric     if (T::mul(LHSR, RHSI, Bits, &A))
526*700637cbSDimitry Andric       return false;
527*700637cbSDimitry Andric     if (T::mul(LHSI, RHSR, Bits, &B))
528*700637cbSDimitry Andric       return false;
529*700637cbSDimitry Andric     if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))
530*700637cbSDimitry Andric       return false;
531*700637cbSDimitry Andric     Result.atIndex(1).initialize();
532*700637cbSDimitry Andric     Result.initialize();
533*700637cbSDimitry Andric   }
534*700637cbSDimitry Andric 
535*700637cbSDimitry Andric   return true;
536*700637cbSDimitry Andric }
537*700637cbSDimitry Andric 
538*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Divc(InterpState & S,CodePtr OpPC)539*700637cbSDimitry Andric inline bool Divc(InterpState &S, CodePtr OpPC) {
540*700637cbSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
541*700637cbSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
542*700637cbSDimitry Andric   const Pointer &Result = S.Stk.peek<Pointer>();
543*700637cbSDimitry Andric 
544*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Floating>) {
545*700637cbSDimitry Andric     APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();
546*700637cbSDimitry Andric     APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();
547*700637cbSDimitry Andric     APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();
548*700637cbSDimitry Andric     APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();
549*700637cbSDimitry Andric 
550*700637cbSDimitry Andric     APFloat ResR(A.getSemantics());
551*700637cbSDimitry Andric     APFloat ResI(A.getSemantics());
552*700637cbSDimitry Andric     HandleComplexComplexDiv(A, B, C, D, ResR, ResI);
553*700637cbSDimitry Andric 
554*700637cbSDimitry Andric     // Copy into the result.
555*700637cbSDimitry Andric     Floating RA = S.allocFloat(A.getSemantics());
556*700637cbSDimitry Andric     RA.copy(ResR);
557*700637cbSDimitry Andric     Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);
558*700637cbSDimitry Andric     Result.atIndex(0).initialize();
559*700637cbSDimitry Andric 
560*700637cbSDimitry Andric     Floating RI = S.allocFloat(A.getSemantics());
561*700637cbSDimitry Andric     RI.copy(ResI);
562*700637cbSDimitry Andric     Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);
563*700637cbSDimitry Andric     Result.atIndex(1).initialize();
564*700637cbSDimitry Andric 
565*700637cbSDimitry Andric     Result.initialize();
566*700637cbSDimitry Andric   } else {
567*700637cbSDimitry Andric     // Integer element type.
568*700637cbSDimitry Andric     const T &LHSR = LHS.atIndex(0).deref<T>();
569*700637cbSDimitry Andric     const T &LHSI = LHS.atIndex(1).deref<T>();
570*700637cbSDimitry Andric     const T &RHSR = RHS.atIndex(0).deref<T>();
571*700637cbSDimitry Andric     const T &RHSI = RHS.atIndex(1).deref<T>();
572*700637cbSDimitry Andric     unsigned Bits = LHSR.bitWidth();
573*700637cbSDimitry Andric     const T Zero = T::from(0, Bits);
574*700637cbSDimitry Andric 
575*700637cbSDimitry Andric     if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&
576*700637cbSDimitry Andric         Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {
577*700637cbSDimitry Andric       const SourceInfo &E = S.Current->getSource(OpPC);
578*700637cbSDimitry Andric       S.FFDiag(E, diag::note_expr_divide_by_zero);
579*700637cbSDimitry Andric       return false;
580*700637cbSDimitry Andric     }
581*700637cbSDimitry Andric 
582*700637cbSDimitry Andric     // Den = real(RHS)² + imag(RHS)²
583*700637cbSDimitry Andric     T A, B;
584*700637cbSDimitry Andric     if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {
585*700637cbSDimitry Andric       // Ignore overflow here, because that's what the current interpeter does.
586*700637cbSDimitry Andric     }
587*700637cbSDimitry Andric     T Den;
588*700637cbSDimitry Andric     if (T::add(A, B, Bits, &Den))
589*700637cbSDimitry Andric       return false;
590*700637cbSDimitry Andric 
591*700637cbSDimitry Andric     if (Compare(Den, Zero) == ComparisonCategoryResult::Equal) {
592*700637cbSDimitry Andric       const SourceInfo &E = S.Current->getSource(OpPC);
593*700637cbSDimitry Andric       S.FFDiag(E, diag::note_expr_divide_by_zero);
594*700637cbSDimitry Andric       return false;
595*700637cbSDimitry Andric     }
596*700637cbSDimitry Andric 
597*700637cbSDimitry Andric     // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den
598*700637cbSDimitry Andric     T &ResultR = Result.atIndex(0).deref<T>();
599*700637cbSDimitry Andric     T &ResultI = Result.atIndex(1).deref<T>();
600*700637cbSDimitry Andric 
601*700637cbSDimitry Andric     if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))
602*700637cbSDimitry Andric       return false;
603*700637cbSDimitry Andric     if (T::add(A, B, Bits, &ResultR))
604*700637cbSDimitry Andric       return false;
605*700637cbSDimitry Andric     if (T::div(ResultR, Den, Bits, &ResultR))
606*700637cbSDimitry Andric       return false;
607*700637cbSDimitry Andric     Result.atIndex(0).initialize();
608*700637cbSDimitry Andric 
609*700637cbSDimitry Andric     // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den
610*700637cbSDimitry Andric     if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))
611*700637cbSDimitry Andric       return false;
612*700637cbSDimitry Andric     if (T::sub(A, B, Bits, &ResultI))
613*700637cbSDimitry Andric       return false;
614*700637cbSDimitry Andric     if (T::div(ResultI, Den, Bits, &ResultI))
615*700637cbSDimitry Andric       return false;
616*700637cbSDimitry Andric     Result.atIndex(1).initialize();
617*700637cbSDimitry Andric     Result.initialize();
618*700637cbSDimitry Andric   }
619*700637cbSDimitry Andric 
620*700637cbSDimitry Andric   return true;
621*700637cbSDimitry Andric }
622*700637cbSDimitry Andric 
623*700637cbSDimitry Andric /// 1) Pops the RHS from the stack.
624*700637cbSDimitry Andric /// 2) Pops the LHS from the stack.
625*700637cbSDimitry Andric /// 3) Pushes 'LHS & RHS' on the stack
626*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
BitAnd(InterpState & S,CodePtr OpPC)627*700637cbSDimitry Andric bool BitAnd(InterpState &S, CodePtr OpPC) {
628*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
629*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
630*700637cbSDimitry Andric   unsigned Bits = RHS.bitWidth();
631*700637cbSDimitry Andric 
632*700637cbSDimitry Andric   T Result;
633*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
634*700637cbSDimitry Andric     Result = S.allocAP<T>(Bits);
635*700637cbSDimitry Andric 
636*700637cbSDimitry Andric   if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
637*700637cbSDimitry Andric     S.Stk.push<T>(Result);
638*700637cbSDimitry Andric     return true;
639*700637cbSDimitry Andric   }
640*700637cbSDimitry Andric   return false;
641*700637cbSDimitry Andric }
642*700637cbSDimitry Andric 
643*700637cbSDimitry Andric /// 1) Pops the RHS from the stack.
644*700637cbSDimitry Andric /// 2) Pops the LHS from the stack.
645*700637cbSDimitry Andric /// 3) Pushes 'LHS | RHS' on the stack
646*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
BitOr(InterpState & S,CodePtr OpPC)647*700637cbSDimitry Andric bool BitOr(InterpState &S, CodePtr OpPC) {
648*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
649*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
650*700637cbSDimitry Andric   unsigned Bits = RHS.bitWidth();
651*700637cbSDimitry Andric 
652*700637cbSDimitry Andric   T Result;
653*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
654*700637cbSDimitry Andric     Result = S.allocAP<T>(Bits);
655*700637cbSDimitry Andric 
656*700637cbSDimitry Andric   if (!T::bitOr(LHS, RHS, Bits, &Result)) {
657*700637cbSDimitry Andric     S.Stk.push<T>(Result);
658*700637cbSDimitry Andric     return true;
659*700637cbSDimitry Andric   }
660*700637cbSDimitry Andric   return false;
661*700637cbSDimitry Andric }
662*700637cbSDimitry Andric 
663*700637cbSDimitry Andric /// 1) Pops the RHS from the stack.
664*700637cbSDimitry Andric /// 2) Pops the LHS from the stack.
665*700637cbSDimitry Andric /// 3) Pushes 'LHS ^ RHS' on the stack
666*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
BitXor(InterpState & S,CodePtr OpPC)667*700637cbSDimitry Andric bool BitXor(InterpState &S, CodePtr OpPC) {
668*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
669*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
670*700637cbSDimitry Andric 
671*700637cbSDimitry Andric   unsigned Bits = RHS.bitWidth();
672*700637cbSDimitry Andric 
673*700637cbSDimitry Andric   T Result;
674*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
675*700637cbSDimitry Andric     Result = S.allocAP<T>(Bits);
676*700637cbSDimitry Andric 
677*700637cbSDimitry Andric   if (!T::bitXor(LHS, RHS, Bits, &Result)) {
678*700637cbSDimitry Andric     S.Stk.push<T>(Result);
679*700637cbSDimitry Andric     return true;
680*700637cbSDimitry Andric   }
681*700637cbSDimitry Andric   return false;
682*700637cbSDimitry Andric }
683*700637cbSDimitry Andric 
684*700637cbSDimitry Andric /// 1) Pops the RHS from the stack.
685*700637cbSDimitry Andric /// 2) Pops the LHS from the stack.
686*700637cbSDimitry Andric /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
687*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Rem(InterpState & S,CodePtr OpPC)688*700637cbSDimitry Andric bool Rem(InterpState &S, CodePtr OpPC) {
689*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
690*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
691*700637cbSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
692*700637cbSDimitry Andric 
693*700637cbSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
694*700637cbSDimitry Andric     return false;
695*700637cbSDimitry Andric 
696*700637cbSDimitry Andric   T Result;
697*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
698*700637cbSDimitry Andric     Result = S.allocAP<T>(LHS.bitWidth());
699*700637cbSDimitry Andric 
700*700637cbSDimitry Andric   if (!T::rem(LHS, RHS, Bits, &Result)) {
701*700637cbSDimitry Andric     S.Stk.push<T>(Result);
702*700637cbSDimitry Andric     return true;
703*700637cbSDimitry Andric   }
704*700637cbSDimitry Andric   return false;
705*700637cbSDimitry Andric }
706*700637cbSDimitry Andric 
707*700637cbSDimitry Andric /// 1) Pops the RHS from the stack.
708*700637cbSDimitry Andric /// 2) Pops the LHS from the stack.
709*700637cbSDimitry Andric /// 3) Pushes 'LHS / RHS' on the stack
710*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Div(InterpState & S,CodePtr OpPC)711*700637cbSDimitry Andric bool Div(InterpState &S, CodePtr OpPC) {
712*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
713*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
714*700637cbSDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
715*700637cbSDimitry Andric 
716*700637cbSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
717*700637cbSDimitry Andric     return false;
718*700637cbSDimitry Andric 
719*700637cbSDimitry Andric   T Result;
720*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
721*700637cbSDimitry Andric     Result = S.allocAP<T>(LHS.bitWidth());
722*700637cbSDimitry Andric 
723*700637cbSDimitry Andric   if (!T::div(LHS, RHS, Bits, &Result)) {
724*700637cbSDimitry Andric     S.Stk.push<T>(Result);
725*700637cbSDimitry Andric     return true;
726*700637cbSDimitry Andric   }
727*700637cbSDimitry Andric 
728*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, FixedPoint>) {
729*700637cbSDimitry Andric     if (handleFixedPointOverflow(S, OpPC, Result)) {
730*700637cbSDimitry Andric       S.Stk.push<T>(Result);
731*700637cbSDimitry Andric       return true;
732*700637cbSDimitry Andric     }
733*700637cbSDimitry Andric   }
734*700637cbSDimitry Andric   return false;
735*700637cbSDimitry Andric }
736*700637cbSDimitry Andric 
Divf(InterpState & S,CodePtr OpPC,uint32_t FPOI)737*700637cbSDimitry Andric inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
738*700637cbSDimitry Andric   const Floating &RHS = S.Stk.pop<Floating>();
739*700637cbSDimitry Andric   const Floating &LHS = S.Stk.pop<Floating>();
740*700637cbSDimitry Andric 
741*700637cbSDimitry Andric   if (!CheckDivRem(S, OpPC, LHS, RHS))
742*700637cbSDimitry Andric     return false;
743*700637cbSDimitry Andric 
744*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
745*700637cbSDimitry Andric 
746*700637cbSDimitry Andric   Floating Result = S.allocFloat(LHS.getSemantics());
747*700637cbSDimitry Andric   auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);
748*700637cbSDimitry Andric 
749*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
750*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status, FPO);
751*700637cbSDimitry Andric }
752*700637cbSDimitry Andric 
753*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
754*700637cbSDimitry Andric // Inv
755*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
756*700637cbSDimitry Andric 
Inv(InterpState & S,CodePtr OpPC)757*700637cbSDimitry Andric inline bool Inv(InterpState &S, CodePtr OpPC) {
758*700637cbSDimitry Andric   const auto &Val = S.Stk.pop<Boolean>();
759*700637cbSDimitry Andric   S.Stk.push<Boolean>(!Val);
760*700637cbSDimitry Andric   return true;
761*700637cbSDimitry Andric }
762*700637cbSDimitry Andric 
763*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
764*700637cbSDimitry Andric // Neg
765*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
766*700637cbSDimitry Andric 
767*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Neg(InterpState & S,CodePtr OpPC)768*700637cbSDimitry Andric bool Neg(InterpState &S, CodePtr OpPC) {
769*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
770*700637cbSDimitry Andric 
771*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Floating>) {
772*700637cbSDimitry Andric     T Result = S.allocFloat(Value.getSemantics());
773*700637cbSDimitry Andric 
774*700637cbSDimitry Andric     if (!T::neg(Value, &Result)) {
775*700637cbSDimitry Andric       S.Stk.push<T>(Result);
776*700637cbSDimitry Andric       return true;
777*700637cbSDimitry Andric     }
778*700637cbSDimitry Andric     return false;
779*700637cbSDimitry Andric   } else {
780*700637cbSDimitry Andric     T Result;
781*700637cbSDimitry Andric     if constexpr (needsAlloc<T>())
782*700637cbSDimitry Andric       Result = S.allocAP<T>(Value.bitWidth());
783*700637cbSDimitry Andric 
784*700637cbSDimitry Andric     if (!T::neg(Value, &Result)) {
785*700637cbSDimitry Andric       S.Stk.push<T>(Result);
786*700637cbSDimitry Andric       return true;
787*700637cbSDimitry Andric     }
788*700637cbSDimitry Andric 
789*700637cbSDimitry Andric     assert(isIntegralType(Name) &&
790*700637cbSDimitry Andric            "don't expect other types to fail at constexpr negation");
791*700637cbSDimitry Andric     S.Stk.push<T>(Result);
792*700637cbSDimitry Andric 
793*700637cbSDimitry Andric     APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);
794*700637cbSDimitry Andric     if (S.checkingForUndefinedBehavior()) {
795*700637cbSDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
796*700637cbSDimitry Andric       QualType Type = E->getType();
797*700637cbSDimitry Andric       SmallString<32> Trunc;
798*700637cbSDimitry Andric       NegatedValue.trunc(Result.bitWidth())
799*700637cbSDimitry Andric           .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
800*700637cbSDimitry Andric                     /*UpperCase=*/true, /*InsertSeparators=*/true);
801*700637cbSDimitry Andric       S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
802*700637cbSDimitry Andric           << Trunc << Type << E->getSourceRange();
803*700637cbSDimitry Andric       return true;
804*700637cbSDimitry Andric     }
805*700637cbSDimitry Andric 
806*700637cbSDimitry Andric     return handleOverflow(S, OpPC, NegatedValue);
807*700637cbSDimitry Andric   }
808*700637cbSDimitry Andric }
809*700637cbSDimitry Andric 
810*700637cbSDimitry Andric enum class PushVal : bool {
811*700637cbSDimitry Andric   No,
812*700637cbSDimitry Andric   Yes,
813*700637cbSDimitry Andric };
814*700637cbSDimitry Andric enum class IncDecOp {
815*700637cbSDimitry Andric   Inc,
816*700637cbSDimitry Andric   Dec,
817*700637cbSDimitry Andric };
818*700637cbSDimitry Andric 
819*700637cbSDimitry Andric template <typename T, IncDecOp Op, PushVal DoPush>
IncDecHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr,bool CanOverflow)820*700637cbSDimitry Andric bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
821*700637cbSDimitry Andric                   bool CanOverflow) {
822*700637cbSDimitry Andric   assert(!Ptr.isDummy());
823*700637cbSDimitry Andric 
824*700637cbSDimitry Andric   if (!S.inConstantContext()) {
825*700637cbSDimitry Andric     if (isConstexprUnknown(Ptr))
826*700637cbSDimitry Andric       return false;
827*700637cbSDimitry Andric   }
828*700637cbSDimitry Andric 
829*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Boolean>) {
830*700637cbSDimitry Andric     if (!S.getLangOpts().CPlusPlus14)
831*700637cbSDimitry Andric       return Invalid(S, OpPC);
832*700637cbSDimitry Andric   }
833*700637cbSDimitry Andric 
834*700637cbSDimitry Andric   const T &Value = Ptr.deref<T>();
835*700637cbSDimitry Andric   T Result;
836*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
837*700637cbSDimitry Andric     Result = S.allocAP<T>(Value.bitWidth());
838*700637cbSDimitry Andric 
839*700637cbSDimitry Andric   if constexpr (DoPush == PushVal::Yes)
840*700637cbSDimitry Andric     S.Stk.push<T>(Value);
841*700637cbSDimitry Andric 
842*700637cbSDimitry Andric   if constexpr (Op == IncDecOp::Inc) {
843*700637cbSDimitry Andric     if (!T::increment(Value, &Result) || !CanOverflow) {
844*700637cbSDimitry Andric       Ptr.deref<T>() = Result;
845*700637cbSDimitry Andric       return true;
846*700637cbSDimitry Andric     }
847*700637cbSDimitry Andric   } else {
848*700637cbSDimitry Andric     if (!T::decrement(Value, &Result) || !CanOverflow) {
849*700637cbSDimitry Andric       Ptr.deref<T>() = Result;
850*700637cbSDimitry Andric       return true;
851*700637cbSDimitry Andric     }
852*700637cbSDimitry Andric   }
853*700637cbSDimitry Andric   assert(CanOverflow);
854*700637cbSDimitry Andric 
855*700637cbSDimitry Andric   // Something went wrong with the previous operation. Compute the
856*700637cbSDimitry Andric   // result with another bit of precision.
857*700637cbSDimitry Andric   unsigned Bits = Value.bitWidth() + 1;
858*700637cbSDimitry Andric   APSInt APResult;
859*700637cbSDimitry Andric   if constexpr (Op == IncDecOp::Inc)
860*700637cbSDimitry Andric     APResult = ++Value.toAPSInt(Bits);
861*700637cbSDimitry Andric   else
862*700637cbSDimitry Andric     APResult = --Value.toAPSInt(Bits);
863*700637cbSDimitry Andric 
864*700637cbSDimitry Andric   // Report undefined behaviour, stopping if required.
865*700637cbSDimitry Andric   if (S.checkingForUndefinedBehavior()) {
866*700637cbSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
867*700637cbSDimitry Andric     QualType Type = E->getType();
868*700637cbSDimitry Andric     SmallString<32> Trunc;
869*700637cbSDimitry Andric     APResult.trunc(Result.bitWidth())
870*700637cbSDimitry Andric         .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,
871*700637cbSDimitry Andric                   /*UpperCase=*/true, /*InsertSeparators=*/true);
872*700637cbSDimitry Andric     S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)
873*700637cbSDimitry Andric         << Trunc << Type << E->getSourceRange();
874*700637cbSDimitry Andric     return true;
875*700637cbSDimitry Andric   }
876*700637cbSDimitry Andric   return handleOverflow(S, OpPC, APResult);
877*700637cbSDimitry Andric }
878*700637cbSDimitry Andric 
879*700637cbSDimitry Andric /// 1) Pops a pointer from the stack
880*700637cbSDimitry Andric /// 2) Load the value from the pointer
881*700637cbSDimitry Andric /// 3) Writes the value increased by one back to the pointer
882*700637cbSDimitry Andric /// 4) Pushes the original (pre-inc) value on the stack.
883*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Inc(InterpState & S,CodePtr OpPC,bool CanOverflow)884*700637cbSDimitry Andric bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
885*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
886*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
887*700637cbSDimitry Andric     return false;
888*700637cbSDimitry Andric 
889*700637cbSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr,
890*700637cbSDimitry Andric                                                       CanOverflow);
891*700637cbSDimitry Andric }
892*700637cbSDimitry Andric 
893*700637cbSDimitry Andric /// 1) Pops a pointer from the stack
894*700637cbSDimitry Andric /// 2) Load the value from the pointer
895*700637cbSDimitry Andric /// 3) Writes the value increased by one back to the pointer
896*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
IncPop(InterpState & S,CodePtr OpPC,bool CanOverflow)897*700637cbSDimitry Andric bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
898*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
899*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
900*700637cbSDimitry Andric     return false;
901*700637cbSDimitry Andric 
902*700637cbSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
903*700637cbSDimitry Andric }
904*700637cbSDimitry Andric 
905*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
PreInc(InterpState & S,CodePtr OpPC,bool CanOverflow)906*700637cbSDimitry Andric bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {
907*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
908*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
909*700637cbSDimitry Andric     return false;
910*700637cbSDimitry Andric 
911*700637cbSDimitry Andric   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);
912*700637cbSDimitry Andric }
913*700637cbSDimitry Andric 
914*700637cbSDimitry Andric /// 1) Pops a pointer from the stack
915*700637cbSDimitry Andric /// 2) Load the value from the pointer
916*700637cbSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
917*700637cbSDimitry Andric /// 4) Pushes the original (pre-dec) value on the stack.
918*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Dec(InterpState & S,CodePtr OpPC,bool CanOverflow)919*700637cbSDimitry Andric bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
920*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
921*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
922*700637cbSDimitry Andric     return false;
923*700637cbSDimitry Andric 
924*700637cbSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,
925*700637cbSDimitry Andric                                                       CanOverflow);
926*700637cbSDimitry Andric }
927*700637cbSDimitry Andric 
928*700637cbSDimitry Andric /// 1) Pops a pointer from the stack
929*700637cbSDimitry Andric /// 2) Load the value from the pointer
930*700637cbSDimitry Andric /// 3) Writes the value decreased by one back to the pointer
931*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
DecPop(InterpState & S,CodePtr OpPC,bool CanOverflow)932*700637cbSDimitry Andric bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {
933*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
934*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
935*700637cbSDimitry Andric     return false;
936*700637cbSDimitry Andric 
937*700637cbSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
938*700637cbSDimitry Andric }
939*700637cbSDimitry Andric 
940*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
PreDec(InterpState & S,CodePtr OpPC,bool CanOverflow)941*700637cbSDimitry Andric bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {
942*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
943*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
944*700637cbSDimitry Andric     return false;
945*700637cbSDimitry Andric   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);
946*700637cbSDimitry Andric }
947*700637cbSDimitry Andric 
948*700637cbSDimitry Andric template <IncDecOp Op, PushVal DoPush>
IncDecFloatHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr,uint32_t FPOI)949*700637cbSDimitry Andric bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
950*700637cbSDimitry Andric                        uint32_t FPOI) {
951*700637cbSDimitry Andric   Floating Value = Ptr.deref<Floating>();
952*700637cbSDimitry Andric   Floating Result = S.allocFloat(Value.getSemantics());
953*700637cbSDimitry Andric 
954*700637cbSDimitry Andric   if constexpr (DoPush == PushVal::Yes)
955*700637cbSDimitry Andric     S.Stk.push<Floating>(Value);
956*700637cbSDimitry Andric 
957*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
958*700637cbSDimitry Andric   llvm::APFloat::opStatus Status;
959*700637cbSDimitry Andric   if constexpr (Op == IncDecOp::Inc)
960*700637cbSDimitry Andric     Status = Floating::increment(Value, getRoundingMode(FPO), &Result);
961*700637cbSDimitry Andric   else
962*700637cbSDimitry Andric     Status = Floating::decrement(Value, getRoundingMode(FPO), &Result);
963*700637cbSDimitry Andric 
964*700637cbSDimitry Andric   Ptr.deref<Floating>() = Result;
965*700637cbSDimitry Andric 
966*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status, FPO);
967*700637cbSDimitry Andric }
968*700637cbSDimitry Andric 
Incf(InterpState & S,CodePtr OpPC,uint32_t FPOI)969*700637cbSDimitry Andric inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
970*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
971*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
972*700637cbSDimitry Andric     return false;
973*700637cbSDimitry Andric 
974*700637cbSDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);
975*700637cbSDimitry Andric }
976*700637cbSDimitry Andric 
IncfPop(InterpState & S,CodePtr OpPC,uint32_t FPOI)977*700637cbSDimitry Andric inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
978*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
979*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Increment))
980*700637cbSDimitry Andric     return false;
981*700637cbSDimitry Andric 
982*700637cbSDimitry Andric   return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);
983*700637cbSDimitry Andric }
984*700637cbSDimitry Andric 
Decf(InterpState & S,CodePtr OpPC,uint32_t FPOI)985*700637cbSDimitry Andric inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
986*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
987*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
988*700637cbSDimitry Andric     return false;
989*700637cbSDimitry Andric 
990*700637cbSDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);
991*700637cbSDimitry Andric }
992*700637cbSDimitry Andric 
DecfPop(InterpState & S,CodePtr OpPC,uint32_t FPOI)993*700637cbSDimitry Andric inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
994*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
995*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))
996*700637cbSDimitry Andric     return false;
997*700637cbSDimitry Andric 
998*700637cbSDimitry Andric   return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);
999*700637cbSDimitry Andric }
1000*700637cbSDimitry Andric 
1001*700637cbSDimitry Andric /// 1) Pops the value from the stack.
1002*700637cbSDimitry Andric /// 2) Pushes the bitwise complemented value on the stack (~V).
1003*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Comp(InterpState & S,CodePtr OpPC)1004*700637cbSDimitry Andric bool Comp(InterpState &S, CodePtr OpPC) {
1005*700637cbSDimitry Andric   const T &Val = S.Stk.pop<T>();
1006*700637cbSDimitry Andric 
1007*700637cbSDimitry Andric   T Result;
1008*700637cbSDimitry Andric   if constexpr (needsAlloc<T>())
1009*700637cbSDimitry Andric     Result = S.allocAP<T>(Val.bitWidth());
1010*700637cbSDimitry Andric 
1011*700637cbSDimitry Andric   if (!T::comp(Val, &Result)) {
1012*700637cbSDimitry Andric     S.Stk.push<T>(Result);
1013*700637cbSDimitry Andric     return true;
1014*700637cbSDimitry Andric   }
1015*700637cbSDimitry Andric   return false;
1016*700637cbSDimitry Andric }
1017*700637cbSDimitry Andric 
1018*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1019*700637cbSDimitry Andric // EQ, NE, GT, GE, LT, LE
1020*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1021*700637cbSDimitry Andric 
1022*700637cbSDimitry Andric using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
1023*700637cbSDimitry Andric 
1024*700637cbSDimitry Andric template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)1025*700637cbSDimitry Andric bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1026*700637cbSDimitry Andric   assert((!std::is_same_v<T, MemberPointer>) &&
1027*700637cbSDimitry Andric          "Non-equality comparisons on member pointer types should already be "
1028*700637cbSDimitry Andric          "rejected in Sema.");
1029*700637cbSDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
1030*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
1031*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
1032*700637cbSDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
1033*700637cbSDimitry Andric   return true;
1034*700637cbSDimitry Andric }
1035*700637cbSDimitry Andric 
1036*700637cbSDimitry Andric template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)1037*700637cbSDimitry Andric bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1038*700637cbSDimitry Andric   return CmpHelper<T>(S, OpPC, Fn);
1039*700637cbSDimitry Andric }
1040*700637cbSDimitry Andric 
1041*700637cbSDimitry Andric template <>
1042*700637cbSDimitry Andric inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1043*700637cbSDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
1044*700637cbSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
1045*700637cbSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
1046*700637cbSDimitry Andric 
1047*700637cbSDimitry Andric   // Function pointers cannot be compared in an ordered way.
1048*700637cbSDimitry Andric   if (LHS.isFunctionPointer() || RHS.isFunctionPointer() ||
1049*700637cbSDimitry Andric       LHS.isTypeidPointer() || RHS.isTypeidPointer()) {
1050*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
1051*700637cbSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1052*700637cbSDimitry Andric         << LHS.toDiagnosticString(S.getASTContext())
1053*700637cbSDimitry Andric         << RHS.toDiagnosticString(S.getASTContext());
1054*700637cbSDimitry Andric     return false;
1055*700637cbSDimitry Andric   }
1056*700637cbSDimitry Andric 
1057*700637cbSDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
1058*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
1059*700637cbSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1060*700637cbSDimitry Andric         << LHS.toDiagnosticString(S.getASTContext())
1061*700637cbSDimitry Andric         << RHS.toDiagnosticString(S.getASTContext());
1062*700637cbSDimitry Andric     return false;
1063*700637cbSDimitry Andric   }
1064*700637cbSDimitry Andric 
1065*700637cbSDimitry Andric   // Diagnose comparisons between fields with different access specifiers.
1066*700637cbSDimitry Andric   if (std::optional<std::pair<Pointer, Pointer>> Split =
1067*700637cbSDimitry Andric           Pointer::computeSplitPoint(LHS, RHS)) {
1068*700637cbSDimitry Andric     const FieldDecl *LF = Split->first.getField();
1069*700637cbSDimitry Andric     const FieldDecl *RF = Split->second.getField();
1070*700637cbSDimitry Andric     if (LF && RF && !LF->getParent()->isUnion() &&
1071*700637cbSDimitry Andric         LF->getAccess() != RF->getAccess()) {
1072*700637cbSDimitry Andric       S.CCEDiag(S.Current->getSource(OpPC),
1073*700637cbSDimitry Andric                 diag::note_constexpr_pointer_comparison_differing_access)
1074*700637cbSDimitry Andric           << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent();
1075*700637cbSDimitry Andric     }
1076*700637cbSDimitry Andric   }
1077*700637cbSDimitry Andric 
1078*700637cbSDimitry Andric   unsigned VL = LHS.getByteOffset();
1079*700637cbSDimitry Andric   unsigned VR = RHS.getByteOffset();
1080*700637cbSDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1081*700637cbSDimitry Andric   return true;
1082*700637cbSDimitry Andric }
1083*700637cbSDimitry Andric 
IsOpaqueConstantCall(const CallExpr * E)1084*700637cbSDimitry Andric static inline bool IsOpaqueConstantCall(const CallExpr *E) {
1085*700637cbSDimitry Andric   unsigned Builtin = E->getBuiltinCallee();
1086*700637cbSDimitry Andric   return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
1087*700637cbSDimitry Andric           Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
1088*700637cbSDimitry Andric           Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
1089*700637cbSDimitry Andric           Builtin == Builtin::BI__builtin_function_start);
1090*700637cbSDimitry Andric }
1091*700637cbSDimitry Andric 
1092*700637cbSDimitry Andric bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
1093*700637cbSDimitry Andric                                              const Pointer &RHS);
1094*700637cbSDimitry Andric 
1095*700637cbSDimitry Andric template <>
1096*700637cbSDimitry Andric inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
1097*700637cbSDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
1098*700637cbSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
1099*700637cbSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
1100*700637cbSDimitry Andric 
1101*700637cbSDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
1102*700637cbSDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
1103*700637cbSDimitry Andric     return true;
1104*700637cbSDimitry Andric   }
1105*700637cbSDimitry Andric 
1106*700637cbSDimitry Andric   // Reject comparisons to weak pointers.
1107*700637cbSDimitry Andric   for (const auto &P : {LHS, RHS}) {
1108*700637cbSDimitry Andric     if (P.isZero())
1109*700637cbSDimitry Andric       continue;
1110*700637cbSDimitry Andric     if (P.isWeak()) {
1111*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
1112*700637cbSDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
1113*700637cbSDimitry Andric           << P.toDiagnosticString(S.getASTContext());
1114*700637cbSDimitry Andric       return false;
1115*700637cbSDimitry Andric     }
1116*700637cbSDimitry Andric   }
1117*700637cbSDimitry Andric 
1118*700637cbSDimitry Andric   if (!S.inConstantContext()) {
1119*700637cbSDimitry Andric     if (isConstexprUnknown(LHS) || isConstexprUnknown(RHS))
1120*700637cbSDimitry Andric       return false;
1121*700637cbSDimitry Andric   }
1122*700637cbSDimitry Andric 
1123*700637cbSDimitry Andric   if (LHS.isFunctionPointer() && RHS.isFunctionPointer()) {
1124*700637cbSDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(LHS.getIntegerRepresentation(),
1125*700637cbSDimitry Andric                                              RHS.getIntegerRepresentation()))));
1126*700637cbSDimitry Andric     return true;
1127*700637cbSDimitry Andric   }
1128*700637cbSDimitry Andric 
1129*700637cbSDimitry Andric   // FIXME: The source check here isn't entirely correct.
1130*700637cbSDimitry Andric   if (LHS.pointsToStringLiteral() && RHS.pointsToStringLiteral() &&
1131*700637cbSDimitry Andric       LHS.getFieldDesc()->asExpr() != RHS.getFieldDesc()->asExpr()) {
1132*700637cbSDimitry Andric     if (arePotentiallyOverlappingStringLiterals(LHS, RHS)) {
1133*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
1134*700637cbSDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_literal_comparison)
1135*700637cbSDimitry Andric           << LHS.toDiagnosticString(S.getASTContext())
1136*700637cbSDimitry Andric           << RHS.toDiagnosticString(S.getASTContext());
1137*700637cbSDimitry Andric       return false;
1138*700637cbSDimitry Andric     }
1139*700637cbSDimitry Andric   }
1140*700637cbSDimitry Andric 
1141*700637cbSDimitry Andric   if (Pointer::hasSameBase(LHS, RHS)) {
1142*700637cbSDimitry Andric     size_t A = LHS.computeOffsetForComparison();
1143*700637cbSDimitry Andric     size_t B = RHS.computeOffsetForComparison();
1144*700637cbSDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(A, B))));
1145*700637cbSDimitry Andric     return true;
1146*700637cbSDimitry Andric   }
1147*700637cbSDimitry Andric 
1148*700637cbSDimitry Andric   // Otherwise we need to do a bunch of extra checks before returning Unordered.
1149*700637cbSDimitry Andric   if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&
1150*700637cbSDimitry Andric       RHS.getOffset() == 0) {
1151*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
1152*700637cbSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1153*700637cbSDimitry Andric         << LHS.toDiagnosticString(S.getASTContext());
1154*700637cbSDimitry Andric     return false;
1155*700637cbSDimitry Andric   } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&
1156*700637cbSDimitry Andric              LHS.getOffset() == 0) {
1157*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
1158*700637cbSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)
1159*700637cbSDimitry Andric         << RHS.toDiagnosticString(S.getASTContext());
1160*700637cbSDimitry Andric     return false;
1161*700637cbSDimitry Andric   }
1162*700637cbSDimitry Andric 
1163*700637cbSDimitry Andric   bool BothNonNull = !LHS.isZero() && !RHS.isZero();
1164*700637cbSDimitry Andric   // Reject comparisons to literals.
1165*700637cbSDimitry Andric   for (const auto &P : {LHS, RHS}) {
1166*700637cbSDimitry Andric     if (P.isZero())
1167*700637cbSDimitry Andric       continue;
1168*700637cbSDimitry Andric     if (BothNonNull && P.pointsToLiteral()) {
1169*700637cbSDimitry Andric       const Expr *E = P.getDeclDesc()->asExpr();
1170*700637cbSDimitry Andric       if (isa<StringLiteral>(E)) {
1171*700637cbSDimitry Andric         const SourceInfo &Loc = S.Current->getSource(OpPC);
1172*700637cbSDimitry Andric         S.FFDiag(Loc, diag::note_constexpr_literal_comparison);
1173*700637cbSDimitry Andric         return false;
1174*700637cbSDimitry Andric       } else if (const auto *CE = dyn_cast<CallExpr>(E);
1175*700637cbSDimitry Andric                  CE && IsOpaqueConstantCall(CE)) {
1176*700637cbSDimitry Andric         const SourceInfo &Loc = S.Current->getSource(OpPC);
1177*700637cbSDimitry Andric         S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)
1178*700637cbSDimitry Andric             << P.toDiagnosticString(S.getASTContext());
1179*700637cbSDimitry Andric         return false;
1180*700637cbSDimitry Andric       }
1181*700637cbSDimitry Andric     } else if (BothNonNull && P.isIntegralPointer()) {
1182*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
1183*700637cbSDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)
1184*700637cbSDimitry Andric           << LHS.toDiagnosticString(S.getASTContext())
1185*700637cbSDimitry Andric           << RHS.toDiagnosticString(S.getASTContext());
1186*700637cbSDimitry Andric       return false;
1187*700637cbSDimitry Andric     }
1188*700637cbSDimitry Andric   }
1189*700637cbSDimitry Andric 
1190*700637cbSDimitry Andric   if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {
1191*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
1192*700637cbSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)
1193*700637cbSDimitry Andric         << LHS.toDiagnosticString(S.getASTContext())
1194*700637cbSDimitry Andric         << RHS.toDiagnosticString(S.getASTContext());
1195*700637cbSDimitry Andric     return false;
1196*700637cbSDimitry Andric   }
1197*700637cbSDimitry Andric 
1198*700637cbSDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
1199*700637cbSDimitry Andric   return true;
1200*700637cbSDimitry Andric }
1201*700637cbSDimitry Andric 
1202*700637cbSDimitry Andric template <>
1203*700637cbSDimitry Andric inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,
1204*700637cbSDimitry Andric                                        CompareFn Fn) {
1205*700637cbSDimitry Andric   const auto &RHS = S.Stk.pop<MemberPointer>();
1206*700637cbSDimitry Andric   const auto &LHS = S.Stk.pop<MemberPointer>();
1207*700637cbSDimitry Andric 
1208*700637cbSDimitry Andric   // If either operand is a pointer to a weak function, the comparison is not
1209*700637cbSDimitry Andric   // constant.
1210*700637cbSDimitry Andric   for (const auto &MP : {LHS, RHS}) {
1211*700637cbSDimitry Andric     if (MP.isWeak()) {
1212*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
1213*700637cbSDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)
1214*700637cbSDimitry Andric           << MP.getMemberFunction();
1215*700637cbSDimitry Andric       return false;
1216*700637cbSDimitry Andric     }
1217*700637cbSDimitry Andric   }
1218*700637cbSDimitry Andric 
1219*700637cbSDimitry Andric   // C++11 [expr.eq]p2:
1220*700637cbSDimitry Andric   //   If both operands are null, they compare equal. Otherwise if only one is
1221*700637cbSDimitry Andric   //   null, they compare unequal.
1222*700637cbSDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
1223*700637cbSDimitry Andric     S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));
1224*700637cbSDimitry Andric     return true;
1225*700637cbSDimitry Andric   }
1226*700637cbSDimitry Andric   if (LHS.isZero() || RHS.isZero()) {
1227*700637cbSDimitry Andric     S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));
1228*700637cbSDimitry Andric     return true;
1229*700637cbSDimitry Andric   }
1230*700637cbSDimitry Andric 
1231*700637cbSDimitry Andric   // We cannot compare against virtual declarations at compile time.
1232*700637cbSDimitry Andric   for (const auto &MP : {LHS, RHS}) {
1233*700637cbSDimitry Andric     if (const CXXMethodDecl *MD = MP.getMemberFunction();
1234*700637cbSDimitry Andric         MD && MD->isVirtual()) {
1235*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
1236*700637cbSDimitry Andric       S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;
1237*700637cbSDimitry Andric     }
1238*700637cbSDimitry Andric   }
1239*700637cbSDimitry Andric 
1240*700637cbSDimitry Andric   S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));
1241*700637cbSDimitry Andric   return true;
1242*700637cbSDimitry Andric }
1243*700637cbSDimitry Andric 
1244*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)1245*700637cbSDimitry Andric bool EQ(InterpState &S, CodePtr OpPC) {
1246*700637cbSDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1247*700637cbSDimitry Andric     return R == ComparisonCategoryResult::Equal;
1248*700637cbSDimitry Andric   });
1249*700637cbSDimitry Andric }
1250*700637cbSDimitry Andric 
1251*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CMP3(InterpState & S,CodePtr OpPC,const ComparisonCategoryInfo * CmpInfo)1252*700637cbSDimitry Andric bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
1253*700637cbSDimitry Andric   const T &RHS = S.Stk.pop<T>();
1254*700637cbSDimitry Andric   const T &LHS = S.Stk.pop<T>();
1255*700637cbSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
1256*700637cbSDimitry Andric 
1257*700637cbSDimitry Andric   ComparisonCategoryResult CmpResult = LHS.compare(RHS);
1258*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Pointer>) {
1259*700637cbSDimitry Andric     if (CmpResult == ComparisonCategoryResult::Unordered) {
1260*700637cbSDimitry Andric       const SourceInfo &Loc = S.Current->getSource(OpPC);
1261*700637cbSDimitry Andric       S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1262*700637cbSDimitry Andric           << LHS.toDiagnosticString(S.getASTContext())
1263*700637cbSDimitry Andric           << RHS.toDiagnosticString(S.getASTContext());
1264*700637cbSDimitry Andric       return false;
1265*700637cbSDimitry Andric     }
1266*700637cbSDimitry Andric   }
1267*700637cbSDimitry Andric 
1268*700637cbSDimitry Andric   assert(CmpInfo);
1269*700637cbSDimitry Andric   const auto *CmpValueInfo =
1270*700637cbSDimitry Andric       CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
1271*700637cbSDimitry Andric   assert(CmpValueInfo);
1272*700637cbSDimitry Andric   assert(CmpValueInfo->hasValidIntValue());
1273*700637cbSDimitry Andric   return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());
1274*700637cbSDimitry Andric }
1275*700637cbSDimitry Andric 
1276*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)1277*700637cbSDimitry Andric bool NE(InterpState &S, CodePtr OpPC) {
1278*700637cbSDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
1279*700637cbSDimitry Andric     return R != ComparisonCategoryResult::Equal;
1280*700637cbSDimitry Andric   });
1281*700637cbSDimitry Andric }
1282*700637cbSDimitry Andric 
1283*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)1284*700637cbSDimitry Andric bool LT(InterpState &S, CodePtr OpPC) {
1285*700637cbSDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1286*700637cbSDimitry Andric     return R == ComparisonCategoryResult::Less;
1287*700637cbSDimitry Andric   });
1288*700637cbSDimitry Andric }
1289*700637cbSDimitry Andric 
1290*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)1291*700637cbSDimitry Andric bool LE(InterpState &S, CodePtr OpPC) {
1292*700637cbSDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1293*700637cbSDimitry Andric     return R == ComparisonCategoryResult::Less ||
1294*700637cbSDimitry Andric            R == ComparisonCategoryResult::Equal;
1295*700637cbSDimitry Andric   });
1296*700637cbSDimitry Andric }
1297*700637cbSDimitry Andric 
1298*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)1299*700637cbSDimitry Andric bool GT(InterpState &S, CodePtr OpPC) {
1300*700637cbSDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1301*700637cbSDimitry Andric     return R == ComparisonCategoryResult::Greater;
1302*700637cbSDimitry Andric   });
1303*700637cbSDimitry Andric }
1304*700637cbSDimitry Andric 
1305*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)1306*700637cbSDimitry Andric bool GE(InterpState &S, CodePtr OpPC) {
1307*700637cbSDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
1308*700637cbSDimitry Andric     return R == ComparisonCategoryResult::Greater ||
1309*700637cbSDimitry Andric            R == ComparisonCategoryResult::Equal;
1310*700637cbSDimitry Andric   });
1311*700637cbSDimitry Andric }
1312*700637cbSDimitry Andric 
1313*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1314*700637cbSDimitry Andric // Dup, Pop, Test
1315*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1316*700637cbSDimitry Andric 
1317*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)1318*700637cbSDimitry Andric bool Dup(InterpState &S, CodePtr OpPC) {
1319*700637cbSDimitry Andric   S.Stk.push<T>(S.Stk.peek<T>());
1320*700637cbSDimitry Andric   return true;
1321*700637cbSDimitry Andric }
1322*700637cbSDimitry Andric 
1323*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)1324*700637cbSDimitry Andric bool Pop(InterpState &S, CodePtr OpPC) {
1325*700637cbSDimitry Andric   S.Stk.pop<T>();
1326*700637cbSDimitry Andric   return true;
1327*700637cbSDimitry Andric }
1328*700637cbSDimitry Andric 
1329*700637cbSDimitry Andric /// [Value1, Value2] -> [Value2, Value1]
1330*700637cbSDimitry Andric template <PrimType TopName, PrimType BottomName>
Flip(InterpState & S,CodePtr OpPC)1331*700637cbSDimitry Andric bool Flip(InterpState &S, CodePtr OpPC) {
1332*700637cbSDimitry Andric   using TopT = typename PrimConv<TopName>::T;
1333*700637cbSDimitry Andric   using BottomT = typename PrimConv<BottomName>::T;
1334*700637cbSDimitry Andric 
1335*700637cbSDimitry Andric   const auto &Top = S.Stk.pop<TopT>();
1336*700637cbSDimitry Andric   const auto &Bottom = S.Stk.pop<BottomT>();
1337*700637cbSDimitry Andric 
1338*700637cbSDimitry Andric   S.Stk.push<TopT>(Top);
1339*700637cbSDimitry Andric   S.Stk.push<BottomT>(Bottom);
1340*700637cbSDimitry Andric 
1341*700637cbSDimitry Andric   return true;
1342*700637cbSDimitry Andric }
1343*700637cbSDimitry Andric 
1344*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1345*700637cbSDimitry Andric // Const
1346*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1347*700637cbSDimitry Andric 
1348*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)1349*700637cbSDimitry Andric bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
1350*700637cbSDimitry Andric   if constexpr (needsAlloc<T>()) {
1351*700637cbSDimitry Andric     T Result = S.allocAP<T>(Arg.bitWidth());
1352*700637cbSDimitry Andric     Result.copy(Arg.toAPSInt());
1353*700637cbSDimitry Andric     S.Stk.push<T>(Result);
1354*700637cbSDimitry Andric     return true;
1355*700637cbSDimitry Andric   }
1356*700637cbSDimitry Andric   S.Stk.push<T>(Arg);
1357*700637cbSDimitry Andric   return true;
1358*700637cbSDimitry Andric }
1359*700637cbSDimitry Andric 
ConstFloat(InterpState & S,CodePtr OpPC,const Floating & F)1360*700637cbSDimitry Andric inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
1361*700637cbSDimitry Andric   Floating Result = S.allocFloat(F.getSemantics());
1362*700637cbSDimitry Andric   Result.copy(F.getAPFloat());
1363*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
1364*700637cbSDimitry Andric   return true;
1365*700637cbSDimitry Andric }
1366*700637cbSDimitry Andric 
1367*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1368*700637cbSDimitry Andric // Get/Set Local/Param/Global/This
1369*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1370*700637cbSDimitry Andric 
1371*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)1372*700637cbSDimitry Andric bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1373*700637cbSDimitry Andric   const Pointer &Ptr = S.Current->getLocalPointer(I);
1374*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1375*700637cbSDimitry Andric     return false;
1376*700637cbSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1377*700637cbSDimitry Andric   return true;
1378*700637cbSDimitry Andric }
1379*700637cbSDimitry Andric 
1380*700637cbSDimitry Andric bool EndLifetime(InterpState &S, CodePtr OpPC);
1381*700637cbSDimitry Andric bool EndLifetimePop(InterpState &S, CodePtr OpPC);
1382*700637cbSDimitry Andric bool StartLifetime(InterpState &S, CodePtr OpPC);
1383*700637cbSDimitry Andric 
1384*700637cbSDimitry Andric /// 1) Pops the value from the stack.
1385*700637cbSDimitry Andric /// 2) Writes the value to the local variable with the
1386*700637cbSDimitry Andric ///    given offset.
1387*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)1388*700637cbSDimitry Andric bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1389*700637cbSDimitry Andric   S.Current->setLocal<T>(I, S.Stk.pop<T>());
1390*700637cbSDimitry Andric   return true;
1391*700637cbSDimitry Andric }
1392*700637cbSDimitry Andric 
1393*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)1394*700637cbSDimitry Andric bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1395*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1396*700637cbSDimitry Andric     return false;
1397*700637cbSDimitry Andric   }
1398*700637cbSDimitry Andric   S.Stk.push<T>(S.Current->getParam<T>(I));
1399*700637cbSDimitry Andric   return true;
1400*700637cbSDimitry Andric }
1401*700637cbSDimitry Andric 
1402*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)1403*700637cbSDimitry Andric bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1404*700637cbSDimitry Andric   S.Current->setParam<T>(I, S.Stk.pop<T>());
1405*700637cbSDimitry Andric   return true;
1406*700637cbSDimitry Andric }
1407*700637cbSDimitry Andric 
1408*700637cbSDimitry Andric /// 1) Peeks a pointer on the stack
1409*700637cbSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
1410*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)1411*700637cbSDimitry Andric bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1412*700637cbSDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
1413*700637cbSDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1414*700637cbSDimitry Andric     return false;
1415*700637cbSDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1416*700637cbSDimitry Andric     return false;
1417*700637cbSDimitry Andric   const Pointer &Field = Obj.atField(I);
1418*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Field))
1419*700637cbSDimitry Andric     return false;
1420*700637cbSDimitry Andric   S.Stk.push<T>(Field.deref<T>());
1421*700637cbSDimitry Andric   return true;
1422*700637cbSDimitry Andric }
1423*700637cbSDimitry Andric 
1424*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)1425*700637cbSDimitry Andric bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
1426*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1427*700637cbSDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
1428*700637cbSDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1429*700637cbSDimitry Andric     return false;
1430*700637cbSDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1431*700637cbSDimitry Andric     return false;
1432*700637cbSDimitry Andric   const Pointer &Field = Obj.atField(I);
1433*700637cbSDimitry Andric   if (!CheckStore(S, OpPC, Field))
1434*700637cbSDimitry Andric     return false;
1435*700637cbSDimitry Andric   Field.initialize();
1436*700637cbSDimitry Andric   Field.deref<T>() = Value;
1437*700637cbSDimitry Andric   return true;
1438*700637cbSDimitry Andric }
1439*700637cbSDimitry Andric 
1440*700637cbSDimitry Andric /// 1) Pops a pointer from the stack
1441*700637cbSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack
1442*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)1443*700637cbSDimitry Andric bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
1444*700637cbSDimitry Andric   const Pointer &Obj = S.Stk.pop<Pointer>();
1445*700637cbSDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
1446*700637cbSDimitry Andric     return false;
1447*700637cbSDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
1448*700637cbSDimitry Andric     return false;
1449*700637cbSDimitry Andric   const Pointer &Field = Obj.atField(I);
1450*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Field))
1451*700637cbSDimitry Andric     return false;
1452*700637cbSDimitry Andric   S.Stk.push<T>(Field.deref<T>());
1453*700637cbSDimitry Andric   return true;
1454*700637cbSDimitry Andric }
1455*700637cbSDimitry Andric 
1456*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)1457*700637cbSDimitry Andric bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1458*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression())
1459*700637cbSDimitry Andric     return false;
1460*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1461*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1462*700637cbSDimitry Andric     return false;
1463*700637cbSDimitry Andric   const Pointer &Field = This.atField(I);
1464*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Field))
1465*700637cbSDimitry Andric     return false;
1466*700637cbSDimitry Andric   S.Stk.push<T>(Field.deref<T>());
1467*700637cbSDimitry Andric   return true;
1468*700637cbSDimitry Andric }
1469*700637cbSDimitry Andric 
1470*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)1471*700637cbSDimitry Andric bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1472*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression())
1473*700637cbSDimitry Andric     return false;
1474*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1475*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1476*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1477*700637cbSDimitry Andric     return false;
1478*700637cbSDimitry Andric   const Pointer &Field = This.atField(I);
1479*700637cbSDimitry Andric   if (!CheckStore(S, OpPC, Field))
1480*700637cbSDimitry Andric     return false;
1481*700637cbSDimitry Andric   Field.deref<T>() = Value;
1482*700637cbSDimitry Andric   return true;
1483*700637cbSDimitry Andric }
1484*700637cbSDimitry Andric 
1485*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1486*700637cbSDimitry Andric bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1487*700637cbSDimitry Andric   const Pointer &Ptr = S.P.getPtrGlobal(I);
1488*700637cbSDimitry Andric   if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))
1489*700637cbSDimitry Andric     return false;
1490*700637cbSDimitry Andric   if (Ptr.isExtern())
1491*700637cbSDimitry Andric     return false;
1492*700637cbSDimitry Andric 
1493*700637cbSDimitry Andric   // If a global variable is uninitialized, that means the initializer we've
1494*700637cbSDimitry Andric   // compiled for it wasn't a constant expression. Diagnose that.
1495*700637cbSDimitry Andric   if (!CheckGlobalInitialized(S, OpPC, Ptr))
1496*700637cbSDimitry Andric     return false;
1497*700637cbSDimitry Andric 
1498*700637cbSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1499*700637cbSDimitry Andric   return true;
1500*700637cbSDimitry Andric }
1501*700637cbSDimitry Andric 
1502*700637cbSDimitry Andric /// Same as GetGlobal, but without the checks.
1503*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobalUnchecked(InterpState & S,CodePtr OpPC,uint32_t I)1504*700637cbSDimitry Andric bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
1505*700637cbSDimitry Andric   const Pointer &Ptr = S.P.getPtrGlobal(I);
1506*700637cbSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
1507*700637cbSDimitry Andric     return false;
1508*700637cbSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1509*700637cbSDimitry Andric   return true;
1510*700637cbSDimitry Andric }
1511*700637cbSDimitry Andric 
1512*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1513*700637cbSDimitry Andric bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1514*700637cbSDimitry Andric   // TODO: emit warning.
1515*700637cbSDimitry Andric   return false;
1516*700637cbSDimitry Andric }
1517*700637cbSDimitry Andric 
1518*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1519*700637cbSDimitry Andric bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1520*700637cbSDimitry Andric   const Pointer &P = S.P.getGlobal(I);
1521*700637cbSDimitry Andric 
1522*700637cbSDimitry Andric   P.deref<T>() = S.Stk.pop<T>();
1523*700637cbSDimitry Andric 
1524*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Floating>) {
1525*700637cbSDimitry Andric     auto &Val = P.deref<Floating>();
1526*700637cbSDimitry Andric     if (!Val.singleWord()) {
1527*700637cbSDimitry Andric       uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1528*700637cbSDimitry Andric       Val.take(NewMemory);
1529*700637cbSDimitry Andric     }
1530*700637cbSDimitry Andric 
1531*700637cbSDimitry Andric   } else if constexpr (needsAlloc<T>()) {
1532*700637cbSDimitry Andric     auto &Val = P.deref<T>();
1533*700637cbSDimitry Andric     if (!Val.singleWord()) {
1534*700637cbSDimitry Andric       uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
1535*700637cbSDimitry Andric       Val.take(NewMemory);
1536*700637cbSDimitry Andric     }
1537*700637cbSDimitry Andric   }
1538*700637cbSDimitry Andric 
1539*700637cbSDimitry Andric   P.initialize();
1540*700637cbSDimitry Andric   return true;
1541*700637cbSDimitry Andric }
1542*700637cbSDimitry Andric 
1543*700637cbSDimitry Andric /// 1) Converts the value on top of the stack to an APValue
1544*700637cbSDimitry Andric /// 2) Sets that APValue on \Temp
1545*700637cbSDimitry Andric /// 3) Initializes global with index \I with that
1546*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobalTemp(InterpState & S,CodePtr OpPC,uint32_t I,const LifetimeExtendedTemporaryDecl * Temp)1547*700637cbSDimitry Andric bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
1548*700637cbSDimitry Andric                     const LifetimeExtendedTemporaryDecl *Temp) {
1549*700637cbSDimitry Andric   const Pointer &Ptr = S.P.getGlobal(I);
1550*700637cbSDimitry Andric 
1551*700637cbSDimitry Andric   const T Value = S.Stk.peek<T>();
1552*700637cbSDimitry Andric   APValue APV = Value.toAPValue(S.getASTContext());
1553*700637cbSDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
1554*700637cbSDimitry Andric   *Cached = APV;
1555*700637cbSDimitry Andric 
1556*700637cbSDimitry Andric   assert(Ptr.getDeclDesc()->asExpr());
1557*700637cbSDimitry Andric 
1558*700637cbSDimitry Andric   S.SeenGlobalTemporaries.push_back(
1559*700637cbSDimitry Andric       std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));
1560*700637cbSDimitry Andric 
1561*700637cbSDimitry Andric   Ptr.deref<T>() = S.Stk.pop<T>();
1562*700637cbSDimitry Andric   Ptr.initialize();
1563*700637cbSDimitry Andric   return true;
1564*700637cbSDimitry Andric }
1565*700637cbSDimitry Andric 
1566*700637cbSDimitry Andric /// 1) Converts the value on top of the stack to an APValue
1567*700637cbSDimitry Andric /// 2) Sets that APValue on \Temp
1568*700637cbSDimitry Andric /// 3) Initialized global with index \I with that
InitGlobalTempComp(InterpState & S,CodePtr OpPC,const LifetimeExtendedTemporaryDecl * Temp)1569*700637cbSDimitry Andric inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,
1570*700637cbSDimitry Andric                                const LifetimeExtendedTemporaryDecl *Temp) {
1571*700637cbSDimitry Andric   assert(Temp);
1572*700637cbSDimitry Andric   const Pointer &P = S.Stk.peek<Pointer>();
1573*700637cbSDimitry Andric   APValue *Cached = Temp->getOrCreateValue(true);
1574*700637cbSDimitry Andric 
1575*700637cbSDimitry Andric   S.SeenGlobalTemporaries.push_back(
1576*700637cbSDimitry Andric       std::make_pair(P.getDeclDesc()->asExpr(), Temp));
1577*700637cbSDimitry Andric 
1578*700637cbSDimitry Andric   if (std::optional<APValue> APV =
1579*700637cbSDimitry Andric           P.toRValue(S.getASTContext(), Temp->getTemporaryExpr()->getType())) {
1580*700637cbSDimitry Andric     *Cached = *APV;
1581*700637cbSDimitry Andric     return true;
1582*700637cbSDimitry Andric   }
1583*700637cbSDimitry Andric 
1584*700637cbSDimitry Andric   return false;
1585*700637cbSDimitry Andric }
1586*700637cbSDimitry Andric 
1587*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)1588*700637cbSDimitry Andric bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
1589*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1590*700637cbSDimitry Andric     return false;
1591*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1592*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1593*700637cbSDimitry Andric     return false;
1594*700637cbSDimitry Andric   const Pointer &Field = This.atField(I);
1595*700637cbSDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
1596*700637cbSDimitry Andric   Field.activate();
1597*700637cbSDimitry Andric   Field.initialize();
1598*700637cbSDimitry Andric   return true;
1599*700637cbSDimitry Andric }
1600*700637cbSDimitry Andric 
1601*700637cbSDimitry Andric // FIXME: The Field pointer here is too much IMO and we could instead just
1602*700637cbSDimitry Andric // pass an Offset + BitWidth pair.
1603*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F,uint32_t FieldOffset)1604*700637cbSDimitry Andric bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,
1605*700637cbSDimitry Andric                       uint32_t FieldOffset) {
1606*700637cbSDimitry Andric   assert(F->isBitField());
1607*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1608*700637cbSDimitry Andric     return false;
1609*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1610*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1611*700637cbSDimitry Andric     return false;
1612*700637cbSDimitry Andric   const Pointer &Field = This.atField(FieldOffset);
1613*700637cbSDimitry Andric   const auto &Value = S.Stk.pop<T>();
1614*700637cbSDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1615*700637cbSDimitry Andric   Field.initialize();
1616*700637cbSDimitry Andric   return true;
1617*700637cbSDimitry Andric }
1618*700637cbSDimitry Andric 
1619*700637cbSDimitry Andric /// 1) Pops the value from the stack
1620*700637cbSDimitry Andric /// 2) Peeks a pointer from the stack
1621*700637cbSDimitry Andric /// 3) Pushes the value to field I of the pointer on the stack
1622*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)1623*700637cbSDimitry Andric bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
1624*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1625*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1626*700637cbSDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1627*700637cbSDimitry Andric     return false;
1628*700637cbSDimitry Andric   const Pointer &Field = Ptr.atField(I);
1629*700637cbSDimitry Andric   Field.deref<T>() = Value;
1630*700637cbSDimitry Andric   Field.activate();
1631*700637cbSDimitry Andric   Field.initialize();
1632*700637cbSDimitry Andric   return true;
1633*700637cbSDimitry Andric }
1634*700637cbSDimitry Andric 
1635*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)1636*700637cbSDimitry Andric bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
1637*700637cbSDimitry Andric   assert(F->isBitField());
1638*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1639*700637cbSDimitry Andric   const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
1640*700637cbSDimitry Andric 
1641*700637cbSDimitry Andric   if constexpr (needsAlloc<T>()) {
1642*700637cbSDimitry Andric     T Result = S.allocAP<T>(Value.bitWidth());
1643*700637cbSDimitry Andric     if (T::isSigned())
1644*700637cbSDimitry Andric       Result.copy(Value.toAPSInt()
1645*700637cbSDimitry Andric                       .trunc(F->Decl->getBitWidthValue())
1646*700637cbSDimitry Andric                       .sextOrTrunc(Value.bitWidth()));
1647*700637cbSDimitry Andric     else
1648*700637cbSDimitry Andric       Result.copy(Value.toAPSInt()
1649*700637cbSDimitry Andric                       .trunc(F->Decl->getBitWidthValue())
1650*700637cbSDimitry Andric                       .zextOrTrunc(Value.bitWidth()));
1651*700637cbSDimitry Andric 
1652*700637cbSDimitry Andric     Field.deref<T>() = Result;
1653*700637cbSDimitry Andric   } else {
1654*700637cbSDimitry Andric     Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());
1655*700637cbSDimitry Andric   }
1656*700637cbSDimitry Andric   Field.activate();
1657*700637cbSDimitry Andric   Field.initialize();
1658*700637cbSDimitry Andric   return true;
1659*700637cbSDimitry Andric }
1660*700637cbSDimitry Andric 
1661*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1662*700637cbSDimitry Andric // GetPtr Local/Param/Global/Field/This
1663*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1664*700637cbSDimitry Andric 
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)1665*700637cbSDimitry Andric inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
1666*700637cbSDimitry Andric   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
1667*700637cbSDimitry Andric   return true;
1668*700637cbSDimitry Andric }
1669*700637cbSDimitry Andric 
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)1670*700637cbSDimitry Andric inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
1671*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression()) {
1672*700637cbSDimitry Andric     return false;
1673*700637cbSDimitry Andric   }
1674*700637cbSDimitry Andric   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
1675*700637cbSDimitry Andric   return true;
1676*700637cbSDimitry Andric }
1677*700637cbSDimitry Andric 
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)1678*700637cbSDimitry Andric inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
1679*700637cbSDimitry Andric   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
1680*700637cbSDimitry Andric   return true;
1681*700637cbSDimitry Andric }
1682*700637cbSDimitry Andric 
1683*700637cbSDimitry Andric /// 1) Peeks a Pointer
1684*700637cbSDimitry Andric /// 2) Pushes Pointer.atField(Off) on the stack
1685*700637cbSDimitry Andric bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);
1686*700637cbSDimitry Andric bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);
1687*700637cbSDimitry Andric 
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)1688*700637cbSDimitry Andric inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1689*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)
1690*700637cbSDimitry Andric     return false;
1691*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1692*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1693*700637cbSDimitry Andric     return false;
1694*700637cbSDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1695*700637cbSDimitry Andric   return true;
1696*700637cbSDimitry Andric }
1697*700637cbSDimitry Andric 
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)1698*700637cbSDimitry Andric inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1699*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1700*700637cbSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
1701*700637cbSDimitry Andric     return false;
1702*700637cbSDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1703*700637cbSDimitry Andric     return false;
1704*700637cbSDimitry Andric   Pointer Field = Ptr.atField(Off);
1705*700637cbSDimitry Andric   Ptr.deactivate();
1706*700637cbSDimitry Andric   Field.activate();
1707*700637cbSDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1708*700637cbSDimitry Andric   return true;
1709*700637cbSDimitry Andric }
1710*700637cbSDimitry Andric 
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)1711*700637cbSDimitry Andric inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1712*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression())
1713*700637cbSDimitry Andric     return false;
1714*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1715*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1716*700637cbSDimitry Andric     return false;
1717*700637cbSDimitry Andric   Pointer Field = This.atField(Off);
1718*700637cbSDimitry Andric   This.deactivate();
1719*700637cbSDimitry Andric   Field.activate();
1720*700637cbSDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
1721*700637cbSDimitry Andric   return true;
1722*700637cbSDimitry Andric }
1723*700637cbSDimitry Andric 
GetPtrDerivedPop(InterpState & S,CodePtr OpPC,uint32_t Off,bool NullOK,const Type * TargetType)1724*700637cbSDimitry Andric inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
1725*700637cbSDimitry Andric                              bool NullOK, const Type *TargetType) {
1726*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1727*700637cbSDimitry Andric   if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))
1728*700637cbSDimitry Andric     return false;
1729*700637cbSDimitry Andric 
1730*700637cbSDimitry Andric   if (!Ptr.isBlockPointer()) {
1731*700637cbSDimitry Andric     // FIXME: We don't have the necessary information in integral pointers.
1732*700637cbSDimitry Andric     // The Descriptor only has a record, but that does of course not include
1733*700637cbSDimitry Andric     // the potential derived classes of said record.
1734*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr);
1735*700637cbSDimitry Andric     return true;
1736*700637cbSDimitry Andric   }
1737*700637cbSDimitry Andric 
1738*700637cbSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))
1739*700637cbSDimitry Andric     return false;
1740*700637cbSDimitry Andric   if (!CheckDowncast(S, OpPC, Ptr, Off))
1741*700637cbSDimitry Andric     return false;
1742*700637cbSDimitry Andric 
1743*700637cbSDimitry Andric   const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
1744*700637cbSDimitry Andric   assert(TargetRecord);
1745*700637cbSDimitry Andric 
1746*700637cbSDimitry Andric   if (TargetRecord->getDecl()
1747*700637cbSDimitry Andric           ->getTypeForDecl()
1748*700637cbSDimitry Andric           ->getAsCXXRecordDecl()
1749*700637cbSDimitry Andric           ->getCanonicalDecl() !=
1750*700637cbSDimitry Andric       TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
1751*700637cbSDimitry Andric     QualType MostDerivedType = Ptr.getDeclDesc()->getType();
1752*700637cbSDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
1753*700637cbSDimitry Andric         << MostDerivedType << QualType(TargetType, 0);
1754*700637cbSDimitry Andric     return false;
1755*700637cbSDimitry Andric   }
1756*700637cbSDimitry Andric 
1757*700637cbSDimitry Andric   S.Stk.push<Pointer>(Ptr.atFieldSub(Off));
1758*700637cbSDimitry Andric   return true;
1759*700637cbSDimitry Andric }
1760*700637cbSDimitry Andric 
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)1761*700637cbSDimitry Andric inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1762*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1763*700637cbSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1764*700637cbSDimitry Andric     return false;
1765*700637cbSDimitry Andric 
1766*700637cbSDimitry Andric   if (!Ptr.isBlockPointer()) {
1767*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1768*700637cbSDimitry Andric     return true;
1769*700637cbSDimitry Andric   }
1770*700637cbSDimitry Andric 
1771*700637cbSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1772*700637cbSDimitry Andric     return false;
1773*700637cbSDimitry Andric   const Pointer &Result = Ptr.atField(Off);
1774*700637cbSDimitry Andric   if (Result.isPastEnd() || !Result.isBaseClass())
1775*700637cbSDimitry Andric     return false;
1776*700637cbSDimitry Andric   S.Stk.push<Pointer>(Result);
1777*700637cbSDimitry Andric   return true;
1778*700637cbSDimitry Andric }
1779*700637cbSDimitry Andric 
GetPtrBasePop(InterpState & S,CodePtr OpPC,uint32_t Off,bool NullOK)1780*700637cbSDimitry Andric inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,
1781*700637cbSDimitry Andric                           bool NullOK) {
1782*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1783*700637cbSDimitry Andric 
1784*700637cbSDimitry Andric   if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))
1785*700637cbSDimitry Andric     return false;
1786*700637cbSDimitry Andric 
1787*700637cbSDimitry Andric   if (!Ptr.isBlockPointer()) {
1788*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
1789*700637cbSDimitry Andric     return true;
1790*700637cbSDimitry Andric   }
1791*700637cbSDimitry Andric 
1792*700637cbSDimitry Andric   if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))
1793*700637cbSDimitry Andric     return false;
1794*700637cbSDimitry Andric   const Pointer &Result = Ptr.atField(Off);
1795*700637cbSDimitry Andric   if (Result.isPastEnd() || !Result.isBaseClass())
1796*700637cbSDimitry Andric     return false;
1797*700637cbSDimitry Andric   S.Stk.push<Pointer>(Result);
1798*700637cbSDimitry Andric   return true;
1799*700637cbSDimitry Andric }
1800*700637cbSDimitry Andric 
GetMemberPtrBasePop(InterpState & S,CodePtr OpPC,int32_t Off)1801*700637cbSDimitry Andric inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {
1802*700637cbSDimitry Andric   const auto &Ptr = S.Stk.pop<MemberPointer>();
1803*700637cbSDimitry Andric   S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));
1804*700637cbSDimitry Andric   return true;
1805*700637cbSDimitry Andric }
1806*700637cbSDimitry Andric 
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)1807*700637cbSDimitry Andric inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
1808*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression())
1809*700637cbSDimitry Andric     return false;
1810*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1811*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1812*700637cbSDimitry Andric     return false;
1813*700637cbSDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
1814*700637cbSDimitry Andric   return true;
1815*700637cbSDimitry Andric }
1816*700637cbSDimitry Andric 
FinishInitPop(InterpState & S,CodePtr OpPC)1817*700637cbSDimitry Andric inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
1818*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1819*700637cbSDimitry Andric   if (Ptr.canBeInitialized()) {
1820*700637cbSDimitry Andric     Ptr.initialize();
1821*700637cbSDimitry Andric     Ptr.activate();
1822*700637cbSDimitry Andric   }
1823*700637cbSDimitry Andric   return true;
1824*700637cbSDimitry Andric }
1825*700637cbSDimitry Andric 
FinishInit(InterpState & S,CodePtr OpPC)1826*700637cbSDimitry Andric inline bool FinishInit(InterpState &S, CodePtr OpPC) {
1827*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1828*700637cbSDimitry Andric   if (Ptr.canBeInitialized()) {
1829*700637cbSDimitry Andric     Ptr.initialize();
1830*700637cbSDimitry Andric     Ptr.activate();
1831*700637cbSDimitry Andric   }
1832*700637cbSDimitry Andric   return true;
1833*700637cbSDimitry Andric }
1834*700637cbSDimitry Andric 
1835*700637cbSDimitry Andric bool FinishInitGlobal(InterpState &S, CodePtr OpPC);
1836*700637cbSDimitry Andric 
Dump(InterpState & S,CodePtr OpPC)1837*700637cbSDimitry Andric inline bool Dump(InterpState &S, CodePtr OpPC) {
1838*700637cbSDimitry Andric   S.Stk.dump();
1839*700637cbSDimitry Andric   return true;
1840*700637cbSDimitry Andric }
1841*700637cbSDimitry Andric 
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)1842*700637cbSDimitry Andric inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
1843*700637cbSDimitry Andric                            const Pointer &Ptr) {
1844*700637cbSDimitry Andric   Pointer Base = Ptr;
1845*700637cbSDimitry Andric   while (Base.isBaseClass())
1846*700637cbSDimitry Andric     Base = Base.getBase();
1847*700637cbSDimitry Andric 
1848*700637cbSDimitry Andric   const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);
1849*700637cbSDimitry Andric   S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));
1850*700637cbSDimitry Andric   return true;
1851*700637cbSDimitry Andric }
1852*700637cbSDimitry Andric 
GetPtrVirtBasePop(InterpState & S,CodePtr OpPC,const RecordDecl * D)1853*700637cbSDimitry Andric inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,
1854*700637cbSDimitry Andric                               const RecordDecl *D) {
1855*700637cbSDimitry Andric   assert(D);
1856*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1857*700637cbSDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
1858*700637cbSDimitry Andric     return false;
1859*700637cbSDimitry Andric   return VirtBaseHelper(S, OpPC, D, Ptr);
1860*700637cbSDimitry Andric }
1861*700637cbSDimitry Andric 
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)1862*700637cbSDimitry Andric inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
1863*700637cbSDimitry Andric                                const RecordDecl *D) {
1864*700637cbSDimitry Andric   assert(D);
1865*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression())
1866*700637cbSDimitry Andric     return false;
1867*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
1868*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
1869*700637cbSDimitry Andric     return false;
1870*700637cbSDimitry Andric   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
1871*700637cbSDimitry Andric }
1872*700637cbSDimitry Andric 
1873*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1874*700637cbSDimitry Andric // Load, Store, Init
1875*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
1876*700637cbSDimitry Andric 
1877*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)1878*700637cbSDimitry Andric bool Load(InterpState &S, CodePtr OpPC) {
1879*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1880*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1881*700637cbSDimitry Andric     return false;
1882*700637cbSDimitry Andric   if (!Ptr.isBlockPointer())
1883*700637cbSDimitry Andric     return false;
1884*700637cbSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1885*700637cbSDimitry Andric   return true;
1886*700637cbSDimitry Andric }
1887*700637cbSDimitry Andric 
1888*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)1889*700637cbSDimitry Andric bool LoadPop(InterpState &S, CodePtr OpPC) {
1890*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1891*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
1892*700637cbSDimitry Andric     return false;
1893*700637cbSDimitry Andric   if (!Ptr.isBlockPointer())
1894*700637cbSDimitry Andric     return false;
1895*700637cbSDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
1896*700637cbSDimitry Andric   return true;
1897*700637cbSDimitry Andric }
1898*700637cbSDimitry Andric 
1899*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)1900*700637cbSDimitry Andric bool Store(InterpState &S, CodePtr OpPC) {
1901*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1902*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1903*700637cbSDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1904*700637cbSDimitry Andric     return false;
1905*700637cbSDimitry Andric   if (Ptr.canBeInitialized()) {
1906*700637cbSDimitry Andric     Ptr.initialize();
1907*700637cbSDimitry Andric     Ptr.activate();
1908*700637cbSDimitry Andric   }
1909*700637cbSDimitry Andric   Ptr.deref<T>() = Value;
1910*700637cbSDimitry Andric   return true;
1911*700637cbSDimitry Andric }
1912*700637cbSDimitry Andric 
1913*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)1914*700637cbSDimitry Andric bool StorePop(InterpState &S, CodePtr OpPC) {
1915*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1916*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1917*700637cbSDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1918*700637cbSDimitry Andric     return false;
1919*700637cbSDimitry Andric   if (Ptr.canBeInitialized()) {
1920*700637cbSDimitry Andric     Ptr.initialize();
1921*700637cbSDimitry Andric     Ptr.activate();
1922*700637cbSDimitry Andric   }
1923*700637cbSDimitry Andric   Ptr.deref<T>() = Value;
1924*700637cbSDimitry Andric   return true;
1925*700637cbSDimitry Andric }
1926*700637cbSDimitry Andric 
1927*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)1928*700637cbSDimitry Andric bool StoreBitField(InterpState &S, CodePtr OpPC) {
1929*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1930*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1931*700637cbSDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1932*700637cbSDimitry Andric     return false;
1933*700637cbSDimitry Andric   if (Ptr.canBeInitialized()) {
1934*700637cbSDimitry Andric     Ptr.initialize();
1935*700637cbSDimitry Andric     Ptr.activate();
1936*700637cbSDimitry Andric   }
1937*700637cbSDimitry Andric   if (const auto *FD = Ptr.getField())
1938*700637cbSDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
1939*700637cbSDimitry Andric   else
1940*700637cbSDimitry Andric     Ptr.deref<T>() = Value;
1941*700637cbSDimitry Andric   return true;
1942*700637cbSDimitry Andric }
1943*700637cbSDimitry Andric 
1944*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)1945*700637cbSDimitry Andric bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
1946*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1947*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1948*700637cbSDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
1949*700637cbSDimitry Andric     return false;
1950*700637cbSDimitry Andric   if (Ptr.canBeInitialized()) {
1951*700637cbSDimitry Andric     Ptr.initialize();
1952*700637cbSDimitry Andric     Ptr.activate();
1953*700637cbSDimitry Andric   }
1954*700637cbSDimitry Andric   if (const auto *FD = Ptr.getField())
1955*700637cbSDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());
1956*700637cbSDimitry Andric   else
1957*700637cbSDimitry Andric     Ptr.deref<T>() = Value;
1958*700637cbSDimitry Andric   return true;
1959*700637cbSDimitry Andric }
1960*700637cbSDimitry Andric 
1961*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Init(InterpState & S,CodePtr OpPC)1962*700637cbSDimitry Andric bool Init(InterpState &S, CodePtr OpPC) {
1963*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1964*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1965*700637cbSDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1966*700637cbSDimitry Andric     return false;
1967*700637cbSDimitry Andric   Ptr.activate();
1968*700637cbSDimitry Andric   Ptr.initialize();
1969*700637cbSDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1970*700637cbSDimitry Andric   return true;
1971*700637cbSDimitry Andric }
1972*700637cbSDimitry Andric 
1973*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)1974*700637cbSDimitry Andric bool InitPop(InterpState &S, CodePtr OpPC) {
1975*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1976*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
1977*700637cbSDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
1978*700637cbSDimitry Andric     return false;
1979*700637cbSDimitry Andric   Ptr.activate();
1980*700637cbSDimitry Andric   Ptr.initialize();
1981*700637cbSDimitry Andric   new (&Ptr.deref<T>()) T(Value);
1982*700637cbSDimitry Andric   return true;
1983*700637cbSDimitry Andric }
1984*700637cbSDimitry Andric 
1985*700637cbSDimitry Andric /// 1) Pops the value from the stack
1986*700637cbSDimitry Andric /// 2) Peeks a pointer and gets its index \Idx
1987*700637cbSDimitry Andric /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1988*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)1989*700637cbSDimitry Andric bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1990*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
1991*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
1992*700637cbSDimitry Andric 
1993*700637cbSDimitry Andric   if (Ptr.isUnknownSizeArray())
1994*700637cbSDimitry Andric     return false;
1995*700637cbSDimitry Andric 
1996*700637cbSDimitry Andric   // In the unlikely event that we're initializing the first item of
1997*700637cbSDimitry Andric   // a non-array, skip the atIndex().
1998*700637cbSDimitry Andric   if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
1999*700637cbSDimitry Andric     Ptr.initialize();
2000*700637cbSDimitry Andric     new (&Ptr.deref<T>()) T(Value);
2001*700637cbSDimitry Andric     return true;
2002*700637cbSDimitry Andric   }
2003*700637cbSDimitry Andric 
2004*700637cbSDimitry Andric   const Pointer &ElemPtr = Ptr.atIndex(Idx);
2005*700637cbSDimitry Andric   if (!CheckInit(S, OpPC, ElemPtr))
2006*700637cbSDimitry Andric     return false;
2007*700637cbSDimitry Andric   ElemPtr.initialize();
2008*700637cbSDimitry Andric   new (&ElemPtr.deref<T>()) T(Value);
2009*700637cbSDimitry Andric   return true;
2010*700637cbSDimitry Andric }
2011*700637cbSDimitry Andric 
2012*700637cbSDimitry Andric /// The same as InitElem, but pops the pointer as well.
2013*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)2014*700637cbSDimitry Andric bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
2015*700637cbSDimitry Andric   const T &Value = S.Stk.pop<T>();
2016*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2017*700637cbSDimitry Andric   if (Ptr.isUnknownSizeArray())
2018*700637cbSDimitry Andric     return false;
2019*700637cbSDimitry Andric 
2020*700637cbSDimitry Andric   // In the unlikely event that we're initializing the first item of
2021*700637cbSDimitry Andric   // a non-array, skip the atIndex().
2022*700637cbSDimitry Andric   if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {
2023*700637cbSDimitry Andric     Ptr.initialize();
2024*700637cbSDimitry Andric     new (&Ptr.deref<T>()) T(Value);
2025*700637cbSDimitry Andric     return true;
2026*700637cbSDimitry Andric   }
2027*700637cbSDimitry Andric 
2028*700637cbSDimitry Andric   const Pointer &ElemPtr = Ptr.atIndex(Idx);
2029*700637cbSDimitry Andric   if (!CheckInit(S, OpPC, ElemPtr))
2030*700637cbSDimitry Andric     return false;
2031*700637cbSDimitry Andric   ElemPtr.initialize();
2032*700637cbSDimitry Andric   new (&ElemPtr.deref<T>()) T(Value);
2033*700637cbSDimitry Andric   return true;
2034*700637cbSDimitry Andric }
2035*700637cbSDimitry Andric 
Memcpy(InterpState & S,CodePtr OpPC)2036*700637cbSDimitry Andric inline bool Memcpy(InterpState &S, CodePtr OpPC) {
2037*700637cbSDimitry Andric   const Pointer &Src = S.Stk.pop<Pointer>();
2038*700637cbSDimitry Andric   Pointer &Dest = S.Stk.peek<Pointer>();
2039*700637cbSDimitry Andric 
2040*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Src))
2041*700637cbSDimitry Andric     return false;
2042*700637cbSDimitry Andric 
2043*700637cbSDimitry Andric   return DoMemcpy(S, OpPC, Src, Dest);
2044*700637cbSDimitry Andric }
2045*700637cbSDimitry Andric 
ToMemberPtr(InterpState & S,CodePtr OpPC)2046*700637cbSDimitry Andric inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {
2047*700637cbSDimitry Andric   const auto &Member = S.Stk.pop<MemberPointer>();
2048*700637cbSDimitry Andric   const auto &Base = S.Stk.pop<Pointer>();
2049*700637cbSDimitry Andric 
2050*700637cbSDimitry Andric   S.Stk.push<MemberPointer>(Member.takeInstance(Base));
2051*700637cbSDimitry Andric   return true;
2052*700637cbSDimitry Andric }
2053*700637cbSDimitry Andric 
CastMemberPtrPtr(InterpState & S,CodePtr OpPC)2054*700637cbSDimitry Andric inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {
2055*700637cbSDimitry Andric   const auto &MP = S.Stk.pop<MemberPointer>();
2056*700637cbSDimitry Andric 
2057*700637cbSDimitry Andric   if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {
2058*700637cbSDimitry Andric     S.Stk.push<Pointer>(*Ptr);
2059*700637cbSDimitry Andric     return true;
2060*700637cbSDimitry Andric   }
2061*700637cbSDimitry Andric   return Invalid(S, OpPC);
2062*700637cbSDimitry Andric }
2063*700637cbSDimitry Andric 
2064*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2065*700637cbSDimitry Andric // AddOffset, SubOffset
2066*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2067*700637cbSDimitry Andric 
2068*700637cbSDimitry Andric template <class T, ArithOp Op>
2069*700637cbSDimitry Andric std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,
2070*700637cbSDimitry Andric                                     const T &Offset, const Pointer &Ptr,
2071*700637cbSDimitry Andric                                     bool IsPointerArith = false) {
2072*700637cbSDimitry Andric   // A zero offset does not change the pointer.
2073*700637cbSDimitry Andric   if (Offset.isZero())
2074*700637cbSDimitry Andric     return Ptr;
2075*700637cbSDimitry Andric 
2076*700637cbSDimitry Andric   if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
2077*700637cbSDimitry Andric     // The CheckNull will have emitted a note already, but we only
2078*700637cbSDimitry Andric     // abort in C++, since this is fine in C.
2079*700637cbSDimitry Andric     if (S.getLangOpts().CPlusPlus)
2080*700637cbSDimitry Andric       return std::nullopt;
2081*700637cbSDimitry Andric   }
2082*700637cbSDimitry Andric 
2083*700637cbSDimitry Andric   // Arrays of unknown bounds cannot have pointers into them.
2084*700637cbSDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
2085*700637cbSDimitry Andric     return std::nullopt;
2086*700637cbSDimitry Andric 
2087*700637cbSDimitry Andric   // This is much simpler for integral pointers, so handle them first.
2088*700637cbSDimitry Andric   if (Ptr.isIntegralPointer()) {
2089*700637cbSDimitry Andric     uint64_t V = Ptr.getIntegerRepresentation();
2090*700637cbSDimitry Andric     uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();
2091*700637cbSDimitry Andric     if constexpr (Op == ArithOp::Add)
2092*700637cbSDimitry Andric       return Pointer(V + O, Ptr.asIntPointer().Desc);
2093*700637cbSDimitry Andric     else
2094*700637cbSDimitry Andric       return Pointer(V - O, Ptr.asIntPointer().Desc);
2095*700637cbSDimitry Andric   } else if (Ptr.isFunctionPointer()) {
2096*700637cbSDimitry Andric     uint64_t O = static_cast<uint64_t>(Offset);
2097*700637cbSDimitry Andric     uint64_t N;
2098*700637cbSDimitry Andric     if constexpr (Op == ArithOp::Add)
2099*700637cbSDimitry Andric       N = Ptr.getByteOffset() + O;
2100*700637cbSDimitry Andric     else
2101*700637cbSDimitry Andric       N = Ptr.getByteOffset() - O;
2102*700637cbSDimitry Andric 
2103*700637cbSDimitry Andric     if (N > 1)
2104*700637cbSDimitry Andric       S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
2105*700637cbSDimitry Andric           << N << /*non-array*/ true << 0;
2106*700637cbSDimitry Andric     return Pointer(Ptr.asFunctionPointer().getFunction(), N);
2107*700637cbSDimitry Andric   }
2108*700637cbSDimitry Andric 
2109*700637cbSDimitry Andric   assert(Ptr.isBlockPointer());
2110*700637cbSDimitry Andric 
2111*700637cbSDimitry Andric   uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());
2112*700637cbSDimitry Andric   uint64_t Index;
2113*700637cbSDimitry Andric   if (Ptr.isOnePastEnd())
2114*700637cbSDimitry Andric     Index = MaxIndex;
2115*700637cbSDimitry Andric   else
2116*700637cbSDimitry Andric     Index = Ptr.getIndex();
2117*700637cbSDimitry Andric 
2118*700637cbSDimitry Andric   bool Invalid = false;
2119*700637cbSDimitry Andric   // Helper to report an invalid offset, computed as APSInt.
2120*700637cbSDimitry Andric   auto DiagInvalidOffset = [&]() -> void {
2121*700637cbSDimitry Andric     const unsigned Bits = Offset.bitWidth();
2122*700637cbSDimitry Andric     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);
2123*700637cbSDimitry Andric     APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),
2124*700637cbSDimitry Andric                    /*IsUnsigned=*/false);
2125*700637cbSDimitry Andric     APSInt NewIndex =
2126*700637cbSDimitry Andric         (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);
2127*700637cbSDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
2128*700637cbSDimitry Andric         << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;
2129*700637cbSDimitry Andric     Invalid = true;
2130*700637cbSDimitry Andric   };
2131*700637cbSDimitry Andric 
2132*700637cbSDimitry Andric   if (Ptr.isBlockPointer()) {
2133*700637cbSDimitry Andric     uint64_t IOffset = static_cast<uint64_t>(Offset);
2134*700637cbSDimitry Andric     uint64_t MaxOffset = MaxIndex - Index;
2135*700637cbSDimitry Andric 
2136*700637cbSDimitry Andric     if constexpr (Op == ArithOp::Add) {
2137*700637cbSDimitry Andric       // If the new offset would be negative, bail out.
2138*700637cbSDimitry Andric       if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))
2139*700637cbSDimitry Andric         DiagInvalidOffset();
2140*700637cbSDimitry Andric 
2141*700637cbSDimitry Andric       // If the new offset would be out of bounds, bail out.
2142*700637cbSDimitry Andric       if (Offset.isPositive() && IOffset > MaxOffset)
2143*700637cbSDimitry Andric         DiagInvalidOffset();
2144*700637cbSDimitry Andric     } else {
2145*700637cbSDimitry Andric       // If the new offset would be negative, bail out.
2146*700637cbSDimitry Andric       if (Offset.isPositive() && Index < IOffset)
2147*700637cbSDimitry Andric         DiagInvalidOffset();
2148*700637cbSDimitry Andric 
2149*700637cbSDimitry Andric       // If the new offset would be out of bounds, bail out.
2150*700637cbSDimitry Andric       if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))
2151*700637cbSDimitry Andric         DiagInvalidOffset();
2152*700637cbSDimitry Andric     }
2153*700637cbSDimitry Andric   }
2154*700637cbSDimitry Andric 
2155*700637cbSDimitry Andric   if (Invalid && S.getLangOpts().CPlusPlus)
2156*700637cbSDimitry Andric     return std::nullopt;
2157*700637cbSDimitry Andric 
2158*700637cbSDimitry Andric   // Offset is valid - compute it on unsigned.
2159*700637cbSDimitry Andric   int64_t WideIndex = static_cast<int64_t>(Index);
2160*700637cbSDimitry Andric   int64_t WideOffset = static_cast<int64_t>(Offset);
2161*700637cbSDimitry Andric   int64_t Result;
2162*700637cbSDimitry Andric   if constexpr (Op == ArithOp::Add)
2163*700637cbSDimitry Andric     Result = WideIndex + WideOffset;
2164*700637cbSDimitry Andric   else
2165*700637cbSDimitry Andric     Result = WideIndex - WideOffset;
2166*700637cbSDimitry Andric 
2167*700637cbSDimitry Andric   // When the pointer is one-past-end, going back to index 0 is the only
2168*700637cbSDimitry Andric   // useful thing we can do. Any other index has been diagnosed before and
2169*700637cbSDimitry Andric   // we don't get here.
2170*700637cbSDimitry Andric   if (Result == 0 && Ptr.isOnePastEnd()) {
2171*700637cbSDimitry Andric     if (Ptr.getFieldDesc()->isArray())
2172*700637cbSDimitry Andric       return Ptr.atIndex(0);
2173*700637cbSDimitry Andric     return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);
2174*700637cbSDimitry Andric   }
2175*700637cbSDimitry Andric 
2176*700637cbSDimitry Andric   return Ptr.atIndex(static_cast<uint64_t>(Result));
2177*700637cbSDimitry Andric }
2178*700637cbSDimitry Andric 
2179*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)2180*700637cbSDimitry Andric bool AddOffset(InterpState &S, CodePtr OpPC) {
2181*700637cbSDimitry Andric   const T &Offset = S.Stk.pop<T>();
2182*700637cbSDimitry Andric   Pointer Ptr = S.Stk.pop<Pointer>();
2183*700637cbSDimitry Andric   if (Ptr.isBlockPointer())
2184*700637cbSDimitry Andric     Ptr = Ptr.expand();
2185*700637cbSDimitry Andric 
2186*700637cbSDimitry Andric   if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(
2187*700637cbSDimitry Andric           S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2188*700637cbSDimitry Andric     S.Stk.push<Pointer>(*Result);
2189*700637cbSDimitry Andric     return true;
2190*700637cbSDimitry Andric   }
2191*700637cbSDimitry Andric   return false;
2192*700637cbSDimitry Andric }
2193*700637cbSDimitry Andric 
2194*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)2195*700637cbSDimitry Andric bool SubOffset(InterpState &S, CodePtr OpPC) {
2196*700637cbSDimitry Andric   const T &Offset = S.Stk.pop<T>();
2197*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2198*700637cbSDimitry Andric 
2199*700637cbSDimitry Andric   if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(
2200*700637cbSDimitry Andric           S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {
2201*700637cbSDimitry Andric     S.Stk.push<Pointer>(*Result);
2202*700637cbSDimitry Andric     return true;
2203*700637cbSDimitry Andric   }
2204*700637cbSDimitry Andric   return false;
2205*700637cbSDimitry Andric }
2206*700637cbSDimitry Andric 
2207*700637cbSDimitry Andric template <ArithOp Op>
IncDecPtrHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)2208*700637cbSDimitry Andric static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
2209*700637cbSDimitry Andric                                    const Pointer &Ptr) {
2210*700637cbSDimitry Andric   if (Ptr.isDummy())
2211*700637cbSDimitry Andric     return false;
2212*700637cbSDimitry Andric 
2213*700637cbSDimitry Andric   using OneT = Integral<8, false>;
2214*700637cbSDimitry Andric 
2215*700637cbSDimitry Andric   const Pointer &P = Ptr.deref<Pointer>();
2216*700637cbSDimitry Andric   if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))
2217*700637cbSDimitry Andric     return false;
2218*700637cbSDimitry Andric 
2219*700637cbSDimitry Andric   // Get the current value on the stack.
2220*700637cbSDimitry Andric   S.Stk.push<Pointer>(P);
2221*700637cbSDimitry Andric 
2222*700637cbSDimitry Andric   // Now the current Ptr again and a constant 1.
2223*700637cbSDimitry Andric   OneT One = OneT::from(1);
2224*700637cbSDimitry Andric   if (std::optional<Pointer> Result =
2225*700637cbSDimitry Andric           OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) {
2226*700637cbSDimitry Andric     // Store the new value.
2227*700637cbSDimitry Andric     Ptr.deref<Pointer>() = *Result;
2228*700637cbSDimitry Andric     return true;
2229*700637cbSDimitry Andric   }
2230*700637cbSDimitry Andric   return false;
2231*700637cbSDimitry Andric }
2232*700637cbSDimitry Andric 
IncPtr(InterpState & S,CodePtr OpPC)2233*700637cbSDimitry Andric static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
2234*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2235*700637cbSDimitry Andric 
2236*700637cbSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
2237*700637cbSDimitry Andric     return false;
2238*700637cbSDimitry Andric 
2239*700637cbSDimitry Andric   return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
2240*700637cbSDimitry Andric }
2241*700637cbSDimitry Andric 
DecPtr(InterpState & S,CodePtr OpPC)2242*700637cbSDimitry Andric static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
2243*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2244*700637cbSDimitry Andric 
2245*700637cbSDimitry Andric   if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
2246*700637cbSDimitry Andric     return false;
2247*700637cbSDimitry Andric 
2248*700637cbSDimitry Andric   return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
2249*700637cbSDimitry Andric }
2250*700637cbSDimitry Andric 
2251*700637cbSDimitry Andric /// 1) Pops a Pointer from the stack.
2252*700637cbSDimitry Andric /// 2) Pops another Pointer from the stack.
2253*700637cbSDimitry Andric /// 3) Pushes the difference of the indices of the two pointers on the stack.
2254*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
SubPtr(InterpState & S,CodePtr OpPC)2255*700637cbSDimitry Andric inline bool SubPtr(InterpState &S, CodePtr OpPC) {
2256*700637cbSDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
2257*700637cbSDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
2258*700637cbSDimitry Andric 
2259*700637cbSDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
2260*700637cbSDimitry Andric     S.FFDiag(S.Current->getSource(OpPC),
2261*700637cbSDimitry Andric              diag::note_constexpr_pointer_arith_unspecified)
2262*700637cbSDimitry Andric         << LHS.toDiagnosticString(S.getASTContext())
2263*700637cbSDimitry Andric         << RHS.toDiagnosticString(S.getASTContext());
2264*700637cbSDimitry Andric     return false;
2265*700637cbSDimitry Andric   }
2266*700637cbSDimitry Andric 
2267*700637cbSDimitry Andric   if (LHS == RHS) {
2268*700637cbSDimitry Andric     S.Stk.push<T>();
2269*700637cbSDimitry Andric     return true;
2270*700637cbSDimitry Andric   }
2271*700637cbSDimitry Andric 
2272*700637cbSDimitry Andric   for (const Pointer &P : {LHS, RHS}) {
2273*700637cbSDimitry Andric     if (P.isZeroSizeArray()) {
2274*700637cbSDimitry Andric       QualType PtrT = P.getType();
2275*700637cbSDimitry Andric       while (auto *AT = dyn_cast<ArrayType>(PtrT))
2276*700637cbSDimitry Andric         PtrT = AT->getElementType();
2277*700637cbSDimitry Andric 
2278*700637cbSDimitry Andric       QualType ArrayTy = S.getASTContext().getConstantArrayType(
2279*700637cbSDimitry Andric           PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);
2280*700637cbSDimitry Andric       S.FFDiag(S.Current->getSource(OpPC),
2281*700637cbSDimitry Andric                diag::note_constexpr_pointer_subtraction_zero_size)
2282*700637cbSDimitry Andric           << ArrayTy;
2283*700637cbSDimitry Andric 
2284*700637cbSDimitry Andric       return false;
2285*700637cbSDimitry Andric     }
2286*700637cbSDimitry Andric   }
2287*700637cbSDimitry Andric 
2288*700637cbSDimitry Andric   int64_t A64 =
2289*700637cbSDimitry Andric       LHS.isBlockPointer()
2290*700637cbSDimitry Andric           ? (LHS.isElementPastEnd() ? LHS.getNumElems() : LHS.getIndex())
2291*700637cbSDimitry Andric           : LHS.getIntegerRepresentation();
2292*700637cbSDimitry Andric 
2293*700637cbSDimitry Andric   int64_t B64 =
2294*700637cbSDimitry Andric       RHS.isBlockPointer()
2295*700637cbSDimitry Andric           ? (RHS.isElementPastEnd() ? RHS.getNumElems() : RHS.getIndex())
2296*700637cbSDimitry Andric           : RHS.getIntegerRepresentation();
2297*700637cbSDimitry Andric 
2298*700637cbSDimitry Andric   int64_t R64 = A64 - B64;
2299*700637cbSDimitry Andric   if (static_cast<int64_t>(T::from(R64)) != R64)
2300*700637cbSDimitry Andric     return handleOverflow(S, OpPC, R64);
2301*700637cbSDimitry Andric 
2302*700637cbSDimitry Andric   S.Stk.push<T>(T::from(R64));
2303*700637cbSDimitry Andric   return true;
2304*700637cbSDimitry Andric }
2305*700637cbSDimitry Andric 
2306*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2307*700637cbSDimitry Andric // Destroy
2308*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2309*700637cbSDimitry Andric 
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)2310*700637cbSDimitry Andric inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
2311*700637cbSDimitry Andric   assert(S.Current->getFunction());
2312*700637cbSDimitry Andric 
2313*700637cbSDimitry Andric   // FIXME: We iterate the scope once here and then again in the destroy() call
2314*700637cbSDimitry Andric   // below.
2315*700637cbSDimitry Andric   for (auto &Local : S.Current->getFunction()->getScope(I).locals_reverse()) {
2316*700637cbSDimitry Andric     const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset);
2317*700637cbSDimitry Andric 
2318*700637cbSDimitry Andric     if (Ptr.getLifetime() == Lifetime::Ended) {
2319*700637cbSDimitry Andric       auto *D = cast<NamedDecl>(Ptr.getFieldDesc()->asDecl());
2320*700637cbSDimitry Andric       S.FFDiag(D->getLocation(), diag::note_constexpr_destroy_out_of_lifetime)
2321*700637cbSDimitry Andric           << D->getNameAsString();
2322*700637cbSDimitry Andric       return false;
2323*700637cbSDimitry Andric     }
2324*700637cbSDimitry Andric   }
2325*700637cbSDimitry Andric 
2326*700637cbSDimitry Andric   S.Current->destroy(I);
2327*700637cbSDimitry Andric   return true;
2328*700637cbSDimitry Andric }
2329*700637cbSDimitry Andric 
InitScope(InterpState & S,CodePtr OpPC,uint32_t I)2330*700637cbSDimitry Andric inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {
2331*700637cbSDimitry Andric   S.Current->initScope(I);
2332*700637cbSDimitry Andric   return true;
2333*700637cbSDimitry Andric }
2334*700637cbSDimitry Andric 
2335*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2336*700637cbSDimitry Andric // Cast, CastFP
2337*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2338*700637cbSDimitry Andric 
Cast(InterpState & S,CodePtr OpPC)2339*700637cbSDimitry Andric template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
2340*700637cbSDimitry Andric   using T = typename PrimConv<TIn>::T;
2341*700637cbSDimitry Andric   using U = typename PrimConv<TOut>::T;
2342*700637cbSDimitry Andric   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
2343*700637cbSDimitry Andric   return true;
2344*700637cbSDimitry Andric }
2345*700637cbSDimitry Andric 
2346*700637cbSDimitry Andric /// 1) Pops a Floating from the stack.
2347*700637cbSDimitry Andric /// 2) Pushes a new floating on the stack that uses the given semantics.
CastFP(InterpState & S,CodePtr OpPC,const llvm::fltSemantics * Sem,llvm::RoundingMode RM)2348*700637cbSDimitry Andric inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,
2349*700637cbSDimitry Andric                    llvm::RoundingMode RM) {
2350*700637cbSDimitry Andric   Floating F = S.Stk.pop<Floating>();
2351*700637cbSDimitry Andric   Floating Result = S.allocFloat(*Sem);
2352*700637cbSDimitry Andric   F.toSemantics(Sem, RM, &Result);
2353*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
2354*700637cbSDimitry Andric   return true;
2355*700637cbSDimitry Andric }
2356*700637cbSDimitry Andric 
CastFixedPoint(InterpState & S,CodePtr OpPC,uint32_t FPS)2357*700637cbSDimitry Andric inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
2358*700637cbSDimitry Andric   FixedPointSemantics TargetSemantics =
2359*700637cbSDimitry Andric       FixedPointSemantics::getFromOpaqueInt(FPS);
2360*700637cbSDimitry Andric   const auto &Source = S.Stk.pop<FixedPoint>();
2361*700637cbSDimitry Andric 
2362*700637cbSDimitry Andric   bool Overflow;
2363*700637cbSDimitry Andric   FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
2364*700637cbSDimitry Andric 
2365*700637cbSDimitry Andric   if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2366*700637cbSDimitry Andric     return false;
2367*700637cbSDimitry Andric 
2368*700637cbSDimitry Andric   S.Stk.push<FixedPoint>(Result);
2369*700637cbSDimitry Andric   return true;
2370*700637cbSDimitry Andric }
2371*700637cbSDimitry Andric 
2372*700637cbSDimitry Andric /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need
2373*700637cbSDimitry Andric /// to know what bitwidth the result should be.
2374*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2375*700637cbSDimitry Andric bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2376*700637cbSDimitry Andric   auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2377*700637cbSDimitry Andric   // Copy data.
2378*700637cbSDimitry Andric   {
2379*700637cbSDimitry Andric     APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
2380*700637cbSDimitry Andric     Result.copy(Source);
2381*700637cbSDimitry Andric   }
2382*700637cbSDimitry Andric   S.Stk.push<IntegralAP<false>>(Result);
2383*700637cbSDimitry Andric   return true;
2384*700637cbSDimitry Andric }
2385*700637cbSDimitry Andric 
2386*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2387*700637cbSDimitry Andric bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2388*700637cbSDimitry Andric   auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2389*700637cbSDimitry Andric   // Copy data.
2390*700637cbSDimitry Andric   {
2391*700637cbSDimitry Andric     APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);
2392*700637cbSDimitry Andric     Result.copy(Source);
2393*700637cbSDimitry Andric   }
2394*700637cbSDimitry Andric   S.Stk.push<IntegralAP<true>>(Result);
2395*700637cbSDimitry Andric   return true;
2396*700637cbSDimitry Andric }
2397*700637cbSDimitry Andric 
2398*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastIntegralFloating(InterpState & S,CodePtr OpPC,const llvm::fltSemantics * Sem,uint32_t FPOI)2399*700637cbSDimitry Andric bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
2400*700637cbSDimitry Andric                           const llvm::fltSemantics *Sem, uint32_t FPOI) {
2401*700637cbSDimitry Andric   const T &From = S.Stk.pop<T>();
2402*700637cbSDimitry Andric   APSInt FromAP = From.toAPSInt();
2403*700637cbSDimitry Andric 
2404*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
2405*700637cbSDimitry Andric   Floating Result = S.allocFloat(*Sem);
2406*700637cbSDimitry Andric   auto Status =
2407*700637cbSDimitry Andric       Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), &Result);
2408*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
2409*700637cbSDimitry Andric 
2410*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, Result, Status, FPO);
2411*700637cbSDimitry Andric }
2412*700637cbSDimitry Andric 
2413*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastFloatingIntegral(InterpState & S,CodePtr OpPC,uint32_t FPOI)2414*700637cbSDimitry Andric bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {
2415*700637cbSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
2416*700637cbSDimitry Andric 
2417*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Boolean>) {
2418*700637cbSDimitry Andric     S.Stk.push<T>(T(F.isNonZero()));
2419*700637cbSDimitry Andric     return true;
2420*700637cbSDimitry Andric   } else {
2421*700637cbSDimitry Andric     APSInt Result(std::max(8u, T::bitWidth()),
2422*700637cbSDimitry Andric                   /*IsUnsigned=*/!T::isSigned());
2423*700637cbSDimitry Andric     auto Status = F.convertToInteger(Result);
2424*700637cbSDimitry Andric 
2425*700637cbSDimitry Andric     // Float-to-Integral overflow check.
2426*700637cbSDimitry Andric     if ((Status & APFloat::opStatus::opInvalidOp)) {
2427*700637cbSDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
2428*700637cbSDimitry Andric       QualType Type = E->getType();
2429*700637cbSDimitry Andric 
2430*700637cbSDimitry Andric       S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
2431*700637cbSDimitry Andric       if (S.noteUndefinedBehavior()) {
2432*700637cbSDimitry Andric         S.Stk.push<T>(T(Result));
2433*700637cbSDimitry Andric         return true;
2434*700637cbSDimitry Andric       }
2435*700637cbSDimitry Andric       return false;
2436*700637cbSDimitry Andric     }
2437*700637cbSDimitry Andric 
2438*700637cbSDimitry Andric     FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
2439*700637cbSDimitry Andric     S.Stk.push<T>(T(Result));
2440*700637cbSDimitry Andric     return CheckFloatResult(S, OpPC, F, Status, FPO);
2441*700637cbSDimitry Andric   }
2442*700637cbSDimitry Andric }
2443*700637cbSDimitry Andric 
CastFloatingIntegralAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth,uint32_t FPOI)2444*700637cbSDimitry Andric static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
2445*700637cbSDimitry Andric                                           uint32_t BitWidth, uint32_t FPOI) {
2446*700637cbSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
2447*700637cbSDimitry Andric 
2448*700637cbSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/true);
2449*700637cbSDimitry Andric   auto Status = F.convertToInteger(Result);
2450*700637cbSDimitry Andric 
2451*700637cbSDimitry Andric   // Float-to-Integral overflow check.
2452*700637cbSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2453*700637cbSDimitry Andric     return handleOverflow(S, OpPC, F.getAPFloat());
2454*700637cbSDimitry Andric 
2455*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
2456*700637cbSDimitry Andric 
2457*700637cbSDimitry Andric   auto ResultAP = S.allocAP<IntegralAP<false>>(BitWidth);
2458*700637cbSDimitry Andric   ResultAP.copy(Result);
2459*700637cbSDimitry Andric 
2460*700637cbSDimitry Andric   S.Stk.push<IntegralAP<false>>(ResultAP);
2461*700637cbSDimitry Andric 
2462*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status, FPO);
2463*700637cbSDimitry Andric }
2464*700637cbSDimitry Andric 
CastFloatingIntegralAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth,uint32_t FPOI)2465*700637cbSDimitry Andric static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
2466*700637cbSDimitry Andric                                            uint32_t BitWidth, uint32_t FPOI) {
2467*700637cbSDimitry Andric   const Floating &F = S.Stk.pop<Floating>();
2468*700637cbSDimitry Andric 
2469*700637cbSDimitry Andric   APSInt Result(BitWidth, /*IsUnsigned=*/false);
2470*700637cbSDimitry Andric   auto Status = F.convertToInteger(Result);
2471*700637cbSDimitry Andric 
2472*700637cbSDimitry Andric   // Float-to-Integral overflow check.
2473*700637cbSDimitry Andric   if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
2474*700637cbSDimitry Andric     return handleOverflow(S, OpPC, F.getAPFloat());
2475*700637cbSDimitry Andric 
2476*700637cbSDimitry Andric   FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
2477*700637cbSDimitry Andric 
2478*700637cbSDimitry Andric   auto ResultAP = S.allocAP<IntegralAP<true>>(BitWidth);
2479*700637cbSDimitry Andric   ResultAP.copy(Result);
2480*700637cbSDimitry Andric 
2481*700637cbSDimitry Andric   S.Stk.push<IntegralAP<true>>(ResultAP);
2482*700637cbSDimitry Andric 
2483*700637cbSDimitry Andric   return CheckFloatResult(S, OpPC, F, Status, FPO);
2484*700637cbSDimitry Andric }
2485*700637cbSDimitry Andric 
2486*700637cbSDimitry Andric bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
2487*700637cbSDimitry Andric                                 const Pointer &Ptr, unsigned BitWidth);
2488*700637cbSDimitry Andric bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2489*700637cbSDimitry Andric bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);
2490*700637cbSDimitry Andric 
2491*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastPointerIntegral(InterpState & S,CodePtr OpPC)2492*700637cbSDimitry Andric bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {
2493*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2494*700637cbSDimitry Andric 
2495*700637cbSDimitry Andric   S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
2496*700637cbSDimitry Andric       << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2497*700637cbSDimitry Andric       << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2498*700637cbSDimitry Andric 
2499*700637cbSDimitry Andric   if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))
2500*700637cbSDimitry Andric     return Invalid(S, OpPC);
2501*700637cbSDimitry Andric 
2502*700637cbSDimitry Andric   S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));
2503*700637cbSDimitry Andric   return true;
2504*700637cbSDimitry Andric }
2505*700637cbSDimitry Andric 
2506*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastIntegralFixedPoint(InterpState & S,CodePtr OpPC,uint32_t FPS)2507*700637cbSDimitry Andric static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
2508*700637cbSDimitry Andric                                           uint32_t FPS) {
2509*700637cbSDimitry Andric   const T &Int = S.Stk.pop<T>();
2510*700637cbSDimitry Andric 
2511*700637cbSDimitry Andric   FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2512*700637cbSDimitry Andric 
2513*700637cbSDimitry Andric   bool Overflow;
2514*700637cbSDimitry Andric   FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
2515*700637cbSDimitry Andric 
2516*700637cbSDimitry Andric   if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2517*700637cbSDimitry Andric     return false;
2518*700637cbSDimitry Andric 
2519*700637cbSDimitry Andric   S.Stk.push<FixedPoint>(Result);
2520*700637cbSDimitry Andric   return true;
2521*700637cbSDimitry Andric }
2522*700637cbSDimitry Andric 
CastFloatingFixedPoint(InterpState & S,CodePtr OpPC,uint32_t FPS)2523*700637cbSDimitry Andric static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
2524*700637cbSDimitry Andric                                           uint32_t FPS) {
2525*700637cbSDimitry Andric   const auto &Float = S.Stk.pop<Floating>();
2526*700637cbSDimitry Andric 
2527*700637cbSDimitry Andric   FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);
2528*700637cbSDimitry Andric 
2529*700637cbSDimitry Andric   bool Overflow;
2530*700637cbSDimitry Andric   FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
2531*700637cbSDimitry Andric 
2532*700637cbSDimitry Andric   if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
2533*700637cbSDimitry Andric     return false;
2534*700637cbSDimitry Andric 
2535*700637cbSDimitry Andric   S.Stk.push<FixedPoint>(Result);
2536*700637cbSDimitry Andric   return true;
2537*700637cbSDimitry Andric }
2538*700637cbSDimitry Andric 
CastFixedPointFloating(InterpState & S,CodePtr OpPC,const llvm::fltSemantics * Sem)2539*700637cbSDimitry Andric static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
2540*700637cbSDimitry Andric                                           const llvm::fltSemantics *Sem) {
2541*700637cbSDimitry Andric   const auto &Fixed = S.Stk.pop<FixedPoint>();
2542*700637cbSDimitry Andric   Floating Result = S.allocFloat(*Sem);
2543*700637cbSDimitry Andric   Result.copy(Fixed.toFloat(Sem));
2544*700637cbSDimitry Andric   S.Stk.push<Floating>(Result);
2545*700637cbSDimitry Andric   return true;
2546*700637cbSDimitry Andric }
2547*700637cbSDimitry Andric 
2548*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CastFixedPointIntegral(InterpState & S,CodePtr OpPC)2549*700637cbSDimitry Andric static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
2550*700637cbSDimitry Andric   const auto &Fixed = S.Stk.pop<FixedPoint>();
2551*700637cbSDimitry Andric 
2552*700637cbSDimitry Andric   bool Overflow;
2553*700637cbSDimitry Andric   APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
2554*700637cbSDimitry Andric 
2555*700637cbSDimitry Andric   if (Overflow && !handleOverflow(S, OpPC, Int))
2556*700637cbSDimitry Andric     return false;
2557*700637cbSDimitry Andric 
2558*700637cbSDimitry Andric   S.Stk.push<T>(Int);
2559*700637cbSDimitry Andric   return true;
2560*700637cbSDimitry Andric }
2561*700637cbSDimitry Andric 
PtrPtrCast(InterpState & S,CodePtr OpPC,bool SrcIsVoidPtr)2562*700637cbSDimitry Andric static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
2563*700637cbSDimitry Andric   const auto &Ptr = S.Stk.peek<Pointer>();
2564*700637cbSDimitry Andric 
2565*700637cbSDimitry Andric   if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {
2566*700637cbSDimitry Andric     bool HasValidResult = !Ptr.isZero();
2567*700637cbSDimitry Andric 
2568*700637cbSDimitry Andric     if (HasValidResult) {
2569*700637cbSDimitry Andric       if (S.getStdAllocatorCaller("allocate"))
2570*700637cbSDimitry Andric         return true;
2571*700637cbSDimitry Andric 
2572*700637cbSDimitry Andric       const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));
2573*700637cbSDimitry Andric       if (S.getLangOpts().CPlusPlus26 &&
2574*700637cbSDimitry Andric           S.getASTContext().hasSimilarType(Ptr.getType(),
2575*700637cbSDimitry Andric                                            E->getType()->getPointeeType()))
2576*700637cbSDimitry Andric         return true;
2577*700637cbSDimitry Andric 
2578*700637cbSDimitry Andric       S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)
2579*700637cbSDimitry Andric           << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus26
2580*700637cbSDimitry Andric           << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();
2581*700637cbSDimitry Andric     } else if (!S.getLangOpts().CPlusPlus26) {
2582*700637cbSDimitry Andric       const SourceInfo &E = S.Current->getSource(OpPC);
2583*700637cbSDimitry Andric       S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2584*700637cbSDimitry Andric           << diag::ConstexprInvalidCastKind::CastFrom << "'void *'"
2585*700637cbSDimitry Andric           << S.Current->getRange(OpPC);
2586*700637cbSDimitry Andric     }
2587*700637cbSDimitry Andric   } else {
2588*700637cbSDimitry Andric     const SourceInfo &E = S.Current->getSource(OpPC);
2589*700637cbSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_invalid_cast)
2590*700637cbSDimitry Andric         << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
2591*700637cbSDimitry Andric         << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
2592*700637cbSDimitry Andric   }
2593*700637cbSDimitry Andric 
2594*700637cbSDimitry Andric   return true;
2595*700637cbSDimitry Andric }
2596*700637cbSDimitry Andric 
2597*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2598*700637cbSDimitry Andric // Zero, Nullptr
2599*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2600*700637cbSDimitry Andric 
2601*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)2602*700637cbSDimitry Andric bool Zero(InterpState &S, CodePtr OpPC) {
2603*700637cbSDimitry Andric   S.Stk.push<T>(T::zero());
2604*700637cbSDimitry Andric   return true;
2605*700637cbSDimitry Andric }
2606*700637cbSDimitry Andric 
ZeroIntAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2607*700637cbSDimitry Andric static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2608*700637cbSDimitry Andric   auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
2609*700637cbSDimitry Andric   if (!Result.singleWord())
2610*700637cbSDimitry Andric     std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
2611*700637cbSDimitry Andric   S.Stk.push<IntegralAP<false>>(Result);
2612*700637cbSDimitry Andric   return true;
2613*700637cbSDimitry Andric }
2614*700637cbSDimitry Andric 
ZeroIntAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)2615*700637cbSDimitry Andric static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
2616*700637cbSDimitry Andric   auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
2617*700637cbSDimitry Andric   if (!Result.singleWord())
2618*700637cbSDimitry Andric     std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));
2619*700637cbSDimitry Andric   S.Stk.push<IntegralAP<true>>(Result);
2620*700637cbSDimitry Andric   return true;
2621*700637cbSDimitry Andric }
2622*700637cbSDimitry Andric 
2623*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC,uint64_t Value,const Descriptor * Desc)2624*700637cbSDimitry Andric inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
2625*700637cbSDimitry Andric                  const Descriptor *Desc) {
2626*700637cbSDimitry Andric   // FIXME(perf): This is a somewhat often-used function and the value of a
2627*700637cbSDimitry Andric   // null pointer is almost always 0.
2628*700637cbSDimitry Andric   S.Stk.push<T>(Value, Desc);
2629*700637cbSDimitry Andric   return true;
2630*700637cbSDimitry Andric }
2631*700637cbSDimitry Andric 
2632*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
IsNonNull(InterpState & S,CodePtr OpPC)2633*700637cbSDimitry Andric inline bool IsNonNull(InterpState &S, CodePtr OpPC) {
2634*700637cbSDimitry Andric   const auto &P = S.Stk.pop<T>();
2635*700637cbSDimitry Andric   if (P.isWeak())
2636*700637cbSDimitry Andric     return false;
2637*700637cbSDimitry Andric   S.Stk.push<Boolean>(Boolean::from(!P.isZero()));
2638*700637cbSDimitry Andric   return true;
2639*700637cbSDimitry Andric }
2640*700637cbSDimitry Andric 
2641*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2642*700637cbSDimitry Andric // This, ImplicitThis
2643*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2644*700637cbSDimitry Andric 
This(InterpState & S,CodePtr OpPC)2645*700637cbSDimitry Andric inline bool This(InterpState &S, CodePtr OpPC) {
2646*700637cbSDimitry Andric   // Cannot read 'this' in this mode.
2647*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression()) {
2648*700637cbSDimitry Andric     return false;
2649*700637cbSDimitry Andric   }
2650*700637cbSDimitry Andric 
2651*700637cbSDimitry Andric   const Pointer &This = S.Current->getThis();
2652*700637cbSDimitry Andric   if (!CheckThis(S, OpPC, This))
2653*700637cbSDimitry Andric     return false;
2654*700637cbSDimitry Andric 
2655*700637cbSDimitry Andric   // Ensure the This pointer has been cast to the correct base.
2656*700637cbSDimitry Andric   if (!This.isDummy()) {
2657*700637cbSDimitry Andric     assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));
2658*700637cbSDimitry Andric     if (!This.isTypeidPointer()) {
2659*700637cbSDimitry Andric       [[maybe_unused]] const Record *R = This.getRecord();
2660*700637cbSDimitry Andric       if (!R)
2661*700637cbSDimitry Andric         R = This.narrow().getRecord();
2662*700637cbSDimitry Andric       assert(R);
2663*700637cbSDimitry Andric       assert(R->getDecl() ==
2664*700637cbSDimitry Andric              cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())
2665*700637cbSDimitry Andric                  ->getParent());
2666*700637cbSDimitry Andric     }
2667*700637cbSDimitry Andric   }
2668*700637cbSDimitry Andric 
2669*700637cbSDimitry Andric   S.Stk.push<Pointer>(This);
2670*700637cbSDimitry Andric   return true;
2671*700637cbSDimitry Andric }
2672*700637cbSDimitry Andric 
RVOPtr(InterpState & S,CodePtr OpPC)2673*700637cbSDimitry Andric inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
2674*700637cbSDimitry Andric   assert(S.Current->getFunction()->hasRVO());
2675*700637cbSDimitry Andric   if (S.checkingPotentialConstantExpression())
2676*700637cbSDimitry Andric     return false;
2677*700637cbSDimitry Andric   S.Stk.push<Pointer>(S.Current->getRVOPtr());
2678*700637cbSDimitry Andric   return true;
2679*700637cbSDimitry Andric }
2680*700637cbSDimitry Andric 
2681*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2682*700637cbSDimitry Andric // Shr, Shl
2683*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2684*700637cbSDimitry Andric 
2685*700637cbSDimitry Andric template <class LT, class RT, ShiftDir Dir>
DoShift(InterpState & S,CodePtr OpPC,LT & LHS,RT & RHS,LT * Result)2686*700637cbSDimitry Andric inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,
2687*700637cbSDimitry Andric                     LT *Result) {
2688*700637cbSDimitry Andric   static_assert(!needsAlloc<LT>());
2689*700637cbSDimitry Andric   const unsigned Bits = LHS.bitWidth();
2690*700637cbSDimitry Andric 
2691*700637cbSDimitry Andric   // OpenCL 6.3j: shift values are effectively % word size of LHS.
2692*700637cbSDimitry Andric   if (S.getLangOpts().OpenCL)
2693*700637cbSDimitry Andric     RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),
2694*700637cbSDimitry Andric                RHS.bitWidth(), &RHS);
2695*700637cbSDimitry Andric 
2696*700637cbSDimitry Andric   if (RHS.isNegative()) {
2697*700637cbSDimitry Andric     // During constant-folding, a negative shift is an opposite shift. Such a
2698*700637cbSDimitry Andric     // shift is not a constant expression.
2699*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
2700*700637cbSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
2701*700637cbSDimitry Andric     if (!S.noteUndefinedBehavior())
2702*700637cbSDimitry Andric       return false;
2703*700637cbSDimitry Andric     RHS = -RHS;
2704*700637cbSDimitry Andric     return DoShift<LT, RT,
2705*700637cbSDimitry Andric                    Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
2706*700637cbSDimitry Andric         S, OpPC, LHS, RHS, Result);
2707*700637cbSDimitry Andric   }
2708*700637cbSDimitry Andric 
2709*700637cbSDimitry Andric   if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2710*700637cbSDimitry Andric     return false;
2711*700637cbSDimitry Andric 
2712*700637cbSDimitry Andric   // Limit the shift amount to Bits - 1. If this happened,
2713*700637cbSDimitry Andric   // it has already been diagnosed by CheckShift() above,
2714*700637cbSDimitry Andric   // but we still need to handle it.
2715*700637cbSDimitry Andric   // Note that we have to be extra careful here since we're doing the shift in
2716*700637cbSDimitry Andric   // any case, but we need to adjust the shift amount or the way we do the shift
2717*700637cbSDimitry Andric   // for the potential error cases.
2718*700637cbSDimitry Andric   typename LT::AsUnsigned R;
2719*700637cbSDimitry Andric   unsigned MaxShiftAmount = LHS.bitWidth() - 1;
2720*700637cbSDimitry Andric   if constexpr (Dir == ShiftDir::Left) {
2721*700637cbSDimitry Andric     if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2722*700637cbSDimitry Andric         ComparisonCategoryResult::Greater) {
2723*700637cbSDimitry Andric       if (LHS.isNegative())
2724*700637cbSDimitry Andric         R = LT::AsUnsigned::zero(LHS.bitWidth());
2725*700637cbSDimitry Andric       else {
2726*700637cbSDimitry Andric         RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());
2727*700637cbSDimitry Andric         LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2728*700637cbSDimitry Andric                                   LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2729*700637cbSDimitry Andric       }
2730*700637cbSDimitry Andric     } else if (LHS.isNegative()) {
2731*700637cbSDimitry Andric       if (LHS.isMin()) {
2732*700637cbSDimitry Andric         R = LT::AsUnsigned::zero(LHS.bitWidth());
2733*700637cbSDimitry Andric       } else {
2734*700637cbSDimitry Andric         // If the LHS is negative, perform the cast and invert the result.
2735*700637cbSDimitry Andric         typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);
2736*700637cbSDimitry Andric         LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,
2737*700637cbSDimitry Andric                                   &R);
2738*700637cbSDimitry Andric         R = -R;
2739*700637cbSDimitry Andric       }
2740*700637cbSDimitry Andric     } else {
2741*700637cbSDimitry Andric       // The good case, a simple left shift.
2742*700637cbSDimitry Andric       LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
2743*700637cbSDimitry Andric                                 LT::AsUnsigned::from(RHS, Bits), Bits, &R);
2744*700637cbSDimitry Andric     }
2745*700637cbSDimitry Andric     S.Stk.push<LT>(LT::from(R));
2746*700637cbSDimitry Andric     return true;
2747*700637cbSDimitry Andric   }
2748*700637cbSDimitry Andric 
2749*700637cbSDimitry Andric     // Right shift.
2750*700637cbSDimitry Andric     if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==
2751*700637cbSDimitry Andric         ComparisonCategoryResult::Greater) {
2752*700637cbSDimitry Andric       R = LT::AsUnsigned::from(-1);
2753*700637cbSDimitry Andric     } else {
2754*700637cbSDimitry Andric       // Do the shift on potentially signed LT, then convert to unsigned type.
2755*700637cbSDimitry Andric       LT A;
2756*700637cbSDimitry Andric       LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);
2757*700637cbSDimitry Andric       R = LT::AsUnsigned::from(A);
2758*700637cbSDimitry Andric     }
2759*700637cbSDimitry Andric 
2760*700637cbSDimitry Andric   S.Stk.push<LT>(LT::from(R));
2761*700637cbSDimitry Andric   return true;
2762*700637cbSDimitry Andric }
2763*700637cbSDimitry Andric 
2764*700637cbSDimitry Andric /// A version of DoShift that works on IntegralAP.
2765*700637cbSDimitry Andric template <class LT, class RT, ShiftDir Dir>
DoShiftAP(InterpState & S,CodePtr OpPC,const APSInt & LHS,APSInt RHS,LT * Result)2766*700637cbSDimitry Andric inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS,
2767*700637cbSDimitry Andric                       APSInt RHS, LT *Result) {
2768*700637cbSDimitry Andric   const unsigned Bits = LHS.getBitWidth();
2769*700637cbSDimitry Andric 
2770*700637cbSDimitry Andric   // OpenCL 6.3j: shift values are effectively % word size of LHS.
2771*700637cbSDimitry Andric   if (S.getLangOpts().OpenCL)
2772*700637cbSDimitry Andric     RHS &=
2773*700637cbSDimitry Andric         APSInt(llvm::APInt(RHS.getBitWidth(), static_cast<uint64_t>(Bits - 1)),
2774*700637cbSDimitry Andric                RHS.isUnsigned());
2775*700637cbSDimitry Andric 
2776*700637cbSDimitry Andric   if (RHS.isNegative()) {
2777*700637cbSDimitry Andric     // During constant-folding, a negative shift is an opposite shift. Such a
2778*700637cbSDimitry Andric     // shift is not a constant expression.
2779*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
2780*700637cbSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS; //.toAPSInt();
2781*700637cbSDimitry Andric     if (!S.noteUndefinedBehavior())
2782*700637cbSDimitry Andric       return false;
2783*700637cbSDimitry Andric     return DoShiftAP<LT, RT,
2784*700637cbSDimitry Andric                      Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
2785*700637cbSDimitry Andric         S, OpPC, LHS, -RHS, Result);
2786*700637cbSDimitry Andric   }
2787*700637cbSDimitry Andric 
2788*700637cbSDimitry Andric   if (!CheckShift<Dir>(S, OpPC, static_cast<LT>(LHS), static_cast<RT>(RHS),
2789*700637cbSDimitry Andric                        Bits))
2790*700637cbSDimitry Andric     return false;
2791*700637cbSDimitry Andric 
2792*700637cbSDimitry Andric   unsigned SA = (unsigned)RHS.getLimitedValue(Bits - 1);
2793*700637cbSDimitry Andric   if constexpr (Dir == ShiftDir::Left) {
2794*700637cbSDimitry Andric     if constexpr (needsAlloc<LT>())
2795*700637cbSDimitry Andric       Result->copy(LHS << SA);
2796*700637cbSDimitry Andric     else
2797*700637cbSDimitry Andric       *Result = LT(LHS << SA);
2798*700637cbSDimitry Andric   } else {
2799*700637cbSDimitry Andric     if constexpr (needsAlloc<LT>())
2800*700637cbSDimitry Andric       Result->copy(LHS >> SA);
2801*700637cbSDimitry Andric     else
2802*700637cbSDimitry Andric       *Result = LT(LHS >> SA);
2803*700637cbSDimitry Andric   }
2804*700637cbSDimitry Andric 
2805*700637cbSDimitry Andric   S.Stk.push<LT>(*Result);
2806*700637cbSDimitry Andric   return true;
2807*700637cbSDimitry Andric }
2808*700637cbSDimitry Andric 
2809*700637cbSDimitry Andric template <PrimType NameL, PrimType NameR>
Shr(InterpState & S,CodePtr OpPC)2810*700637cbSDimitry Andric inline bool Shr(InterpState &S, CodePtr OpPC) {
2811*700637cbSDimitry Andric   using LT = typename PrimConv<NameL>::T;
2812*700637cbSDimitry Andric   using RT = typename PrimConv<NameR>::T;
2813*700637cbSDimitry Andric   auto RHS = S.Stk.pop<RT>();
2814*700637cbSDimitry Andric   auto LHS = S.Stk.pop<LT>();
2815*700637cbSDimitry Andric 
2816*700637cbSDimitry Andric   if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
2817*700637cbSDimitry Andric     LT Result;
2818*700637cbSDimitry Andric     if constexpr (needsAlloc<LT>())
2819*700637cbSDimitry Andric       Result = S.allocAP<LT>(LHS.bitWidth());
2820*700637cbSDimitry Andric     return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),
2821*700637cbSDimitry Andric                                               RHS.toAPSInt(), &Result);
2822*700637cbSDimitry Andric   } else {
2823*700637cbSDimitry Andric     LT Result;
2824*700637cbSDimitry Andric     return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);
2825*700637cbSDimitry Andric   }
2826*700637cbSDimitry Andric }
2827*700637cbSDimitry Andric 
2828*700637cbSDimitry Andric template <PrimType NameL, PrimType NameR>
Shl(InterpState & S,CodePtr OpPC)2829*700637cbSDimitry Andric inline bool Shl(InterpState &S, CodePtr OpPC) {
2830*700637cbSDimitry Andric   using LT = typename PrimConv<NameL>::T;
2831*700637cbSDimitry Andric   using RT = typename PrimConv<NameR>::T;
2832*700637cbSDimitry Andric   auto RHS = S.Stk.pop<RT>();
2833*700637cbSDimitry Andric   auto LHS = S.Stk.pop<LT>();
2834*700637cbSDimitry Andric 
2835*700637cbSDimitry Andric   if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {
2836*700637cbSDimitry Andric     LT Result;
2837*700637cbSDimitry Andric     if constexpr (needsAlloc<LT>())
2838*700637cbSDimitry Andric       Result = S.allocAP<LT>(LHS.bitWidth());
2839*700637cbSDimitry Andric     return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),
2840*700637cbSDimitry Andric                                              RHS.toAPSInt(), &Result);
2841*700637cbSDimitry Andric   } else {
2842*700637cbSDimitry Andric     LT Result;
2843*700637cbSDimitry Andric     return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);
2844*700637cbSDimitry Andric   }
2845*700637cbSDimitry Andric }
2846*700637cbSDimitry Andric 
ShiftFixedPoint(InterpState & S,CodePtr OpPC,bool Left)2847*700637cbSDimitry Andric static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
2848*700637cbSDimitry Andric   const auto &RHS = S.Stk.pop<FixedPoint>();
2849*700637cbSDimitry Andric   const auto &LHS = S.Stk.pop<FixedPoint>();
2850*700637cbSDimitry Andric   llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
2851*700637cbSDimitry Andric 
2852*700637cbSDimitry Andric   unsigned ShiftBitWidth =
2853*700637cbSDimitry Andric       LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
2854*700637cbSDimitry Andric 
2855*700637cbSDimitry Andric   // Embedded-C 4.1.6.2.2:
2856*700637cbSDimitry Andric   //   The right operand must be nonnegative and less than the total number
2857*700637cbSDimitry Andric   //   of (nonpadding) bits of the fixed-point operand ...
2858*700637cbSDimitry Andric   if (RHS.isNegative()) {
2859*700637cbSDimitry Andric     S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
2860*700637cbSDimitry Andric         << RHS.toAPSInt();
2861*700637cbSDimitry Andric   } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
2862*700637cbSDimitry Andric                  ShiftBitWidth)) != RHS.toAPSInt()) {
2863*700637cbSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
2864*700637cbSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_large_shift)
2865*700637cbSDimitry Andric         << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
2866*700637cbSDimitry Andric   }
2867*700637cbSDimitry Andric 
2868*700637cbSDimitry Andric   FixedPoint Result;
2869*700637cbSDimitry Andric   if (Left) {
2870*700637cbSDimitry Andric     if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&
2871*700637cbSDimitry Andric         !handleFixedPointOverflow(S, OpPC, Result))
2872*700637cbSDimitry Andric       return false;
2873*700637cbSDimitry Andric   } else {
2874*700637cbSDimitry Andric     if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&
2875*700637cbSDimitry Andric         !handleFixedPointOverflow(S, OpPC, Result))
2876*700637cbSDimitry Andric       return false;
2877*700637cbSDimitry Andric   }
2878*700637cbSDimitry Andric 
2879*700637cbSDimitry Andric   S.Stk.push<FixedPoint>(Result);
2880*700637cbSDimitry Andric   return true;
2881*700637cbSDimitry Andric }
2882*700637cbSDimitry Andric 
2883*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2884*700637cbSDimitry Andric // NoRet
2885*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2886*700637cbSDimitry Andric 
NoRet(InterpState & S,CodePtr OpPC)2887*700637cbSDimitry Andric inline bool NoRet(InterpState &S, CodePtr OpPC) {
2888*700637cbSDimitry Andric   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
2889*700637cbSDimitry Andric   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
2890*700637cbSDimitry Andric   return false;
2891*700637cbSDimitry Andric }
2892*700637cbSDimitry Andric 
2893*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2894*700637cbSDimitry Andric // NarrowPtr, ExpandPtr
2895*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
2896*700637cbSDimitry Andric 
NarrowPtr(InterpState & S,CodePtr OpPC)2897*700637cbSDimitry Andric inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
2898*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2899*700637cbSDimitry Andric   S.Stk.push<Pointer>(Ptr.narrow());
2900*700637cbSDimitry Andric   return true;
2901*700637cbSDimitry Andric }
2902*700637cbSDimitry Andric 
ExpandPtr(InterpState & S,CodePtr OpPC)2903*700637cbSDimitry Andric inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
2904*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2905*700637cbSDimitry Andric   if (Ptr.isBlockPointer())
2906*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr.expand());
2907*700637cbSDimitry Andric   else
2908*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr);
2909*700637cbSDimitry Andric   return true;
2910*700637cbSDimitry Andric }
2911*700637cbSDimitry Andric 
2912*700637cbSDimitry Andric // 1) Pops an integral value from the stack
2913*700637cbSDimitry Andric // 2) Peeks a pointer
2914*700637cbSDimitry Andric // 3) Pushes a new pointer that's a narrowed array
2915*700637cbSDimitry Andric //   element of the peeked pointer with the value
2916*700637cbSDimitry Andric //   from 1) added as offset.
2917*700637cbSDimitry Andric //
2918*700637cbSDimitry Andric // This leaves the original pointer on the stack and pushes a new one
2919*700637cbSDimitry Andric // with the offset applied and narrowed.
2920*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPtr(InterpState & S,CodePtr OpPC)2921*700637cbSDimitry Andric inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
2922*700637cbSDimitry Andric   const T &Offset = S.Stk.pop<T>();
2923*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
2924*700637cbSDimitry Andric 
2925*700637cbSDimitry Andric   if (!Ptr.isZero() && !Offset.isZero()) {
2926*700637cbSDimitry Andric     if (!CheckArray(S, OpPC, Ptr))
2927*700637cbSDimitry Andric       return false;
2928*700637cbSDimitry Andric   }
2929*700637cbSDimitry Andric 
2930*700637cbSDimitry Andric   if (Offset.isZero()) {
2931*700637cbSDimitry Andric     if (Ptr.getFieldDesc()->isArray() && Ptr.getIndex() == 0) {
2932*700637cbSDimitry Andric       S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
2933*700637cbSDimitry Andric       return true;
2934*700637cbSDimitry Andric     }
2935*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr);
2936*700637cbSDimitry Andric     return true;
2937*700637cbSDimitry Andric   }
2938*700637cbSDimitry Andric 
2939*700637cbSDimitry Andric   assert(!Offset.isZero());
2940*700637cbSDimitry Andric 
2941*700637cbSDimitry Andric   if (std::optional<Pointer> Result =
2942*700637cbSDimitry Andric           OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
2943*700637cbSDimitry Andric     S.Stk.push<Pointer>(Result->narrow());
2944*700637cbSDimitry Andric     return true;
2945*700637cbSDimitry Andric   }
2946*700637cbSDimitry Andric 
2947*700637cbSDimitry Andric   return false;
2948*700637cbSDimitry Andric }
2949*700637cbSDimitry Andric 
2950*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPtrPop(InterpState & S,CodePtr OpPC)2951*700637cbSDimitry Andric inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
2952*700637cbSDimitry Andric   const T &Offset = S.Stk.pop<T>();
2953*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2954*700637cbSDimitry Andric 
2955*700637cbSDimitry Andric   if (!Ptr.isZero() && !Offset.isZero()) {
2956*700637cbSDimitry Andric     if (!CheckArray(S, OpPC, Ptr))
2957*700637cbSDimitry Andric       return false;
2958*700637cbSDimitry Andric   }
2959*700637cbSDimitry Andric 
2960*700637cbSDimitry Andric   if (Offset.isZero()) {
2961*700637cbSDimitry Andric     if (Ptr.getFieldDesc()->isArray() && Ptr.getIndex() == 0) {
2962*700637cbSDimitry Andric       S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());
2963*700637cbSDimitry Andric       return true;
2964*700637cbSDimitry Andric     }
2965*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr);
2966*700637cbSDimitry Andric     return true;
2967*700637cbSDimitry Andric   }
2968*700637cbSDimitry Andric 
2969*700637cbSDimitry Andric   assert(!Offset.isZero());
2970*700637cbSDimitry Andric 
2971*700637cbSDimitry Andric   if (std::optional<Pointer> Result =
2972*700637cbSDimitry Andric           OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {
2973*700637cbSDimitry Andric     S.Stk.push<Pointer>(Result->narrow());
2974*700637cbSDimitry Andric     return true;
2975*700637cbSDimitry Andric   }
2976*700637cbSDimitry Andric   return false;
2977*700637cbSDimitry Andric }
2978*700637cbSDimitry Andric 
2979*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElem(InterpState & S,CodePtr OpPC,uint32_t Index)2980*700637cbSDimitry Andric inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {
2981*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
2982*700637cbSDimitry Andric 
2983*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
2984*700637cbSDimitry Andric     return false;
2985*700637cbSDimitry Andric 
2986*700637cbSDimitry Andric   assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2987*700637cbSDimitry Andric   S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
2988*700637cbSDimitry Andric   return true;
2989*700637cbSDimitry Andric }
2990*700637cbSDimitry Andric 
2991*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
ArrayElemPop(InterpState & S,CodePtr OpPC,uint32_t Index)2992*700637cbSDimitry Andric inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {
2993*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
2994*700637cbSDimitry Andric 
2995*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
2996*700637cbSDimitry Andric     return false;
2997*700637cbSDimitry Andric 
2998*700637cbSDimitry Andric   assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);
2999*700637cbSDimitry Andric   S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());
3000*700637cbSDimitry Andric   return true;
3001*700637cbSDimitry Andric }
3002*700637cbSDimitry Andric 
3003*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CopyArray(InterpState & S,CodePtr OpPC,uint32_t SrcIndex,uint32_t DestIndex,uint32_t Size)3004*700637cbSDimitry Andric inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,
3005*700637cbSDimitry Andric                       uint32_t DestIndex, uint32_t Size) {
3006*700637cbSDimitry Andric   const auto &SrcPtr = S.Stk.pop<Pointer>();
3007*700637cbSDimitry Andric   const auto &DestPtr = S.Stk.peek<Pointer>();
3008*700637cbSDimitry Andric 
3009*700637cbSDimitry Andric   for (uint32_t I = 0; I != Size; ++I) {
3010*700637cbSDimitry Andric     const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);
3011*700637cbSDimitry Andric 
3012*700637cbSDimitry Andric     if (!CheckLoad(S, OpPC, SP))
3013*700637cbSDimitry Andric       return false;
3014*700637cbSDimitry Andric 
3015*700637cbSDimitry Andric     const Pointer &DP = DestPtr.atIndex(DestIndex + I);
3016*700637cbSDimitry Andric     DP.deref<T>() = SP.deref<T>();
3017*700637cbSDimitry Andric     DP.initialize();
3018*700637cbSDimitry Andric   }
3019*700637cbSDimitry Andric   return true;
3020*700637cbSDimitry Andric }
3021*700637cbSDimitry Andric 
3022*700637cbSDimitry Andric /// Just takes a pointer and checks if it's an incomplete
3023*700637cbSDimitry Andric /// array type.
ArrayDecay(InterpState & S,CodePtr OpPC)3024*700637cbSDimitry Andric inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
3025*700637cbSDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
3026*700637cbSDimitry Andric 
3027*700637cbSDimitry Andric   if (Ptr.isZero()) {
3028*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr);
3029*700637cbSDimitry Andric     return true;
3030*700637cbSDimitry Andric   }
3031*700637cbSDimitry Andric 
3032*700637cbSDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
3033*700637cbSDimitry Andric     return false;
3034*700637cbSDimitry Andric 
3035*700637cbSDimitry Andric   if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
3036*700637cbSDimitry Andric     S.Stk.push<Pointer>(Ptr.atIndex(0));
3037*700637cbSDimitry Andric     return true;
3038*700637cbSDimitry Andric   }
3039*700637cbSDimitry Andric 
3040*700637cbSDimitry Andric   const SourceInfo &E = S.Current->getSource(OpPC);
3041*700637cbSDimitry Andric   S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
3042*700637cbSDimitry Andric 
3043*700637cbSDimitry Andric   return false;
3044*700637cbSDimitry Andric }
3045*700637cbSDimitry Andric 
GetFnPtr(InterpState & S,CodePtr OpPC,const Function * Func)3046*700637cbSDimitry Andric inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
3047*700637cbSDimitry Andric   assert(Func);
3048*700637cbSDimitry Andric   S.Stk.push<Pointer>(Func);
3049*700637cbSDimitry Andric   return true;
3050*700637cbSDimitry Andric }
3051*700637cbSDimitry Andric 
3052*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
GetIntPtr(InterpState & S,CodePtr OpPC,const Descriptor * Desc)3053*700637cbSDimitry Andric inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3054*700637cbSDimitry Andric   const T &IntVal = S.Stk.pop<T>();
3055*700637cbSDimitry Andric 
3056*700637cbSDimitry Andric   S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
3057*700637cbSDimitry Andric       << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret
3058*700637cbSDimitry Andric       << S.getLangOpts().CPlusPlus;
3059*700637cbSDimitry Andric 
3060*700637cbSDimitry Andric   S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
3061*700637cbSDimitry Andric   return true;
3062*700637cbSDimitry Andric }
3063*700637cbSDimitry Andric 
GetMemberPtr(InterpState & S,CodePtr OpPC,const ValueDecl * D)3064*700637cbSDimitry Andric inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
3065*700637cbSDimitry Andric   S.Stk.push<MemberPointer>(D);
3066*700637cbSDimitry Andric   return true;
3067*700637cbSDimitry Andric }
3068*700637cbSDimitry Andric 
GetMemberPtrBase(InterpState & S,CodePtr OpPC)3069*700637cbSDimitry Andric inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
3070*700637cbSDimitry Andric   const auto &MP = S.Stk.pop<MemberPointer>();
3071*700637cbSDimitry Andric 
3072*700637cbSDimitry Andric   S.Stk.push<Pointer>(MP.getBase());
3073*700637cbSDimitry Andric   return true;
3074*700637cbSDimitry Andric }
3075*700637cbSDimitry Andric 
GetMemberPtrDecl(InterpState & S,CodePtr OpPC)3076*700637cbSDimitry Andric inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
3077*700637cbSDimitry Andric   const auto &MP = S.Stk.pop<MemberPointer>();
3078*700637cbSDimitry Andric 
3079*700637cbSDimitry Andric   const auto *FD = cast<FunctionDecl>(MP.getDecl());
3080*700637cbSDimitry Andric   const auto *Func = S.getContext().getOrCreateFunction(FD);
3081*700637cbSDimitry Andric 
3082*700637cbSDimitry Andric   S.Stk.push<Pointer>(Func);
3083*700637cbSDimitry Andric   return true;
3084*700637cbSDimitry Andric }
3085*700637cbSDimitry Andric 
3086*700637cbSDimitry Andric /// Just emit a diagnostic. The expression that caused emission of this
3087*700637cbSDimitry Andric /// op is not valid in a constant context.
Invalid(InterpState & S,CodePtr OpPC)3088*700637cbSDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC) {
3089*700637cbSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
3090*700637cbSDimitry Andric   S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)
3091*700637cbSDimitry Andric       << S.Current->getRange(OpPC);
3092*700637cbSDimitry Andric   return false;
3093*700637cbSDimitry Andric }
3094*700637cbSDimitry Andric 
Unsupported(InterpState & S,CodePtr OpPC)3095*700637cbSDimitry Andric inline bool Unsupported(InterpState &S, CodePtr OpPC) {
3096*700637cbSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
3097*700637cbSDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
3098*700637cbSDimitry Andric       << S.Current->getRange(OpPC);
3099*700637cbSDimitry Andric   return false;
3100*700637cbSDimitry Andric }
3101*700637cbSDimitry Andric 
StartSpeculation(InterpState & S,CodePtr OpPC)3102*700637cbSDimitry Andric inline bool StartSpeculation(InterpState &S, CodePtr OpPC) {
3103*700637cbSDimitry Andric   ++S.SpeculationDepth;
3104*700637cbSDimitry Andric   if (S.SpeculationDepth != 1)
3105*700637cbSDimitry Andric     return true;
3106*700637cbSDimitry Andric 
3107*700637cbSDimitry Andric   assert(S.PrevDiags == nullptr);
3108*700637cbSDimitry Andric   S.PrevDiags = S.getEvalStatus().Diag;
3109*700637cbSDimitry Andric   S.getEvalStatus().Diag = nullptr;
3110*700637cbSDimitry Andric   return true;
3111*700637cbSDimitry Andric }
EndSpeculation(InterpState & S,CodePtr OpPC)3112*700637cbSDimitry Andric inline bool EndSpeculation(InterpState &S, CodePtr OpPC) {
3113*700637cbSDimitry Andric   assert(S.SpeculationDepth != 0);
3114*700637cbSDimitry Andric   --S.SpeculationDepth;
3115*700637cbSDimitry Andric   if (S.SpeculationDepth == 0) {
3116*700637cbSDimitry Andric     S.getEvalStatus().Diag = S.PrevDiags;
3117*700637cbSDimitry Andric     S.PrevDiags = nullptr;
3118*700637cbSDimitry Andric   }
3119*700637cbSDimitry Andric   return true;
3120*700637cbSDimitry Andric }
3121*700637cbSDimitry Andric 
PushCC(InterpState & S,CodePtr OpPC,bool Value)3122*700637cbSDimitry Andric inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) {
3123*700637cbSDimitry Andric   S.ConstantContextOverride = Value;
3124*700637cbSDimitry Andric   return true;
3125*700637cbSDimitry Andric }
PopCC(InterpState & S,CodePtr OpPC)3126*700637cbSDimitry Andric inline bool PopCC(InterpState &S, CodePtr OpPC) {
3127*700637cbSDimitry Andric   S.ConstantContextOverride = std::nullopt;
3128*700637cbSDimitry Andric   return true;
3129*700637cbSDimitry Andric }
3130*700637cbSDimitry Andric 
3131*700637cbSDimitry Andric /// Do nothing and just abort execution.
Error(InterpState & S,CodePtr OpPC)3132*700637cbSDimitry Andric inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
3133*700637cbSDimitry Andric 
SideEffect(InterpState & S,CodePtr OpPC)3134*700637cbSDimitry Andric inline bool SideEffect(InterpState &S, CodePtr OpPC) {
3135*700637cbSDimitry Andric   return S.noteSideEffect();
3136*700637cbSDimitry Andric }
3137*700637cbSDimitry Andric 
3138*700637cbSDimitry Andric /// Same here, but only for casts.
InvalidCast(InterpState & S,CodePtr OpPC,CastKind Kind,bool Fatal)3139*700637cbSDimitry Andric inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,
3140*700637cbSDimitry Andric                         bool Fatal) {
3141*700637cbSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
3142*700637cbSDimitry Andric 
3143*700637cbSDimitry Andric   if (Kind == CastKind::Reinterpret) {
3144*700637cbSDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)
3145*700637cbSDimitry Andric         << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);
3146*700637cbSDimitry Andric     return !Fatal;
3147*700637cbSDimitry Andric   } else if (Kind == CastKind::Volatile) {
3148*700637cbSDimitry Andric     if (!S.checkingPotentialConstantExpression()) {
3149*700637cbSDimitry Andric       const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
3150*700637cbSDimitry Andric       if (S.getLangOpts().CPlusPlus)
3151*700637cbSDimitry Andric         S.FFDiag(E, diag::note_constexpr_access_volatile_type)
3152*700637cbSDimitry Andric             << AK_Read << E->getSubExpr()->getType();
3153*700637cbSDimitry Andric       else
3154*700637cbSDimitry Andric         S.FFDiag(E);
3155*700637cbSDimitry Andric     }
3156*700637cbSDimitry Andric 
3157*700637cbSDimitry Andric     return false;
3158*700637cbSDimitry Andric   } else if (Kind == CastKind::Dynamic) {
3159*700637cbSDimitry Andric     assert(!S.getLangOpts().CPlusPlus20);
3160*700637cbSDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
3161*700637cbSDimitry Andric         << diag::ConstexprInvalidCastKind::Dynamic;
3162*700637cbSDimitry Andric     return true;
3163*700637cbSDimitry Andric   }
3164*700637cbSDimitry Andric 
3165*700637cbSDimitry Andric   return false;
3166*700637cbSDimitry Andric }
3167*700637cbSDimitry Andric 
InvalidDeclRef(InterpState & S,CodePtr OpPC,const DeclRefExpr * DR,bool InitializerFailed)3168*700637cbSDimitry Andric inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,
3169*700637cbSDimitry Andric                            bool InitializerFailed) {
3170*700637cbSDimitry Andric   assert(DR);
3171*700637cbSDimitry Andric 
3172*700637cbSDimitry Andric   if (InitializerFailed) {
3173*700637cbSDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
3174*700637cbSDimitry Andric     const auto *VD = cast<VarDecl>(DR->getDecl());
3175*700637cbSDimitry Andric     S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
3176*700637cbSDimitry Andric     S.Note(VD->getLocation(), diag::note_declared_at);
3177*700637cbSDimitry Andric     return false;
3178*700637cbSDimitry Andric   }
3179*700637cbSDimitry Andric 
3180*700637cbSDimitry Andric   return CheckDeclRef(S, OpPC, DR);
3181*700637cbSDimitry Andric }
3182*700637cbSDimitry Andric 
SizelessVectorElementSize(InterpState & S,CodePtr OpPC)3183*700637cbSDimitry Andric inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {
3184*700637cbSDimitry Andric   if (S.inConstantContext()) {
3185*700637cbSDimitry Andric     const SourceRange &ArgRange = S.Current->getRange(OpPC);
3186*700637cbSDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
3187*700637cbSDimitry Andric     S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;
3188*700637cbSDimitry Andric   }
3189*700637cbSDimitry Andric   return false;
3190*700637cbSDimitry Andric }
3191*700637cbSDimitry Andric 
CheckPseudoDtor(InterpState & S,CodePtr OpPC)3192*700637cbSDimitry Andric inline bool CheckPseudoDtor(InterpState &S, CodePtr OpPC) {
3193*700637cbSDimitry Andric   if (!S.getLangOpts().CPlusPlus20)
3194*700637cbSDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC),
3195*700637cbSDimitry Andric               diag::note_constexpr_pseudo_destructor);
3196*700637cbSDimitry Andric   return true;
3197*700637cbSDimitry Andric }
3198*700637cbSDimitry Andric 
Assume(InterpState & S,CodePtr OpPC)3199*700637cbSDimitry Andric inline bool Assume(InterpState &S, CodePtr OpPC) {
3200*700637cbSDimitry Andric   const auto Val = S.Stk.pop<Boolean>();
3201*700637cbSDimitry Andric 
3202*700637cbSDimitry Andric   if (Val)
3203*700637cbSDimitry Andric     return true;
3204*700637cbSDimitry Andric 
3205*700637cbSDimitry Andric   // Else, diagnose.
3206*700637cbSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
3207*700637cbSDimitry Andric   S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);
3208*700637cbSDimitry Andric   return false;
3209*700637cbSDimitry Andric }
3210*700637cbSDimitry Andric 
3211*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
OffsetOf(InterpState & S,CodePtr OpPC,const OffsetOfExpr * E)3212*700637cbSDimitry Andric inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
3213*700637cbSDimitry Andric   llvm::SmallVector<int64_t> ArrayIndices;
3214*700637cbSDimitry Andric   for (size_t I = 0; I != E->getNumExpressions(); ++I)
3215*700637cbSDimitry Andric     ArrayIndices.emplace_back(S.Stk.pop<int64_t>());
3216*700637cbSDimitry Andric 
3217*700637cbSDimitry Andric   int64_t Result;
3218*700637cbSDimitry Andric   if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))
3219*700637cbSDimitry Andric     return false;
3220*700637cbSDimitry Andric 
3221*700637cbSDimitry Andric   S.Stk.push<T>(T::from(Result));
3222*700637cbSDimitry Andric 
3223*700637cbSDimitry Andric   return true;
3224*700637cbSDimitry Andric }
3225*700637cbSDimitry Andric 
3226*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CheckNonNullArg(InterpState & S,CodePtr OpPC)3227*700637cbSDimitry Andric inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
3228*700637cbSDimitry Andric   const T &Arg = S.Stk.peek<T>();
3229*700637cbSDimitry Andric   if (!Arg.isZero())
3230*700637cbSDimitry Andric     return true;
3231*700637cbSDimitry Andric 
3232*700637cbSDimitry Andric   const SourceLocation &Loc = S.Current->getLocation(OpPC);
3233*700637cbSDimitry Andric   S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
3234*700637cbSDimitry Andric 
3235*700637cbSDimitry Andric   return false;
3236*700637cbSDimitry Andric }
3237*700637cbSDimitry Andric 
3238*700637cbSDimitry Andric void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
3239*700637cbSDimitry Andric                        const APSInt &Value);
3240*700637cbSDimitry Andric 
3241*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CheckEnumValue(InterpState & S,CodePtr OpPC,const EnumDecl * ED)3242*700637cbSDimitry Andric inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {
3243*700637cbSDimitry Andric   assert(ED);
3244*700637cbSDimitry Andric   assert(!ED->isFixed());
3245*700637cbSDimitry Andric 
3246*700637cbSDimitry Andric   if (S.inConstantContext()) {
3247*700637cbSDimitry Andric     const APSInt Val = S.Stk.peek<T>().toAPSInt();
3248*700637cbSDimitry Andric     diagnoseEnumValue(S, OpPC, ED, Val);
3249*700637cbSDimitry Andric   }
3250*700637cbSDimitry Andric   return true;
3251*700637cbSDimitry Andric }
3252*700637cbSDimitry Andric 
3253*700637cbSDimitry Andric /// OldPtr -> Integer -> NewPtr.
3254*700637cbSDimitry Andric template <PrimType TIn, PrimType TOut>
DecayPtr(InterpState & S,CodePtr OpPC)3255*700637cbSDimitry Andric inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
3256*700637cbSDimitry Andric   static_assert(isPtrType(TIn) && isPtrType(TOut));
3257*700637cbSDimitry Andric   using FromT = typename PrimConv<TIn>::T;
3258*700637cbSDimitry Andric   using ToT = typename PrimConv<TOut>::T;
3259*700637cbSDimitry Andric 
3260*700637cbSDimitry Andric   const FromT &OldPtr = S.Stk.pop<FromT>();
3261*700637cbSDimitry Andric 
3262*700637cbSDimitry Andric   if constexpr (std::is_same_v<FromT, FunctionPointer> &&
3263*700637cbSDimitry Andric                 std::is_same_v<ToT, Pointer>) {
3264*700637cbSDimitry Andric     S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());
3265*700637cbSDimitry Andric     return true;
3266*700637cbSDimitry Andric   } else if constexpr (std::is_same_v<FromT, Pointer> &&
3267*700637cbSDimitry Andric                        std::is_same_v<ToT, FunctionPointer>) {
3268*700637cbSDimitry Andric     if (OldPtr.isFunctionPointer()) {
3269*700637cbSDimitry Andric       S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),
3270*700637cbSDimitry Andric                                   OldPtr.getByteOffset());
3271*700637cbSDimitry Andric       return true;
3272*700637cbSDimitry Andric     }
3273*700637cbSDimitry Andric   }
3274*700637cbSDimitry Andric 
3275*700637cbSDimitry Andric   S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
3276*700637cbSDimitry Andric   return true;
3277*700637cbSDimitry Andric }
3278*700637cbSDimitry Andric 
CheckDecl(InterpState & S,CodePtr OpPC,const VarDecl * VD)3279*700637cbSDimitry Andric inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {
3280*700637cbSDimitry Andric   // An expression E is a core constant expression unless the evaluation of E
3281*700637cbSDimitry Andric   // would evaluate one of the following: [C++23] - a control flow that passes
3282*700637cbSDimitry Andric   // through a declaration of a variable with static or thread storage duration
3283*700637cbSDimitry Andric   // unless that variable is usable in constant expressions.
3284*700637cbSDimitry Andric   assert(VD->isLocalVarDecl() &&
3285*700637cbSDimitry Andric          VD->isStaticLocal()); // Checked before emitting this.
3286*700637cbSDimitry Andric 
3287*700637cbSDimitry Andric   if (VD == S.EvaluatingDecl)
3288*700637cbSDimitry Andric     return true;
3289*700637cbSDimitry Andric 
3290*700637cbSDimitry Andric   if (!VD->isUsableInConstantExpressions(S.getASTContext())) {
3291*700637cbSDimitry Andric     S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
3292*700637cbSDimitry Andric         << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
3293*700637cbSDimitry Andric     return false;
3294*700637cbSDimitry Andric   }
3295*700637cbSDimitry Andric   return true;
3296*700637cbSDimitry Andric }
3297*700637cbSDimitry Andric 
Alloc(InterpState & S,CodePtr OpPC,const Descriptor * Desc)3298*700637cbSDimitry Andric inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3299*700637cbSDimitry Andric   assert(Desc);
3300*700637cbSDimitry Andric 
3301*700637cbSDimitry Andric   if (!CheckDynamicMemoryAllocation(S, OpPC))
3302*700637cbSDimitry Andric     return false;
3303*700637cbSDimitry Andric 
3304*700637cbSDimitry Andric   DynamicAllocator &Allocator = S.getAllocator();
3305*700637cbSDimitry Andric   Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),
3306*700637cbSDimitry Andric                                 DynamicAllocator::Form::NonArray);
3307*700637cbSDimitry Andric   assert(B);
3308*700637cbSDimitry Andric   S.Stk.push<Pointer>(B);
3309*700637cbSDimitry Andric   return true;
3310*700637cbSDimitry Andric }
3311*700637cbSDimitry Andric 
3312*700637cbSDimitry Andric template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
AllocN(InterpState & S,CodePtr OpPC,PrimType T,const Expr * Source,bool IsNoThrow)3313*700637cbSDimitry Andric inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
3314*700637cbSDimitry Andric                    bool IsNoThrow) {
3315*700637cbSDimitry Andric   if (!CheckDynamicMemoryAllocation(S, OpPC))
3316*700637cbSDimitry Andric     return false;
3317*700637cbSDimitry Andric 
3318*700637cbSDimitry Andric   SizeT NumElements = S.Stk.pop<SizeT>();
3319*700637cbSDimitry Andric   if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {
3320*700637cbSDimitry Andric     if (!IsNoThrow)
3321*700637cbSDimitry Andric       return false;
3322*700637cbSDimitry Andric 
3323*700637cbSDimitry Andric     // If this failed and is nothrow, just return a null ptr.
3324*700637cbSDimitry Andric     S.Stk.push<Pointer>(0, nullptr);
3325*700637cbSDimitry Andric     return true;
3326*700637cbSDimitry Andric   }
3327*700637cbSDimitry Andric   assert(NumElements.isPositive());
3328*700637cbSDimitry Andric 
3329*700637cbSDimitry Andric   if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))
3330*700637cbSDimitry Andric     return false;
3331*700637cbSDimitry Andric 
3332*700637cbSDimitry Andric   DynamicAllocator &Allocator = S.getAllocator();
3333*700637cbSDimitry Andric   Block *B =
3334*700637cbSDimitry Andric       Allocator.allocate(Source, T, static_cast<size_t>(NumElements),
3335*700637cbSDimitry Andric                          S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
3336*700637cbSDimitry Andric   assert(B);
3337*700637cbSDimitry Andric   if (NumElements.isZero())
3338*700637cbSDimitry Andric     S.Stk.push<Pointer>(B);
3339*700637cbSDimitry Andric   else
3340*700637cbSDimitry Andric     S.Stk.push<Pointer>(Pointer(B).atIndex(0));
3341*700637cbSDimitry Andric   return true;
3342*700637cbSDimitry Andric }
3343*700637cbSDimitry Andric 
3344*700637cbSDimitry Andric template <PrimType Name, class SizeT = typename PrimConv<Name>::T>
AllocCN(InterpState & S,CodePtr OpPC,const Descriptor * ElementDesc,bool IsNoThrow)3345*700637cbSDimitry Andric inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,
3346*700637cbSDimitry Andric                     bool IsNoThrow) {
3347*700637cbSDimitry Andric   if (!CheckDynamicMemoryAllocation(S, OpPC))
3348*700637cbSDimitry Andric     return false;
3349*700637cbSDimitry Andric 
3350*700637cbSDimitry Andric   SizeT NumElements = S.Stk.pop<SizeT>();
3351*700637cbSDimitry Andric   if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),
3352*700637cbSDimitry Andric                       IsNoThrow)) {
3353*700637cbSDimitry Andric     if (!IsNoThrow)
3354*700637cbSDimitry Andric       return false;
3355*700637cbSDimitry Andric 
3356*700637cbSDimitry Andric     // If this failed and is nothrow, just return a null ptr.
3357*700637cbSDimitry Andric     S.Stk.push<Pointer>(0, ElementDesc);
3358*700637cbSDimitry Andric     return true;
3359*700637cbSDimitry Andric   }
3360*700637cbSDimitry Andric   assert(NumElements.isPositive());
3361*700637cbSDimitry Andric 
3362*700637cbSDimitry Andric   if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))
3363*700637cbSDimitry Andric     return false;
3364*700637cbSDimitry Andric 
3365*700637cbSDimitry Andric   DynamicAllocator &Allocator = S.getAllocator();
3366*700637cbSDimitry Andric   Block *B =
3367*700637cbSDimitry Andric       Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),
3368*700637cbSDimitry Andric                          S.Ctx.getEvalID(), DynamicAllocator::Form::Array);
3369*700637cbSDimitry Andric   assert(B);
3370*700637cbSDimitry Andric   if (NumElements.isZero())
3371*700637cbSDimitry Andric     S.Stk.push<Pointer>(B);
3372*700637cbSDimitry Andric   else
3373*700637cbSDimitry Andric     S.Stk.push<Pointer>(Pointer(B).atIndex(0));
3374*700637cbSDimitry Andric 
3375*700637cbSDimitry Andric   return true;
3376*700637cbSDimitry Andric }
3377*700637cbSDimitry Andric 
3378*700637cbSDimitry Andric bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
3379*700637cbSDimitry Andric           bool IsGlobalDelete);
3380*700637cbSDimitry Andric 
IsConstantContext(InterpState & S,CodePtr OpPC)3381*700637cbSDimitry Andric static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
3382*700637cbSDimitry Andric   S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));
3383*700637cbSDimitry Andric   return true;
3384*700637cbSDimitry Andric }
3385*700637cbSDimitry Andric 
CheckAllocations(InterpState & S,CodePtr OpPC)3386*700637cbSDimitry Andric static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
3387*700637cbSDimitry Andric   return S.maybeDiagnoseDanglingAllocations();
3388*700637cbSDimitry Andric }
3389*700637cbSDimitry Andric 
3390*700637cbSDimitry Andric /// Check if the initializer and storage types of a placement-new expression
3391*700637cbSDimitry Andric /// match.
3392*700637cbSDimitry Andric bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
3393*700637cbSDimitry Andric                           std::optional<uint64_t> ArraySize = std::nullopt);
3394*700637cbSDimitry Andric 
3395*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
CheckNewTypeMismatchArray(InterpState & S,CodePtr OpPC,const Expr * E)3396*700637cbSDimitry Andric bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
3397*700637cbSDimitry Andric   const auto &Size = S.Stk.pop<T>();
3398*700637cbSDimitry Andric   return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
3399*700637cbSDimitry Andric }
3400*700637cbSDimitry Andric bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);
3401*700637cbSDimitry Andric 
3402*700637cbSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
BitCastPrim(InterpState & S,CodePtr OpPC,bool TargetIsUCharOrByte,uint32_t ResultBitWidth,const llvm::fltSemantics * Sem)3403*700637cbSDimitry Andric inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
3404*700637cbSDimitry Andric                         uint32_t ResultBitWidth,
3405*700637cbSDimitry Andric                         const llvm::fltSemantics *Sem) {
3406*700637cbSDimitry Andric   const Pointer &FromPtr = S.Stk.pop<Pointer>();
3407*700637cbSDimitry Andric 
3408*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, FromPtr))
3409*700637cbSDimitry Andric     return false;
3410*700637cbSDimitry Andric 
3411*700637cbSDimitry Andric   if constexpr (std::is_same_v<T, Pointer>) {
3412*700637cbSDimitry Andric     // The only pointer type we can validly bitcast to is nullptr_t.
3413*700637cbSDimitry Andric     S.Stk.push<Pointer>();
3414*700637cbSDimitry Andric     return true;
3415*700637cbSDimitry Andric   } else {
3416*700637cbSDimitry Andric 
3417*700637cbSDimitry Andric     size_t BuffSize = ResultBitWidth / 8;
3418*700637cbSDimitry Andric     llvm::SmallVector<std::byte> Buff(BuffSize);
3419*700637cbSDimitry Andric     bool HasIndeterminateBits = false;
3420*700637cbSDimitry Andric 
3421*700637cbSDimitry Andric     Bits FullBitWidth(ResultBitWidth);
3422*700637cbSDimitry Andric     Bits BitWidth = FullBitWidth;
3423*700637cbSDimitry Andric 
3424*700637cbSDimitry Andric     if constexpr (std::is_same_v<T, Floating>) {
3425*700637cbSDimitry Andric       assert(Sem);
3426*700637cbSDimitry Andric       BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3427*700637cbSDimitry Andric     }
3428*700637cbSDimitry Andric 
3429*700637cbSDimitry Andric     if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3430*700637cbSDimitry Andric                    HasIndeterminateBits))
3431*700637cbSDimitry Andric       return false;
3432*700637cbSDimitry Andric 
3433*700637cbSDimitry Andric     if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
3434*700637cbSDimitry Andric       return false;
3435*700637cbSDimitry Andric 
3436*700637cbSDimitry Andric     if constexpr (std::is_same_v<T, Floating>) {
3437*700637cbSDimitry Andric       assert(Sem);
3438*700637cbSDimitry Andric       Floating Result = S.allocFloat(*Sem);
3439*700637cbSDimitry Andric       Floating::bitcastFromMemory(Buff.data(), *Sem, &Result);
3440*700637cbSDimitry Andric       S.Stk.push<Floating>(Result);
3441*700637cbSDimitry Andric 
3442*700637cbSDimitry Andric       // S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
3443*700637cbSDimitry Andric     } else if constexpr (needsAlloc<T>()) {
3444*700637cbSDimitry Andric       T Result = S.allocAP<T>(ResultBitWidth);
3445*700637cbSDimitry Andric       T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result);
3446*700637cbSDimitry Andric       S.Stk.push<T>(Result);
3447*700637cbSDimitry Andric     } else {
3448*700637cbSDimitry Andric       assert(!Sem);
3449*700637cbSDimitry Andric       S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
3450*700637cbSDimitry Andric     }
3451*700637cbSDimitry Andric     return true;
3452*700637cbSDimitry Andric   }
3453*700637cbSDimitry Andric }
3454*700637cbSDimitry Andric 
BitCast(InterpState & S,CodePtr OpPC)3455*700637cbSDimitry Andric inline bool BitCast(InterpState &S, CodePtr OpPC) {
3456*700637cbSDimitry Andric   const Pointer &FromPtr = S.Stk.pop<Pointer>();
3457*700637cbSDimitry Andric   Pointer &ToPtr = S.Stk.peek<Pointer>();
3458*700637cbSDimitry Andric 
3459*700637cbSDimitry Andric   if (!CheckLoad(S, OpPC, FromPtr))
3460*700637cbSDimitry Andric     return false;
3461*700637cbSDimitry Andric 
3462*700637cbSDimitry Andric   if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))
3463*700637cbSDimitry Andric     return false;
3464*700637cbSDimitry Andric 
3465*700637cbSDimitry Andric   return true;
3466*700637cbSDimitry Andric }
3467*700637cbSDimitry Andric 
3468*700637cbSDimitry Andric /// Typeid support.
3469*700637cbSDimitry Andric bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
3470*700637cbSDimitry Andric                const Type *TypeInfoType);
3471*700637cbSDimitry Andric bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);
3472*700637cbSDimitry Andric bool DiagTypeid(InterpState &S, CodePtr OpPC);
3473*700637cbSDimitry Andric 
CheckDestruction(InterpState & S,CodePtr OpPC)3474*700637cbSDimitry Andric inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {
3475*700637cbSDimitry Andric   const auto &Ptr = S.Stk.peek<Pointer>();
3476*700637cbSDimitry Andric   return CheckDestructor(S, OpPC, Ptr);
3477*700637cbSDimitry Andric }
3478*700637cbSDimitry Andric 
CheckArraySize(InterpState & S,CodePtr OpPC,uint64_t NumElems)3479*700637cbSDimitry Andric inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {
3480*700637cbSDimitry Andric   uint64_t Limit = S.getLangOpts().ConstexprStepLimit;
3481*700637cbSDimitry Andric   if (NumElems > Limit) {
3482*700637cbSDimitry Andric     S.FFDiag(S.Current->getSource(OpPC),
3483*700637cbSDimitry Andric              diag::note_constexpr_new_exceeds_limits)
3484*700637cbSDimitry Andric         << NumElems << Limit;
3485*700637cbSDimitry Andric     return false;
3486*700637cbSDimitry Andric   }
3487*700637cbSDimitry Andric   return true;
3488*700637cbSDimitry Andric }
3489*700637cbSDimitry Andric 
3490*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
3491*700637cbSDimitry Andric // Read opcode arguments
3492*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
3493*700637cbSDimitry Andric 
ReadArg(InterpState & S,CodePtr & OpPC)3494*700637cbSDimitry Andric template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
3495*700637cbSDimitry Andric   if constexpr (std::is_pointer<T>::value) {
3496*700637cbSDimitry Andric     uint32_t ID = OpPC.read<uint32_t>();
3497*700637cbSDimitry Andric     return reinterpret_cast<T>(S.P.getNativePointer(ID));
3498*700637cbSDimitry Andric   } else {
3499*700637cbSDimitry Andric     return OpPC.read<T>();
3500*700637cbSDimitry Andric   }
3501*700637cbSDimitry Andric }
3502*700637cbSDimitry Andric 
3503*700637cbSDimitry Andric template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
3504*700637cbSDimitry Andric   auto &Semantics =
3505*700637cbSDimitry Andric       llvm::APFloatBase::EnumToSemantics(Floating::deserializeSemantics(*OpPC));
3506*700637cbSDimitry Andric 
3507*700637cbSDimitry Andric   auto F = S.allocFloat(Semantics);
3508*700637cbSDimitry Andric   Floating::deserialize(*OpPC, &F);
3509*700637cbSDimitry Andric   OpPC += align(F.bytesToSerialize());
3510*700637cbSDimitry Andric   return F;
3511*700637cbSDimitry Andric }
3512*700637cbSDimitry Andric 
3513*700637cbSDimitry Andric template <>
3514*700637cbSDimitry Andric inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
3515*700637cbSDimitry Andric                                                     CodePtr &OpPC) {
3516*700637cbSDimitry Andric   uint32_t BitWidth = IntegralAP<false>::deserializeSize(*OpPC);
3517*700637cbSDimitry Andric   auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
3518*700637cbSDimitry Andric   assert(Result.bitWidth() == BitWidth);
3519*700637cbSDimitry Andric 
3520*700637cbSDimitry Andric   IntegralAP<false>::deserialize(*OpPC, &Result);
3521*700637cbSDimitry Andric   OpPC += align(Result.bytesToSerialize());
3522*700637cbSDimitry Andric   return Result;
3523*700637cbSDimitry Andric }
3524*700637cbSDimitry Andric 
3525*700637cbSDimitry Andric template <>
3526*700637cbSDimitry Andric inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
3527*700637cbSDimitry Andric                                                   CodePtr &OpPC) {
3528*700637cbSDimitry Andric   uint32_t BitWidth = IntegralAP<true>::deserializeSize(*OpPC);
3529*700637cbSDimitry Andric   auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
3530*700637cbSDimitry Andric   assert(Result.bitWidth() == BitWidth);
3531*700637cbSDimitry Andric 
3532*700637cbSDimitry Andric   IntegralAP<true>::deserialize(*OpPC, &Result);
3533*700637cbSDimitry Andric   OpPC += align(Result.bytesToSerialize());
3534*700637cbSDimitry Andric   return Result;
3535*700637cbSDimitry Andric }
3536*700637cbSDimitry Andric 
3537*700637cbSDimitry Andric template <>
3538*700637cbSDimitry Andric inline FixedPoint ReadArg<FixedPoint>(InterpState &S, CodePtr &OpPC) {
3539*700637cbSDimitry Andric   FixedPoint FP = FixedPoint::deserialize(*OpPC);
3540*700637cbSDimitry Andric   OpPC += align(FP.bytesToSerialize());
3541*700637cbSDimitry Andric   return FP;
3542*700637cbSDimitry Andric }
3543*700637cbSDimitry Andric 
3544*700637cbSDimitry Andric } // namespace interp
3545*700637cbSDimitry Andric } // namespace clang
3546*700637cbSDimitry Andric 
3547*700637cbSDimitry Andric #endif
3548